mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
3093edcad0
- Validate storedSha and storedBranch from _build-info.json. - Validate latestSha returned from GitHub API. - Validate branch in GithubClient.getShaForBranch and baseSha/headSha in GithubClient.getAffectedFiles. - Use execFileSync instead of execSync to avoid shell execution. TAG=agy CONV=4e3e69ba-3f3d-416b-9ce4-9ef75486d2f3
89 lines
2.2 KiB
JavaScript
89 lines
2.2 KiB
JavaScript
/**
|
|
* @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.dev/license
|
|
*/
|
|
|
|
import {get} from 'node:https';
|
|
import {posix} from 'node:path';
|
|
|
|
const GITHUB_API = 'https://api.github.com/repos/';
|
|
const SHA_REGEX = /^[0-9a-f]{40}$/i;
|
|
const BRANCH_REGEX = /^(?!.*\.\.)[a-zA-Z0-9/_.-]+$/;
|
|
|
|
export class GithubClient {
|
|
#token;
|
|
#ua;
|
|
#api;
|
|
|
|
constructor(repo, token, ua) {
|
|
this.#token = token;
|
|
this.#ua = ua;
|
|
this.#api = posix.join(GITHUB_API, repo);
|
|
}
|
|
|
|
/**
|
|
* Get the affected files.
|
|
*
|
|
* @param {string} baseSha
|
|
* @param {string} headSha
|
|
* @returns Promise<string[]>
|
|
*/
|
|
async getAffectedFiles(baseSha, headSha) {
|
|
if (!SHA_REGEX.test(baseSha)) {
|
|
throw new Error(`Invalid base SHA: ${baseSha}`);
|
|
}
|
|
if (!SHA_REGEX.test(headSha)) {
|
|
throw new Error(`Invalid head SHA: ${headSha}`);
|
|
}
|
|
const {files} = JSON.parse(await this.#httpGet(`${this.#api}/compare/${baseSha}...${headSha}`));
|
|
return files.map((f) => f.filename);
|
|
}
|
|
|
|
/**
|
|
* Get SHA of a branch.
|
|
*
|
|
* @param {string} branch
|
|
* @returns Promise<string>
|
|
*/
|
|
async getShaForBranch(branch) {
|
|
if (!BRANCH_REGEX.test(branch)) {
|
|
throw new Error(`Invalid branch name: ${branch}`);
|
|
}
|
|
const sha = await this.#httpGet(`${this.#api}/commits/${branch}`, {
|
|
headers: {Accept: 'application/vnd.github.VERSION.sha'},
|
|
});
|
|
|
|
if (!sha) {
|
|
throw new Error(`Unable to extract the SHA for '${branch}'.`);
|
|
}
|
|
|
|
return sha.trim();
|
|
}
|
|
|
|
#httpGet(url, options = {}) {
|
|
options.headers ??= {};
|
|
options.headers['Authorization'] = `token ${this.#token}`;
|
|
// User agent is required
|
|
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#user-agent-required
|
|
options.headers['User-Agent'] = this.#ua;
|
|
|
|
return new Promise((resolve, reject) => {
|
|
get(url, options, (res) => {
|
|
let data = '';
|
|
res
|
|
.on('data', (chunk) => {
|
|
data += chunk;
|
|
})
|
|
.on('end', () => {
|
|
resolve(data);
|
|
});
|
|
}).on('error', (e) => {
|
|
reject(e);
|
|
});
|
|
});
|
|
}
|
|
}
|