angular/aio/scripts/update-cli-help/index.mjs
Alan Agius 2dc31576ab ci: add Angular CLI help pages action (#48577)
This commits adds an action to update the Angular CLI help contents that are used by AIO to generate CLI guides.

This also changes the setup to include the files are source files instead of having to clone the repository each time. This also simplifies the PR review process of the PR opened by the action.

PR Close #48577
2023-01-10 08:01:38 -08:00

140 lines
4.1 KiB
JavaScript

import {execSync} from 'node:child_process';
import {readFile, writeFile, mkdtemp, realpath, rm, rename} from 'node:fs/promises';
import {tmpdir} from 'os';
import {get} from 'node:https';
import {dirname, resolve as resolvePath, posix, join} from 'node:path';
import {fileURLToPath} from 'node:url';
import {existsSync} from 'node:fs';
const GITHUB_API = 'https://api.github.com/repos/';
const CLI_BUILDS_REPO = 'angular/cli-builds';
const GITHUB_API_CLI_BUILDS = posix.join(GITHUB_API, CLI_BUILDS_REPO);
const scriptDir = dirname(fileURLToPath(import.meta.url));
const CLI_HELP_CONTENT_PATH = resolvePath(scriptDir, '../../content/cli/help');
const CLI_SHA_PATH = join(CLI_HELP_CONTENT_PATH, 'build-info.json');
async function main() {
if (!existsSync(CLI_SHA_PATH)) {
throw new Error(`${CLI_SHA_PATH} does not exist.`);
}
const branch = process.env.GITHUB_REF;
const {sha: currentSha} = JSON.parse(await readFile(CLI_SHA_PATH, 'utf-8'));
const latestSha = await getShaFromCliBuilds(branch);
console.log(`Comparing ${currentSha}...${latestSha}.`);
const affectedFiles = await getAffectedFiles(currentSha, latestSha);
const changedHelpFiles = affectedFiles.filter((file) => file.startsWith('help/'));
if (changedHelpFiles.length === 0) {
console.log(`No 'help/**' files changed between ${currentSha} and ${latestSha}.`);
return;
}
console.log(
`The below help files changed between ${currentSha} and ${latestSha}:\n` +
changedHelpFiles.map((f) => '* ' + f).join('\n')
);
const temporaryDir = await realpath(await mkdtemp(join(tmpdir(), 'cli-src-')));
const execOptions = {cwd: temporaryDir, stdio: 'inherit'};
execSync('git init', execOptions);
execSync('git remote add origin https://github.com/angular/cli-builds.git', execOptions);
// fetch a commit
execSync(`git fetch origin ${latestSha}`, execOptions);
// reset this repository's main branch to the commit of interest
execSync('git reset --hard FETCH_HEAD', execOptions);
// get sha when files where changed
const shaWhenFilesChanged = execSync(`git rev-list -1 ${latestSha} "help/"`, {
encoding: 'utf8',
cwd: temporaryDir,
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
// Delete current contents
await rm(CLI_HELP_CONTENT_PATH, {recursive: true, force: true});
// Move Help contents
await rename(join(temporaryDir, 'help'), CLI_HELP_CONTENT_PATH);
// Write SHA to file.
await writeFile(
CLI_SHA_PATH,
JSON.stringify(
{
branchName: branch,
sha: shaWhenFilesChanged,
},
undefined,
2
)
);
console.log('\nChanges: ');
execSync(`git status --porcelain`, {stdio: 'inherit'});
console.log(`Successfully updated help files in '${CLI_HELP_CONTENT_PATH}'.\n`);
}
/**
* Get SHA of a branch.
*
* @param {string} branch
* @param {string} headSha
* @returns Promise<string>
*/
async function getShaFromCliBuilds(branch) {
const sha = await httpGet(`${GITHUB_API_CLI_BUILDS}/commits/${branch}`, {
headers: {Accept: 'application/vnd.github.VERSION.sha'},
});
if (!sha) {
throw new Error(`Unable to extract the SHA for '${branch}'.`);
}
return sha;
}
/**
* Get the affected files.
*
* @param {string} baseSha
* @param {string} headSha
* @returns Promise<string[]>
*/
async function getAffectedFiles(baseSha, headSha) {
const {files} = JSON.parse(
await httpGet(`${GITHUB_API_CLI_BUILDS}/compare/${baseSha}...${headSha}`)
);
return files.map((f) => f.filename);
}
function httpGet(url, options = {}) {
options.headers ??= {};
options.headers['Authorization'] = `token ${process.env.GITHUB_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'] = `AIO_Angular_CLI_Sources_Update`;
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);
});
});
}
main().catch((err) => {
console.error(err);
process.exit(1);
});