Creates a tool for staging and publishing releases as per the new branching and versioning that has been outlined in the following document. The tool is intended to be used across the organization to ensure consistent branching/versioning and labeling: https://docs.google.com/document/d/197kVillDwx-RZtSVOBtPb4BBIAw0E9RT3q3v6DZkykU/edit#heading=h.s3qlps8f4zq7dd The tool implements the actions as outlined in the following initial plan: https://hackmd.io/2Le8leq0S6G_R5VEVTNK9A. The implementation slightly diverged in so far that it performs staging and publishing together so that releasing is a single convenient command. In case of errors for which re-running the full command is not sufficient, we want to consider adding recover functionality. e.g. when the staging completed, but the actual NPM publishing aborted unexpectedly due to build errors. PR Close #38656
73 lines
3.5 KiB
TypeScript
73 lines
3.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC 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
|
|
*/
|
|
|
|
import * as Octokit from '@octokit/rest';
|
|
import {GitClient} from '../../utils/git/index';
|
|
|
|
/** State of a pull request in Github. */
|
|
export type PullRequestState = 'merged'|'closed'|'open';
|
|
|
|
/** Gets whether a given pull request has been merged. */
|
|
export async function getPullRequestState(api: GitClient, id: number): Promise<PullRequestState> {
|
|
const {data} = await api.github.pulls.get({...api.remoteParams, pull_number: id});
|
|
if (data.merged) {
|
|
return 'merged';
|
|
} else if (data.closed_at !== null) {
|
|
return await isPullRequestClosedWithAssociatedCommit(api, id) ? 'merged' : 'closed';
|
|
} else {
|
|
return 'open';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Whether the pull request has been closed with an associated commit. This is usually
|
|
* the case if a PR has been merged using the autosquash merge script strategy. Since
|
|
* the merge is not fast-forward, Github does not consider the PR as merged and instead
|
|
* shows the PR as closed. See for example: https://github.com/angular/angular/pull/37918.
|
|
*/
|
|
async function isPullRequestClosedWithAssociatedCommit(api: GitClient, id: number) {
|
|
const request =
|
|
api.github.issues.listEvents.endpoint.merge({...api.remoteParams, issue_number: id});
|
|
const events: Octokit.IssuesListEventsResponse = await api.github.paginate(request);
|
|
// Iterate through the events of the pull request in reverse. We want to find the most
|
|
// recent events and check if the PR has been closed with a commit associated with it.
|
|
// If the PR has been closed through a commit, we assume that the PR has been merged
|
|
// using the autosquash merge strategy. For more details. See the `AutosquashMergeStrategy`.
|
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
const {event, commit_id} = events[i];
|
|
// If we come across a "reopened" event, we abort looking for referenced commits. Any
|
|
// commits that closed the PR before, are no longer relevant and did not close the PR.
|
|
if (event === 'reopened') {
|
|
return false;
|
|
}
|
|
// If a `closed` event is captured with a commit assigned, then we assume that
|
|
// this PR has been merged properly.
|
|
if (event === 'closed' && commit_id) {
|
|
return true;
|
|
}
|
|
// If the PR has been referenced by a commit, check if the commit closes this pull
|
|
// request. Note that this is needed besides checking `closed` as PRs could be merged
|
|
// into any non-default branch where the `Closes <..>` keyword does not work and the PR
|
|
// is simply closed without an associated `commit_id`. For more details see:
|
|
// https://docs.github.com/en/enterprise/2.16/user/github/managing-your-work-on-github/closing-issues-using-keywords#:~:text=non-default.
|
|
if (event === 'referenced' && commit_id &&
|
|
await isCommitClosingPullRequest(api, commit_id, id)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Checks whether the specified commit is closing the given pull request. */
|
|
async function isCommitClosingPullRequest(api: GitClient, sha: string, id: number) {
|
|
const {data} = await api.github.repos.getCommit({...api.remoteParams, ref: sha});
|
|
// Matches the closing keyword supported in commit messages. See:
|
|
// https://docs.github.com/en/enterprise/2.16/user/github/managing-your-work-on-github/closing-issues-using-keywords.
|
|
return data.commit.message.match(new RegExp(`close[sd]? #${id}[^0-9]?`, 'i'));
|
|
}
|