first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import semver from 'semver';
|
||||
import {
|
||||
getCommitForRef,
|
||||
localRefExists,
|
||||
remoteBranchExists,
|
||||
resolveReleaseTagForTrack,
|
||||
sh,
|
||||
writeGithubOutput,
|
||||
} from './github-helpers.mjs';
|
||||
|
||||
const RELEASE_CANDIDATE_BRANCH_PREFIX = 'release-candidate/';
|
||||
|
||||
/**
|
||||
* @typedef BranchChanges
|
||||
* @property { import('./github-helpers.mjs').TagVersionInfo[] } branchesToEnsure TagVersionInfo for branches the system needs to make sure exist
|
||||
* @property { string[] } branchesToDeprecate Branches the system needs to remove as deprecated
|
||||
* */
|
||||
|
||||
/**
|
||||
* Look into git tags and determine which release candidate branches need to
|
||||
* exist and which need to be deprecated and removed.
|
||||
*
|
||||
* @returns { BranchChanges }
|
||||
* */
|
||||
export function determineBranchChanges() {
|
||||
const branchesToDeprecate = [];
|
||||
|
||||
const currentBetaVersion = resolveReleaseTagForTrack('beta');
|
||||
const currentStableVersion = resolveReleaseTagForTrack('stable');
|
||||
|
||||
if (!currentBetaVersion || !currentStableVersion) {
|
||||
throw new Error(
|
||||
`Could not find current stable and/or beta tags. Beta: ${currentBetaVersion?.tag ?? 'not found'}, Stable: ${currentStableVersion?.tag ?? 'not found'}`,
|
||||
);
|
||||
}
|
||||
|
||||
const branchesToEnsure = [currentBetaVersion, currentStableVersion];
|
||||
|
||||
const stableVersion = currentStableVersion.version;
|
||||
// Deprecated branch is the current stable minus 2 versions. e.g. stable: 2.9.x, deprecated is 2.7.x
|
||||
const deprecatedMinorVersion = semver.minor(stableVersion) - 2;
|
||||
|
||||
if (deprecatedMinorVersion >= 0) {
|
||||
const deprecatedBranch = `${RELEASE_CANDIDATE_BRANCH_PREFIX}${semver.major(stableVersion)}.${deprecatedMinorVersion}.x`;
|
||||
branchesToDeprecate.push(deprecatedBranch);
|
||||
}
|
||||
|
||||
return {
|
||||
branchesToEnsure,
|
||||
branchesToDeprecate,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a TagVersionInfo object and returns a rc-branch name.
|
||||
*
|
||||
* e.g. release-candidate/2.8.x
|
||||
*
|
||||
* @param {import('./github-helpers.mjs').TagVersionInfo} tagVersionInfo
|
||||
*
|
||||
* @returns { `${RELEASE_CANDIDATE_BRANCH_PREFIX}${number}.${number}.x` }
|
||||
* */
|
||||
export function tagVersionInfoToReleaseCandidateBranchName(tagVersionInfo) {
|
||||
const version = tagVersionInfo.version;
|
||||
return `${RELEASE_CANDIDATE_BRANCH_PREFIX}${semver.major(version)}.${semver.minor(version)}.x`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./github-helpers.mjs").TagVersionInfo} tagInfo
|
||||
*/
|
||||
function ensureBranch(tagInfo) {
|
||||
const branch = tagVersionInfoToReleaseCandidateBranchName(tagInfo);
|
||||
|
||||
if (remoteBranchExists(branch)) {
|
||||
console.log(`Branch ${branch} already exists on origin. Skipping.`);
|
||||
return branch;
|
||||
}
|
||||
|
||||
const commitRef = getCommitForRef(tagInfo.tag);
|
||||
|
||||
console.log(`Creating branch ${branch} from ${tagInfo.tag} (${commitRef})`);
|
||||
// Create local branch (force safe: it shouldn't exist, but keep it robust)
|
||||
if (localRefExists(`refs/heads/${branch}`)) {
|
||||
sh('git', ['branch', '-f', branch, commitRef]);
|
||||
} else {
|
||||
sh('git', ['switch', '-c', branch, commitRef]);
|
||||
}
|
||||
|
||||
sh('git', ['push', 'origin', branch]);
|
||||
|
||||
return branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} branch
|
||||
*/
|
||||
function removeBranch(branch) {
|
||||
if (!remoteBranchExists(branch)) {
|
||||
console.log(`Couldn't find branch ${branch}. Skipping removal.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`Removing remote branch ${branch} from origin...`);
|
||||
// Delete remote branch
|
||||
sh('git', ['push', 'origin', '--delete', branch]);
|
||||
|
||||
// Optional local cleanup (keeps reruns tidy)
|
||||
if (localRefExists(`refs/heads/${branch}`)) {
|
||||
console.log(`Removing local branch ${branch}...`);
|
||||
sh('git', ['branch', '-D', branch]);
|
||||
}
|
||||
|
||||
return branch;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const branchChanges = determineBranchChanges();
|
||||
|
||||
console.log('💡 Determined branch changes');
|
||||
console.log('');
|
||||
console.log(
|
||||
` Branches to ensure: ${branchChanges.branchesToEnsure.map(tagVersionInfoToReleaseCandidateBranchName).join(', ')}`,
|
||||
);
|
||||
console.log(` Branches to deprecate: ${branchChanges.branchesToDeprecate.join(', ')}`);
|
||||
console.log('');
|
||||
console.log('Preparing to apply changes...');
|
||||
|
||||
let ensuredBranches = [];
|
||||
for (const tagInfo of branchChanges.branchesToEnsure) {
|
||||
const branch = ensureBranch(tagInfo);
|
||||
ensuredBranches.push(branch);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('Starting deprecation of branches...');
|
||||
|
||||
let removedBranches = [];
|
||||
for (const branch of branchChanges.branchesToDeprecate) {
|
||||
const removedBranch = removeBranch(branch);
|
||||
if (removedBranch) {
|
||||
removedBranches.push(removedBranch);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Done!');
|
||||
|
||||
writeGithubOutput({
|
||||
ensuredBranches: ensuredBranches.join(','),
|
||||
removedBranches: removedBranches.join(','),
|
||||
});
|
||||
}
|
||||
|
||||
// only run when executed directly, not when imported by tests
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
main();
|
||||
}
|
||||
Reference in New Issue
Block a user