| 
									
										
										
										
											2019-03-11 16:00:49 +00:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * **Usage:** | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * node rebase-pr <github-repository> <pull-request-number> | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * **Example:** | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * node rebase-pr angular/angular 123 | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Rebases the current branch on top of the GitHub PR target branch. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * **Context:** | 
					
						
							|  |  |  |  * Since a GitHub PR is not necessarily up to date with its target branch, it is useful to rebase | 
					
						
							|  |  |  |  * prior to testing it on CI to ensure more up to date test results. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * **Implementation details:** | 
					
						
							|  |  |  |  * This script obtains the base for a GitHub PR via the | 
					
						
							|  |  |  |  * [GitHub PR API](https://developer.github.com/v3/pulls/#get-a-single-pull-request), then
 | 
					
						
							|  |  |  |  * fetches that branch, and rebases the current branch on top of it. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * **NOTE:** | 
					
						
							|  |  |  |  * This script cannot use external dependencies or be compiled because it needs to run before the | 
					
						
							|  |  |  |  * environment is setup. | 
					
						
							|  |  |  |  * Use only features supported by the NodeJS versions used in the environment. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This script uses `console` to print messages to the user.
 | 
					
						
							|  |  |  | // tslint:disable:no-console
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Imports
 | 
					
						
							|  |  |  | const util = require('util'); | 
					
						
							|  |  |  | const child_process = require('child_process'); | 
					
						
							|  |  |  | const exec = util.promisify(child_process.exec); | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  | const getRefsAndShasForTarget = require('./utils/get-refs-and-shas-for-target'); | 
					
						
							| 
									
										
										
										
											2019-03-11 16:00:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // CLI validation
 | 
					
						
							|  |  |  | if (process.argv.length != 4) { | 
					
						
							|  |  |  |   console.error(`This script requires the GitHub repository and PR number as arguments.`); | 
					
						
							|  |  |  |   console.error(`Example: node tools/rebase-pr.js angular/angular 123`); | 
					
						
							|  |  |  |   process.exitCode = 1; | 
					
						
							|  |  |  |   return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Run
 | 
					
						
							|  |  |  | _main(...process.argv.slice(2)).catch(err => { | 
					
						
							|  |  |  |   console.log('Failed to rebase on top of target branch.\n'); | 
					
						
							|  |  |  |   console.error(err); | 
					
						
							|  |  |  |   process.exitCode = 1; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Helpers
 | 
					
						
							|  |  |  | async function _main(repository, prNumber) { | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const target = await getRefsAndShasForTarget(prNumber); | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Log known refs and shas
 | 
					
						
							|  |  |  |   console.log(`--------------------------------`); | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |   console.log(`    Target Branch:                   ${target.base.ref}`); | 
					
						
							|  |  |  |   console.log(`    Latest Commit for Target Branch: ${target.latestShaOfTargetBranch}`); | 
					
						
							|  |  |  |   console.log(`    Latest Commit for PR:            ${target.latestShaOfPrBranch}`); | 
					
						
							|  |  |  |   console.log(`    First Common Ancestor SHA:       ${target.commonAncestorSha}`); | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  |   console.log(`--------------------------------`); | 
					
						
							|  |  |  |   console.log(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  |   // Get the count of commits between the latest commit from origin and the common ancestor SHA.
 | 
					
						
							|  |  |  |   const {stdout: commitCount} = | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |       await exec(`git rev-list --count origin/${target.base.ref}...${target.commonAncestorSha}`); | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  |   console.log(`Checking ${commitCount.trim()} commits for changes in the CircleCI config file.`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Check if the files changed between the latest commit from origin and the common ancestor SHA
 | 
					
						
							|  |  |  |   // includes the CircleCI config.
 | 
					
						
							|  |  |  |   const {stdout: circleCIConfigChanged} = await exec( | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |       `git diff --name-only origin/${target.base.ref} ${target.commonAncestorSha} -- .circleci/config.yml`); | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (!!circleCIConfigChanged) { | 
					
						
							|  |  |  |     throw Error(`
 | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |         CircleCI config on ${target.base.ref} has been modified since commit ${target.commonAncestorSha.slice(0, 7)}, | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  |         which this PR is based on. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |         Please rebase the PR on ${target.base.ref} after fetching from upstream. | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Rebase instructions for PR Author, please run the following commands: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |           git fetch upstream ${target.base.ref}; | 
					
						
							|  |  |  |           git checkout ${target.head.ref}; | 
					
						
							|  |  |  |           git rebase upstream/${target.base.ref}; | 
					
						
							| 
									
										
										
										
											2019-11-11 10:50:53 -08:00
										 |  |  |           git push --force-with-lease; | 
					
						
							|  |  |  |         `);
 | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     console.log('No change found in the CircleCI config file, continuing.'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   console.log(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Rebase the PR.
 | 
					
						
							| 
									
										
										
										
											2020-01-29 09:19:16 -08:00
										 |  |  |   console.log(`Rebasing current branch on ${target.base.ref}.`); | 
					
						
							|  |  |  |   await exec(`git rebase origin/${target.base.ref}`); | 
					
						
							| 
									
										
										
										
											2019-03-11 16:00:49 +00:00
										 |  |  |   console.log('Rebase successful.'); | 
					
						
							|  |  |  | } |