diff --git a/package.json b/package.json index bb4310c636a4..89f77198641b 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,6 @@ "node-sass": "^4.9.3", "parse5": "^5.0.0", "protractor": "^5.4.0", - "request": "^2.83.0", "resolve-bin": "^0.4.0", "rollup": "^0.56.3", "rollup-plugin-alias": "^1.4.0", diff --git a/tools/release/stage-release.ts b/tools/release/stage-release.ts index 931741053791..10347e5409d5 100644 --- a/tools/release/stage-release.ts +++ b/tools/release/stage-release.ts @@ -1,3 +1,4 @@ +import * as OctokitApi from '@octokit/rest'; import {bold, cyan, green, italic, red, yellow} from 'chalk'; import {existsSync, readFileSync, writeFileSync} from 'fs'; import {prompt} from 'inquirer'; @@ -41,7 +42,12 @@ class StageReleaseTask { /** Instance of a wrapper that can execute Git commands. */ git: GitClient; - constructor(public projectDir: string) { + /** Octokit API instance that can be used to make Github API calls. */ + githubApi: OctokitApi; + + constructor(public projectDir: string, + public repositoryOwner: string, + public repositoryName: string) { this.packageJsonPath = join(projectDir, 'package.json'); console.log(this.projectDir); @@ -61,7 +67,9 @@ class StageReleaseTask { process.exit(1); } - this.git = new GitClient(projectDir, this.packageJson.repository.url); + this.githubApi = new OctokitApi(); + this.git = new GitClient(projectDir, + `https://github.com/${repositoryOwner}/${repositoryName}.git`); } async run() { @@ -81,8 +89,7 @@ class StageReleaseTask { this.verifyPublishBranch(expectedPublishBranch); this.verifyLocalCommitsMatchUpstream(expectedPublishBranch); this.verifyNoUncommittedChanges(); - - // TODO(devversion): Assert that GitHub statuses succeed for this branch. + await this.verifyPassingGithubStatus(); const newVersionName = newVersion.format(); const stagingBranch = `release-stage/${newVersionName}`; @@ -136,8 +143,8 @@ class StageReleaseTask { // Check if current branch matches the expected publish branch. if (expectedPublishBranch !== currentBranchName) { - console.error(red(`Cannot stage release from "${italic(currentBranchName)}". Please stage ` + - `the release from "${bold(expectedPublishBranch)}".`)); + console.error(red(` ✘ Cannot stage release from "${italic(currentBranchName)}". Please ` + + `stage the release from "${bold(expectedPublishBranch)}".`)); process.exit(1); } } @@ -149,8 +156,9 @@ class StageReleaseTask { // Check if the current branch is in sync with the remote branch. if (upstreamCommitSha !== localCommitSha) { - console.error(red(`Cannot stage release. The current branch is not in sync with the remote ` + - `branch. Please make sure your local branch "${italic(publishBranch)}" is up to date.`)); + console.error(red(` ✘ Cannot stage release. The current branch is not in sync with the ` + + `remote branch. Please make sure your local branch "${italic(publishBranch)}" is up ` + + `to date.`)); process.exit(1); } } @@ -158,7 +166,7 @@ class StageReleaseTask { /** Verifies that there are no uncommitted changes in the project. */ private verifyNoUncommittedChanges() { if (this.git.hasUncommittedChanges()) { - console.error(red(`Cannot stage release. There are changes which are not committed and ` + + console.error(red(` ✘ Cannot stage release. There are changes which are not committed and ` + `should be stashed.`)); process.exit(1); } @@ -169,10 +177,32 @@ class StageReleaseTask { const newPackageJson = {...this.packageJson, version: newVersionName}; writeFileSync(this.packageJsonPath, JSON.stringify(newPackageJson, null, 2)); } + + /** Verifies that the latest commit of the current branch is passing all Github statuses. */ + private async verifyPassingGithubStatus() { + const commitRef = this.git.getLocalCommitSha('HEAD'); + const {state} = (await this.githubApi.repos.getCombinedStatusForRef({ + owner: this.repositoryOwner, + repo: this.repositoryName, + ref: commitRef, + })).data; + + if (state === 'failure') { + console.error(red(` ✘ Cannot stage release. Commit "${commitRef}" does not pass all ` + + `github status checks. Please make sure this commit passes all checks before re-running.`)); + process.exit(1); + } else if (state === 'pending') { + console.error(red(` ✘ Cannot stage release yet. Commit "${commitRef}" still has ` + + `pending github statuses that need to succeed before staging a release.`)); + process.exit(0); + } + + console.info(green(` ✓ Upstream commit is passing all github status checks.`)); + } } /** Entry-point for the release staging script. */ if (require.main === module) { - new StageReleaseTask(join(__dirname, '../../')).run(); + new StageReleaseTask(join(__dirname, '../../'), 'angular', 'material2').run(); } diff --git a/yarn.lock b/yarn.lock index 69286713f94f..c2160412cff4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9918,7 +9918,7 @@ request@2.87.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@^2.0.0, request@^2.55.0, request@^2.72.0, request@^2.74.0, request@^2.79.0, request@^2.81.0, request@^2.83.0, request@^2.85.0, request@^2.87.0: +request@^2.0.0, request@^2.55.0, request@^2.72.0, request@^2.74.0, request@^2.79.0, request@^2.81.0, request@^2.85.0, request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==