override async merge()

in ng-dev/pr/merge/strategies/autosquash-merge.ts [34:123]


  override async merge(pullRequest: PullRequest): Promise<PullRequestFailure | null> {
    const {prNumber, targetBranches, requiredBaseSha, needsCommitMessageFixup, githubTargetBranch} =
      pullRequest;
    // In case a required base is specified for this pull request, check if the pull
    // request contains the given commit. If not, return a pull request failure. This
    // check is useful for enforcing that PRs are rebased on top of a given commit. e.g.
    // a commit that changes the codeowner ship validation. PRs which are not rebased
    // could bypass new codeowner ship rules.
    if (requiredBaseSha && !this.git.hasCommit(TEMP_PR_HEAD_BRANCH, requiredBaseSha)) {
      return PullRequestFailure.unsatisfiedBaseSha();
    }

    // SHA for the first commit the pull request is based on. Usually we would able
    // to just rely on the base revision provided by `getPullRequestBaseRevision`, but
    // the revision would rely on the amount of commits in a pull request. This is not
    // reliable as we rebase the PR with autosquash where the amount of commits could
    // change. We work around this by parsing the base revision so that we have a fixated
    // SHA before the autosquash rebase is performed.
    const baseSha = this.git
      .run(['rev-parse', this.getPullRequestBaseRevision(pullRequest)])
      .stdout.trim();
    // Git revision range that matches the pull request commits.
    const revisionRange = `${baseSha}..${TEMP_PR_HEAD_BRANCH}`;

    // We always rebase the pull request so that fixup or squash commits are automatically
    // collapsed. Git's autosquash functionality does only work in interactive rebases, so
    // our rebase is always interactive. In reality though, unless a commit message fixup
    // is desired, we set the `GIT_SEQUENCE_EDITOR` environment variable to `true` so that
    // the rebase seems interactive to Git, while it's not interactive to the user.
    // See: https://github.com/git/git/commit/891d4a0313edc03f7e2ecb96edec5d30dc182294.
    const branchOrRevisionBeforeRebase = this.git.getCurrentBranchOrRevision();
    const rebaseEnv = needsCommitMessageFixup
      ? undefined
      : {...process.env, GIT_SEQUENCE_EDITOR: 'true'};
    this.git.run(['rebase', '--interactive', '--autosquash', baseSha, TEMP_PR_HEAD_BRANCH], {
      stdio: 'inherit',
      env: rebaseEnv,
    });

    // Update pull requests commits to reference the pull request. This matches what
    // Github does when pull requests are merged through the Web UI. The motivation is
    // that it should be easy to determine which pull request contained a given commit.
    // Note: The filter-branch command relies on the working tree, so we want to make sure
    // that we are on the initial branch or revision where the merge script has been invoked.
    this.git.run(['checkout', '-f', branchOrRevisionBeforeRebase]);
    this.git.run([
      'filter-branch',
      '-f',
      '--msg-filter',
      `${MSG_FILTER_SCRIPT} ${prNumber}`,
      revisionRange,
    ]);

    // Cherry-pick the pull request into all determined target branches.
    const failedBranches = this.cherryPickIntoTargetBranches(revisionRange, targetBranches);

    if (failedBranches.length) {
      return PullRequestFailure.mergeConflicts(failedBranches);
    }

    this.pushTargetBranchesUpstream(targetBranches);

    /** The local branch name of the github targeted branch. */
    const localBranch = this.getLocalTargetBranchName(githubTargetBranch);
    /** The SHA of the commit pushed to github which represents closing the PR. */
    const sha = this.git.run(['rev-parse', localBranch]).stdout.trim();
    // Github automatically closes PRs whose commits are merged into the main branch on Github.
    // However, it does not note them as merged using the purple merge badge as occurs when done via
    // the UI. To inform users that the PR was in fact merged, add a comment expressing the fact
    // that the PR is merged.
    await this.git.github.issues.createComment({
      ...this.git.remoteParams,
      issue_number: pullRequest.prNumber,
      body: `This PR was merged into the repository by commit ${sha}.`,
    });

    // For PRs which do not target the `main` branch on Github, Github does not automatically
    // close the PR when its commit is pushed into the repository. To ensure these PRs are
    // correctly marked as closed, we must detect this situation and close the PR via the API after
    // the upstream pushes are completed.
    if (githubTargetBranch !== this.git.mainBranchName) {
      await this.git.github.pulls.update({
        ...this.git.remoteParams,
        pull_number: pullRequest.prNumber,
        state: 'closed',
      });
    }

    return null;
  }