Adds a check to verify that each PR branch to be merged upstream contains SHAs of commits that significantly changed our CI infrastructure. This check is used to enforce that we don't merge PRs that have not been rebased recently and could result in merging of non-approved or otherwise bad changes. PR Close #28250
		
			
				
	
	
		
			187 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env bash
 | |
| 
 | |
| # https://www.tldp.org/LDP/abs/html/options.html#AEN19601
 | |
| # https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
 | |
| set -u -e -E -o pipefail
 | |
| 
 | |
| 
 | |
| BASEDIR=$(dirname "$0")
 | |
| BASEDIR=`(cd $BASEDIR; pwd)`
 | |
| 
 | |
| PR_NUMBER=0
 | |
| PUSH_UPSTREAM=1
 | |
| FORCE=0
 | |
| while [[ $# -gt 0 ]]
 | |
| do
 | |
|   key="$1"
 | |
| 
 | |
|   case $key in
 | |
|       --dryrun)
 | |
|       PUSH_UPSTREAM=0
 | |
|       shift # past argument
 | |
|       ;;
 | |
|       --force)
 | |
|       FORCE=1
 | |
|       shift # past argument
 | |
|       ;;
 | |
|       *)    # unknown option
 | |
|       PR_NUMBER="$1" # save it in an array for later
 | |
|       shift # past argument
 | |
|       ;;
 | |
|   esac
 | |
| done
 | |
| 
 | |
| if [ "$PR_NUMBER" -eq 0 ]; then
 | |
|   echo "Merge github PR into the target branches if status is green"
 | |
|   echo
 | |
|   echo "$0 PR_NUMBER [--dryrun] [--force]"
 | |
|   echo
 | |
|   echo    --dryrun   Performs all operations but does not push the merge back to git@github.com:angular/angular.git.
 | |
|   echo    --force    Continues even if PR status is not green.
 | |
|   exit 0
 | |
| fi
 | |
| 
 | |
| if [ -z ${TOKEN:-''} ]; then
 | |
|     echo "############################################################"
 | |
|     echo "############################################################"
 | |
|     echo "WARNING: you should set the TOKEN variable to a github token"
 | |
|     echo "############################################################"
 | |
|     echo "############################################################"
 | |
|     GH_AUTH=""
 | |
| else
 | |
|     GH_AUTH="Authorization: token $TOKEN"
 | |
| fi
 | |
| 
 | |
| PULL_JSON=`curl -H "$GH_AUTH" -s https://api.github.com/repos/angular/angular/pulls/$PR_NUMBER`
 | |
| PR_SHA_COUNT=`node $BASEDIR/utils/json_extract.js commits <<< """$PULL_JSON"""`
 | |
| STATUS_JSON_URL=`node $BASEDIR/utils/json_extract.js _links.statuses.href <<< """$PULL_JSON"""`
 | |
| STATUS=`curl -H "$GH_AUTH" -s $STATUS_JSON_URL | node $BASEDIR/utils/json_extract.js description | cut -d '|' -f1`
 | |
| PR_LABELS=`curl -H "$GH_AUTH" -s https://api.github.com/repos/angular/angular/issues/$PR_NUMBER/labels`
 | |
| PR_ACTION=`echo "$PR_LABELS" | node $BASEDIR/utils/json_extract.js "name=^PR action:"`
 | |
| PR_TARGET=`echo "$PR_LABELS"  | node $BASEDIR/utils/json_extract.js "name=^PR target:"`
 | |
| PR_CLA=`echo "$PR_LABELS"  | node $BASEDIR/utils/json_extract.js "name=^cla"`
 | |
| MASTER_BRANCH='master'
 | |
| 
 | |
| if [[ ! "$PR_ACTION" =~ "PR action: merge" ]]; then
 | |
|   echo The PR is missing 'PR action: merge(-assistance)' label, found: $PR_ACTION
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| if [[ "$PR_CLA" != "cla: yes" ]]; then
 | |
|   echo The PR is missing 'cla: Yes' label, found: $PR_CLA
 | |
|   exit 1
 | |
| fi
 | |
| 
 | |
| if [[ "$STATUS" != "All checks passed!" ]]; then
 | |
|   echo PR $PR_NUMBER is failing with: $STATUS
 | |
|   if [[ $FORCE == 1 ]]; then
 | |
|     echo FORCING: --force flag used to ignore PR status.
 | |
|   else
 | |
|     echo Exting...
 | |
|     exit 1
 | |
|   fi
 | |
| fi
 | |
| 
 | |
| if [[ $PR_TARGET == "PR target: master & patch" ]]; then
 | |
|   MERGE_MASTER=1
 | |
|   MERGE_PATCH=1
 | |
| elif [[ $PR_TARGET == "PR target: master-only" ]]; then
 | |
|   MERGE_MASTER=1
 | |
|   MERGE_PATCH=0
 | |
| elif [[ $PR_TARGET == "PR target: patch-only" ]]; then
 | |
|   MERGE_MASTER=0
 | |
|   MERGE_PATCH=1
 | |
| else
 | |
|   echo "Unknown PR target format: $PR_TARGET"
 | |
|   exit 1;
 | |
| fi
 | |
| 
 | |
| CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD`
 | |
| PATCH_BRANCH=`git ls-remote --heads  git@github.com:angular/angular.git | grep -E 'refs\/heads\/[0-9]+\.[0-9]+\.x' | cut -d '/' -f3 | sort -r | head -n1`
 | |
| 
 | |
| CHECKOUT_MASTER="git checkout merge_pr_master"
 | |
| CHECKOUT_PATCH="git checkout merge_pr_patch"
 | |
| RESTORE_BRANCH="git checkout $CURRENT_BRANCH"
 | |
| 
 | |
| FETCH_PR="git fetch git@github.com:angular/angular.git pull/$PR_NUMBER/head:merge_pr heads/$MASTER_BRANCH:merge_pr_master heads/$PATCH_BRANCH:merge_pr_patch -f"
 | |
| BASE_PR="git checkout merge_pr~$PR_SHA_COUNT -B merge_pr_base"
 | |
| SQUASH_PR="git rebase --autosquash --interactive merge_pr_base merge_pr"
 | |
| REWRITE_MESSAGE="git filter-branch -f --msg-filter \"$BASEDIR/utils/github_closes.js $PR_NUMBER\" merge_pr_base..merge_pr"
 | |
| PUSH_BRANCHES="git push git@github.com:angular/angular.git merge_pr_master:$MASTER_BRANCH merge_pr_patch:$PATCH_BRANCH"
 | |
| CHERRY_PICK_PR="git cherry-pick merge_pr_base..merge_pr"
 | |
| 
 | |
| # Checks that each PR branch to be merged upstream contains SHAs of commits that significantly changed our CI infrastructure.
 | |
| #
 | |
| # This check is used to enforce that we don't merge PRs that have not been rebased recently and could result in merging
 | |
| # of non-approved or otherwise bad changes.
 | |
| REQUIRED_BASE_SHA_MASTER="3fba6eff79a9b50909199eaa4ebf754c1c4adba6" # pullapprove => CODEOWNERS migration
 | |
| REQUIRED_BASE_SHA_PATCH="e3853e842ea5c10fafbc310a76a4a7f47ed8c65e"  # pullapprove => CODEOWNERS migration
 | |
| if [[ $MERGE_MASTER == 1 ]]; then
 | |
|   REQUIRED_BASE_SHA="$REQUIRED_BASE_SHA_MASTER"
 | |
| # check patch only if patch-only PR
 | |
| elif [[ $MERGE_PATCH == 1 ]]; then
 | |
|   REQUIRED_BASE_SHA="$REQUIRED_BASE_SHA_PATCH"
 | |
| fi
 | |
| CHECK_IF_PR_REBASED="git branch --quiet merge_pr --contains $REQUIRED_BASE_SHA"
 | |
| 
 | |
| echo "======================"
 | |
| echo "GitHub Merge PR Steps"
 | |
| echo "======================"
 | |
| echo "   $FETCH_PR"
 | |
| echo "   $BASE_PR"
 | |
| echo "   $CHECK_IF_PR_REBASED"
 | |
| echo "   $SQUASH_PR"
 | |
| echo "   $REWRITE_MESSAGE"
 | |
| if [[ $MERGE_MASTER == 1 ]]; then
 | |
|   echo "   $CHECKOUT_MASTER && $CHERRY_PICK_PR"
 | |
| fi
 | |
| if [[ $MERGE_PATCH == 1 ]]; then
 | |
|   echo "   $CHECKOUT_PATCH && $CHERRY_PICK_PR"
 | |
| fi
 | |
| echo "   $PUSH_BRANCHES"
 | |
| echo "   $RESTORE_BRANCH"
 | |
| echo "----------------------"
 | |
| echo ">>> Fetch PR: $FETCH_PR"
 | |
| $FETCH_PR
 | |
| echo ">>> Mark base: $BASE_PR"
 | |
| $BASE_PR
 | |
| echo ">>> Check if PR rebased: $CHECK_IF_PR_REBASED"
 | |
| if [[ $($CHECK_IF_PR_REBASED) != "" ]]; then
 | |
|   echo "The PR is sufficiently rebased!"
 | |
| else
 | |
|   echo ""
 | |
|   echo ""
 | |
|   echo "Failed to merge pull request #${PR_NUMBER} because it hasn't been rebased recently and could be bypassing new or updated CI checks!"
 | |
|   echo ""
 | |
|   echo "Please rebase the PR and try again."
 | |
|   echo ""
 | |
|   $RESTORE_BRANCH
 | |
|   exit 1
 | |
| fi
 | |
| echo ">>> Autosquash: $SQUASH_PR"
 | |
| GIT_EDITOR=echo $SQUASH_PR
 | |
| echo ">>> Rewrite message: $REWRITE_MESSAGE"
 | |
| # Next line should work, but it errors, hence copy paste the command.
 | |
| # $REWRITE_MESSAGE
 | |
| git filter-branch -f --msg-filter "$BASEDIR/utils/github_closes.js $PR_NUMBER" merge_pr_base..merge_pr
 | |
| if [[ $MERGE_MASTER == 1 ]]; then
 | |
|   echo
 | |
|   echo ">>> Cherry pick to master: $CHECKOUT_MASTER && $CHERRY_PICK_PR"
 | |
|   $CHECKOUT_MASTER
 | |
|   $CHERRY_PICK_PR
 | |
| fi
 | |
| if [[ $MERGE_PATCH == 1 ]]; then
 | |
|   echo
 | |
|   echo ">>> Cherry pick to path: $CHECKOUT_PATCH && $CHERRY_PICK_PR"
 | |
|   $CHECKOUT_PATCH
 | |
|   $CHERRY_PICK_PR
 | |
| fi
 | |
| $RESTORE_BRANCH
 | |
| 
 | |
| if [[ $PUSH_UPSTREAM == 1 ]]; then
 | |
|   echo ">>> Push branches to angular repo"
 | |
|   $PUSH_BRANCHES
 | |
| fi
 | |
| echo
 | |
| echo ">>>>>> SUCCESS <<<<<< PR#$PR_NUMBER merged."
 |