Files
slsDetectorPackage/.github/workflows/pr_milestone.yaml
T
maliakal_d dba175e986
Build on RHEL9 docker image / build (push) Successful in 3m33s
Build on RHEL8 docker image / build (push) Successful in 4m41s
Run Simulator Tests on local RHEL9 / build (push) Failing after 9m9s
Run Simulator Tests on local RHEL8 / build (push) Successful in 22m20s
added pr automation workflows from developer (#1568)
2026-09-21 14:15:48 +02:00

249 lines
7.8 KiB
YAML

# This reusable workflow sets the milestone based on the
# current PR labels.
name: PR Milestone
on:
workflow_call:
inputs:
pr_number:
required: true
type: number
permissions:
pull-requests: write
contents: read
jobs:
set-milestone:
name: Set PR milestone
runs-on: ubuntu-latest
steps:
- name: Determine target milestone
id: determine-milestone
uses: actions/github-script@v8
with:
script: |
const prNumber = ${{ inputs.pr_number }};
/*
* Get the base branch of the PR.
*/
const { data: pullRequest } =
await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const baseBranch = pullRequest.base.ref;
/*
* 1. Return early if base is main branch. Milestone is already
* managed and probably done when merging to main.
*/
if (baseBranch === 'main') {
core.info('PR targets main. Milestone is managed separately.');
core.setOutput('target_milestone', '');
return;
}
/*
* Helper function to set the target milestone output.
*/
const setTargetMilestoneOutput = (targetMilestone) => {
core.info(`Target milestone: ${targetMilestone}`);
core.setOutput('target_milestone', targetMilestone);
};
/*
* 2. If PR targets a release-candidate branch (for example 9.1.0.rc),
* set milestone to the release version prefix (for example 9.1.0)
* and return early.
*/
if (baseBranch.endsWith('.rc')) {
const targetMilestone = baseBranch.replace(/\.rc$/, '');
core.info(
`PR targets release-candidate branch "${baseBranch}". ` +
`Using milestone "${targetMilestone}".`
);
setTargetMilestoneOutput(targetMilestone);
return;
}
/**
* 3. If PR targets a branch that is not developer, do nothing.
*/
if (baseBranch !== 'developer') {
core.info('PR does not target developer branch. Skipping milestone management.');
core.setOutput('target_milestone', '');
return;
}
/*
* 4. If PR targets developer, check "Equivalent PRs" in the PR body.
* If an equivalent PR targets an RC branch (for example 9.1.0.rc),
* use the corresponding release milestone (for example 9.1.0).
*/
if (baseBranch === 'developer') {
const equivalentPrSectionMatch = pullRequest.body?.match(
/(^|\n)#{1,6}\s*Equivalent PRs\s*\n([\s\S]*?)(?=\n#{1,6}\s+\S|\s*$)/i
);
const equivalentPrNumbers =
equivalentPrSectionMatch?.[2]
? Array.from(
equivalentPrSectionMatch[2].matchAll(/#(\d+)/g),
match => Number(match[1])
)
: [];
for (const equivalentPrNumber of equivalentPrNumbers) {
if (equivalentPrNumber === prNumber) {
continue;
}
const { data: equivalentPr } =
await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: equivalentPrNumber
});
const equivalentBaseBranch = equivalentPr.base.ref;
if (!equivalentBaseBranch.endsWith('.rc')) {
continue;
}
const targetMilestone =
equivalentBaseBranch.replace(/\.rc$/, '');
core.info(
`Developer PR references RC PR #${equivalentPrNumber} ` +
`(${equivalentBaseBranch}). Using milestone "${targetMilestone}".`
);
setTargetMilestoneOutput(targetMilestone);
return;
}
}
/*
* 5. Read release targets through the GitHub API
* from the base branch of PR.
*/
const { data: file } =
await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: '.github/release-targets.yaml',
ref: baseBranch
});
const releaseTargetsFile =
Buffer.from(file.content, 'base64').toString('utf8');
const getTarget = (name) => {
const match = releaseTargetsFile.match(
new RegExp(`^${name}:\\s*["']?([^"'\\s]+)["']?`, 'm')
);
if (!match) {
core.setFailed(
`Release target "${name}" was not found.`
);
return null;
}
return match[1];
};
const major = getTarget('major');
const minor = getTarget('minor');
const bugFix = getTarget('bug_fix');
if (!major || !minor || !bugFix) {
core.setFailed(
'Required release targets (major, minor, bug_fix) could not be resolved from yaml file.'
);
return;
}
/*
* Get current PR labels.
*/
const { data: labels } =
await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const labelNames =
labels.map(label => label.name);
/*
* Determine the milestone.
*
* Breaking API has highest priority.
*/
let targetMilestone;
if (labelNames.includes('Breaking API')) {
targetMilestone = major;
} else if (labelNames.includes('Feature')) {
targetMilestone = minor;
} else if (
labelNames.includes('Bug Fix') ||
labelNames.includes('Infrastructure')
) {
targetMilestone = bugFix;
} else {
core.setFailed(
'No milestone-related labels found.'
);
return;
}
setTargetMilestoneOutput(targetMilestone);
- name: Set milestone
if: steps.determine-milestone.outputs.target_milestone != ''
uses: actions/github-script@v8
with:
script: |
const prNumber = ${{ inputs.pr_number }};
const targetMilestone = '${{ steps.determine-milestone.outputs.target_milestone }}';
const { data: milestones } =
await github.rest.issues.listMilestones({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open'
});
const milestone = milestones.find(
milestone => milestone.title === targetMilestone
);
if (!milestone) {
core.setFailed(
`Milestone "${targetMilestone}" was not found.`
);
return;
}
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
milestone: milestone.number
});
core.info(
`Milestone set to "${targetMilestone}".`
);