134 lines
4.1 KiB
JavaScript
134 lines
4.1 KiB
JavaScript
// Helper function to parse semantic version for comparison
|
|
function parseSemanticVersion(version) {
|
|
const versionStr = version.replace(/^v/, "");
|
|
const cleanVersion = versionStr.replace(/rc\d+$/, "");
|
|
const parts = cleanVersion.split(".").map(Number);
|
|
|
|
return {
|
|
major: parts[0] || 0,
|
|
minor: parts[1] || 0,
|
|
micro: parts[2] || 0,
|
|
isRc: versionStr.includes("rc"),
|
|
original: version,
|
|
};
|
|
}
|
|
|
|
// Helper function to compare versions for sorting
|
|
function compareVersions(a, b) {
|
|
const versionA = parseSemanticVersion(a.tag_name);
|
|
const versionB = parseSemanticVersion(b.tag_name);
|
|
|
|
// Compare major.minor.micro in descending order
|
|
if (versionA.major !== versionB.major) {
|
|
return versionB.major - versionA.major;
|
|
}
|
|
if (versionA.minor !== versionB.minor) {
|
|
return versionB.minor - versionA.minor;
|
|
}
|
|
if (versionA.micro !== versionB.micro) {
|
|
return versionB.micro - versionA.micro;
|
|
}
|
|
|
|
// If versions are equal, prefer non-rc over rc
|
|
if (versionA.isRc !== versionB.isRc) {
|
|
return versionA.isRc ? 1 : -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
module.exports = async ({ context, github, core }) => {
|
|
const { owner, repo } = context.repo;
|
|
const { base, number: pull_number } = context.payload.pull_request;
|
|
if (base.ref.match(/^branch-\d+\.\d+$/)) {
|
|
return;
|
|
}
|
|
|
|
const pr = await github.rest.pulls.get({
|
|
owner,
|
|
repo,
|
|
pull_number,
|
|
});
|
|
const { body } = pr.data;
|
|
|
|
// Skip running this check if PR is filed by a bot (except GitHub Copilot)
|
|
if (pr.data.user?.type?.toLowerCase() === "bot" && pr.data.user?.login !== "Copilot") {
|
|
core.info(
|
|
`Skipping processing because the PR is filed by a bot: ${pr.data.user?.login || "unknown"}`
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Skip running this check on CD automation PRs
|
|
if (!body || body.trim() === "") {
|
|
core.info("Skipping processing because the PR has no body.");
|
|
return;
|
|
}
|
|
|
|
// TODO: remove the "yes/no" alternatives once all open PRs have switched to the new template
|
|
const yesRegex = /- \[( |x)\] (yes \()?this PR (will be|is critical)/gi;
|
|
const yesMatches = [...body.matchAll(yesRegex)];
|
|
const yesMatch = yesMatches.length > 0 ? yesMatches[yesMatches.length - 1] : null;
|
|
const yes = yesMatch ? yesMatch[1].toLowerCase() === "x" : false;
|
|
// TODO: remove the "yes/no" alternatives once all open PRs have switched to the new template
|
|
const noRegex = /- \[( |x)\] (no \()?this PR (will be|can wait)/gi;
|
|
const noMatches = [...body.matchAll(noRegex)];
|
|
const noMatch = noMatches.length > 0 ? noMatches[noMatches.length - 1] : null;
|
|
const no = noMatch ? noMatch[1].toLowerCase() === "x" : false;
|
|
|
|
if (yes && no) {
|
|
core.setFailed(
|
|
"Both yes and no are selected. Please select only one in the patch release section."
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!yes && !no) {
|
|
core.setFailed("Please fill in the patch release section.");
|
|
return;
|
|
}
|
|
|
|
if (no) {
|
|
return;
|
|
}
|
|
|
|
// Check if a version label already exists
|
|
const existingLabels = await github.rest.issues.listLabelsOnIssue({
|
|
owner,
|
|
repo,
|
|
issue_number: context.payload.pull_request.number,
|
|
});
|
|
|
|
const versionLabelPattern = /^v\d+\.\d+\.\d+$/;
|
|
const existingVersionLabel = existingLabels.data.find((label) =>
|
|
versionLabelPattern.test(label.name)
|
|
);
|
|
|
|
if (existingVersionLabel) {
|
|
core.info(
|
|
`Version label ${existingVersionLabel.name} already exists on this PR. Skipping label addition.`
|
|
);
|
|
return;
|
|
}
|
|
|
|
const releases = await github.rest.repos.listReleases({
|
|
owner,
|
|
repo,
|
|
});
|
|
|
|
// Filter version tags that start with 'v', sort by semantic version, and select the latest
|
|
const versionReleases = releases.data.filter(({ tag_name }) => tag_name.startsWith("v"));
|
|
const sortedReleases = versionReleases.sort(compareVersions);
|
|
const latest = sortedReleases[0];
|
|
const version = latest.tag_name.replace("v", "");
|
|
const [major, minor, micro] = version.replace(/rc\d+$/, "").split(".");
|
|
const nextMicro = version.includes("rc") ? micro : (parseInt(micro) + 1).toString();
|
|
const label = `v${major}.${minor}.${nextMicro}`;
|
|
await github.rest.issues.addLabels({
|
|
owner,
|
|
repo,
|
|
issue_number: context.payload.pull_request.number,
|
|
labels: [label],
|
|
});
|
|
};
|