2020-01-29 12:19:16 -05: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
|
|
|
|
*/
|
|
|
|
|
2020-03-23 14:22:57 -04:00
|
|
|
// NOTE: When invoked directly via node, this script will take the first positional
|
|
|
|
// arguement as to be the PR number, and log out the ref and sha information in its
|
|
|
|
// JSON format. For other usages, the function to get the ref and sha information
|
|
|
|
// may be imported by another script to be invoked.
|
|
|
|
|
2020-01-29 12:47:54 -05:00
|
|
|
// This script uses `console` to print messages to the user.
|
|
|
|
// tslint:disable:no-console
|
|
|
|
|
2020-01-29 12:19:16 -05:00
|
|
|
const https = require('https');
|
|
|
|
const util = require('util');
|
|
|
|
const child_process = require('child_process');
|
|
|
|
const exec = util.promisify(child_process.exec);
|
|
|
|
|
|
|
|
async function requestDataFromGithub(url) {
|
|
|
|
// GitHub requires a user agent: https://developer.github.com/v3/#user-agent-required
|
2020-03-23 14:22:57 -04:00
|
|
|
let options = {headers: {'User-Agent': 'angular'}};
|
|
|
|
|
|
|
|
// If a github token is present, use it for authorization.
|
|
|
|
const githubToken = process.env.TOKEN || process.env.GITHUB_TOKEN || '';
|
|
|
|
if (githubToken) {
|
|
|
|
options = {
|
|
|
|
headers: {
|
|
|
|
Authorization: `token ${githubToken}`,
|
|
|
|
...options.headers,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2020-01-29 12:19:16 -05:00
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
https
|
|
|
|
.get(
|
|
|
|
url, options,
|
|
|
|
(res) => {
|
|
|
|
const {statusCode} = res;
|
|
|
|
const contentType = res.headers['content-type'];
|
|
|
|
let rawData = '';
|
|
|
|
|
|
|
|
res.on('data', (chunk) => { rawData += chunk; });
|
|
|
|
res.on('end', () => {
|
|
|
|
let error;
|
|
|
|
if (statusCode !== 200) {
|
|
|
|
error = new Error(
|
|
|
|
`Request Failed.\nStatus Code: ${statusCode}.\nResponse: ${rawData}`);
|
|
|
|
} else if (!/^application\/json/.test(contentType)) {
|
|
|
|
error = new Error(
|
|
|
|
'Invalid content-type.\n' +
|
|
|
|
`Expected application/json but received ${contentType}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
reject(error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
resolve(JSON.parse(rawData));
|
|
|
|
} catch (e) {
|
|
|
|
reject(e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.on('error', (e) => { reject(e); });
|
|
|
|
});
|
|
|
|
}
|
2020-03-23 14:22:57 -04:00
|
|
|
// clang-format off
|
|
|
|
// clang keeps trying to put the function name on the next line.
|
|
|
|
async function getRefsAndShasForTarget(prNumber, suppressLog) {
|
|
|
|
// clang-format on
|
|
|
|
// If the environment variable already contains the refs and shas, reuse them.
|
|
|
|
if (process.env['GITHUB_REFS_AND_SHAS']) {
|
|
|
|
suppressLog ||
|
|
|
|
console.info(`Retrieved refs and SHAs for PR ${prNumber} from environment variables.`);
|
|
|
|
return JSON.parse(process.env['GITHUB_REFS_AND_SHAS']);
|
|
|
|
}
|
2020-01-29 12:19:16 -05:00
|
|
|
|
2020-03-23 14:22:57 -04:00
|
|
|
suppressLog ||
|
|
|
|
console.info(`Getting refs and SHAs for PR ${prNumber} on angular/angular from Github.`);
|
2020-01-29 12:19:16 -05:00
|
|
|
const pullsUrl = `https://api.github.com/repos/angular/angular/pulls/${prNumber}`;
|
|
|
|
const result = await requestDataFromGithub(pullsUrl);
|
|
|
|
|
|
|
|
// Ensure the base ref is up to date
|
|
|
|
await exec(`git fetch origin ${result.base.ref}`);
|
|
|
|
|
|
|
|
// The sha of the latest commit on the target branch.
|
|
|
|
const {stdout: latestShaOfTargetBranch} = await exec(`git rev-parse origin/${result.base.ref}`);
|
|
|
|
// The sha of the latest commit on the PR.
|
|
|
|
const {stdout: latestShaOfPrBranch} = await exec(`git rev-parse HEAD`);
|
|
|
|
// The first common SHA in the history of the target branch and the latest commit in the PR.
|
|
|
|
const {stdout: commonAncestorSha} =
|
|
|
|
await exec(`git merge-base origin/${result.base.ref} ${latestShaOfPrBranch}`);
|
|
|
|
|
2020-01-29 12:47:54 -05:00
|
|
|
const output = {
|
2020-01-29 12:19:16 -05:00
|
|
|
base: {
|
2020-01-29 12:47:54 -05:00
|
|
|
ref: result.base.ref,
|
|
|
|
sha: result.base.sha,
|
2020-01-29 12:19:16 -05:00
|
|
|
},
|
|
|
|
head: {
|
2020-01-29 12:47:54 -05:00
|
|
|
ref: result.head.ref,
|
|
|
|
sha: result.head.sha,
|
2020-01-29 12:19:16 -05:00
|
|
|
},
|
|
|
|
commonAncestorSha: commonAncestorSha.trim(),
|
|
|
|
latestShaOfTargetBranch: latestShaOfTargetBranch.trim(),
|
|
|
|
latestShaOfPrBranch: latestShaOfPrBranch.trim(),
|
2020-01-29 12:47:54 -05:00
|
|
|
};
|
|
|
|
return output;
|
2020-03-23 14:22:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the script is called directly, log the output of the refs and sha for the
|
|
|
|
// requested PR.
|
|
|
|
if (require.main === module) {
|
|
|
|
const run = async() => {
|
|
|
|
const prNumber = Number.parseInt(process.argv[2], 10);
|
|
|
|
if (!!prNumber) {
|
|
|
|
console.info(JSON.stringify(await getRefsAndShasForTarget(prNumber, true)));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
run();
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = getRefsAndShasForTarget;
|