mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
When a new branch is created for a feature, it may not exist in the downstream repo. For example, during an exceptional minor release. In such scenarios, we fallback to the last known branch. This was previously handled in a catch block, but this change makes the fallback more explicit. PR Close #63733
112 lines
4 KiB
JavaScript
112 lines
4 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
|
|
*/
|
|
|
|
//tslint:disable:no-console
|
|
import assert from 'node:assert';
|
|
import {execSync} from 'node:child_process';
|
|
import {existsSync, constants as fsConstants} from 'node:fs';
|
|
import {copyFile, mkdtemp, readdir, readFile, realpath, unlink, writeFile} from 'node:fs/promises';
|
|
import {tmpdir} from 'node:os';
|
|
import {join} from 'node:path';
|
|
|
|
export async function copyJsonAssets({repo, githubApi, assetsPath, destPath}) {
|
|
const buildInfoPath = join(destPath, '_build-info.json');
|
|
if (!existsSync(buildInfoPath)) {
|
|
throw new Error(`${buildInfoPath} does not exist.`);
|
|
}
|
|
|
|
assert(process.env.GITHUB_REF);
|
|
const currentBranch = process.env.GITHUB_REF;
|
|
|
|
const {sha: storedSha, branchName: storedBranch} = JSON.parse(
|
|
await readFile(buildInfoPath, 'utf-8'),
|
|
);
|
|
|
|
let downstreamBranch = currentBranch;
|
|
let latestSha = await githubApi.getShaForBranch(currentBranch);
|
|
if (
|
|
latestSha.includes('No commit') &&
|
|
currentBranch !== 'refs/heads/main' &&
|
|
currentBranch !== storedBranch
|
|
) {
|
|
// In some cases, such as when a new branch is created for a feature,
|
|
// the branch may not exist in the downstream repo. For example, during an
|
|
// exceptional minor release (e.g. FW 20.3.x and Components: 20.2.x).
|
|
// In such scenarios, we fallback to the last known branch.
|
|
latestSha = await githubApi.getShaForBranch(storedBranch);
|
|
downstreamBranch = storedBranch;
|
|
}
|
|
|
|
console.log(`Comparing ${storedSha}...${latestSha}.`);
|
|
const affectedFiles = await githubApi.getAffectedFiles(storedSha, latestSha);
|
|
const changedFiles = affectedFiles.filter((file) => file.startsWith(`${assetsPath}/`));
|
|
|
|
let shaWhenFilesChanged;
|
|
if (changedFiles.length > 0) {
|
|
console.log(
|
|
`The below files changed between ${storedSha} and ${latestSha}:\n` +
|
|
changedFiles.map((f) => '* ' + f).join('\n'),
|
|
);
|
|
|
|
const temporaryDir = await realpath(await mkdtemp(join(tmpdir(), 'copy-json-assets-')));
|
|
const execOptions = {cwd: temporaryDir, stdio: 'inherit'};
|
|
execSync('git init', execOptions);
|
|
execSync(`git remote add origin https://github.com/${repo}.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
|
|
shaWhenFilesChanged = execSync(`git rev-list -1 ${latestSha} "${assetsPath}/"`, {
|
|
encoding: 'utf8',
|
|
cwd: temporaryDir,
|
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
}).trim();
|
|
|
|
// Delete existing asset files.
|
|
const apiFilesUnlink = (await readdir(destPath))
|
|
.filter((f) => f.endsWith('.json'))
|
|
.map((f) => unlink(join(destPath, f)));
|
|
|
|
await Promise.allSettled(apiFilesUnlink);
|
|
|
|
// Copy new asset files
|
|
const tempAssetsDir = join(temporaryDir, assetsPath);
|
|
const assetFilesCopy = (await readdir(tempAssetsDir)).map((f) => {
|
|
const src = join(tempAssetsDir, f);
|
|
const dest = join(destPath, f);
|
|
|
|
return copyFile(src, dest, fsConstants.COPYFILE_FICLONE);
|
|
});
|
|
|
|
await Promise.allSettled(assetFilesCopy);
|
|
|
|
console.log(`Successfully updated asset files in '${destPath}'.\n`);
|
|
} else {
|
|
console.log(`No '${assetsPath}/**' files changed between ${storedSha} and ${latestSha}.`);
|
|
}
|
|
|
|
// Write SHA to file.
|
|
await writeFile(
|
|
buildInfoPath,
|
|
JSON.stringify(
|
|
{
|
|
branchName: downstreamBranch,
|
|
sha: shaWhenFilesChanged ?? storedSha,
|
|
},
|
|
undefined,
|
|
2,
|
|
),
|
|
);
|
|
|
|
// The below command will show uncommitted changes.
|
|
// This is expected because the framework repo and component/cli might have different minors
|
|
// (e.g. during exceptional minor releases), leading to changes that need to be committed.
|
|
console.log('\nChanges: ');
|
|
execSync(`git status --porcelain`, {stdio: 'inherit'});
|
|
}
|