(prNumber: number, interactive: boolean = false)
| 20 | * @returns a status code indicating whether the rebase was successful. |
| 21 | */ |
| 22 | export async function rebasePr(prNumber: number, interactive: boolean = false): Promise<number> { |
| 23 | /** The singleton instance of the authenticated git client. */ |
| 24 | const git = await AuthenticatedGitClient.get(); |
| 25 | |
| 26 | if (git.hasUncommittedChanges()) { |
| 27 | Log.error('Cannot perform rebase of PR with local changes.'); |
| 28 | return 1; |
| 29 | } |
| 30 | |
| 31 | /** |
| 32 | * The branch or revision originally checked out before this method performed |
| 33 | * any Git operations that may change the working branch. |
| 34 | */ |
| 35 | const previousBranchOrRevision = git.getCurrentBranchOrRevision(); |
| 36 | /* Get the PR information from Github. */ |
| 37 | const pr = await fetchPullRequestFromGithub(git, prNumber); |
| 38 | |
| 39 | if (pr === null) { |
| 40 | Log.error(`Specified pull request does not exist.`); |
| 41 | return 1; |
| 42 | } |
| 43 | |
| 44 | const headRefName = pr.headRef.name; |
| 45 | const baseRefName = pr.baseRef.name; |
| 46 | const fullHeadRef = `${pr.headRef.repository.nameWithOwner}:${headRefName}`; |
| 47 | const fullBaseRef = `${pr.baseRef.repository.nameWithOwner}:${baseRefName}`; |
| 48 | const headRefUrl = addTokenToGitHttpsUrl(pr.headRef.repository.url, git.githubToken); |
| 49 | const baseRefUrl = addTokenToGitHttpsUrl(pr.baseRef.repository.url, git.githubToken); |
| 50 | |
| 51 | // Note: Since we use a detached head for rebasing the PR and therefore do not have |
| 52 | // remote-tracking branches configured, we need to set our expected ref and SHA. This |
| 53 | // allows us to use `--force-with-lease` for the detached head while ensuring that we |
| 54 | // never accidentally override upstream changes that have been pushed in the meanwhile. |
| 55 | // See: |
| 56 | // https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegtltexpectgt |
| 57 | const forceWithLeaseFlag = `--force-with-lease=${headRefName}:${pr.headRefOid}`; |
| 58 | const escapedHeadRefName = `'${headRefName.replace(/'/g, "'\\''")}'`; |
| 59 | const escapedForceWithLeaseFlag = `--force-with-lease=${escapedHeadRefName}:${pr.headRefOid}`; |
| 60 | |
| 61 | // If the PR does not allow maintainers to modify it, exit as the rebased PR cannot |
| 62 | // be pushed up. |
| 63 | if (!pr.maintainerCanModify && !pr.viewerDidAuthor) { |
| 64 | Log.error( |
| 65 | `Cannot rebase as you did not author the PR and the PR does not allow maintainers` + |
| 66 | `to modify the PR`, |
| 67 | ); |
| 68 | return 1; |
| 69 | } |
| 70 | |
| 71 | try { |
| 72 | // Fetches are done with --deepen=500 increase the likelihood of finding a common ancestor when |
| 73 | // a shallow clone is being used. |
| 74 | |
| 75 | // Fetch the branch at the commit of the PR, and check it out in a detached state. |
| 76 | Log.info(`Checking out PR #${prNumber} from ${fullHeadRef}`); |
| 77 | git.run(['fetch', '-q', headRefUrl, '--deepen=500', '--', headRefName]); |
| 78 | git.run(['checkout', '-q', '--detach', 'FETCH_HEAD']); |
| 79 | // Fetch the PRs target branch and rebase onto it. |
no test coverage detected