Assign Latest Milestone workflow (Unidata/siphon)
The Assign Latest Milestone workflow from Unidata/siphon, explained and optimized by Latchkey.
A
CI health: A - excellent
Point runs-on at Latchkey and get job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Assign Latest Milestone workflow from the Unidata/siphon repository, a real project running GitHub Actions. It is shown here with attribution under its BSD-3-Clause license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
workflow (.yml)
# If a PR doesn't have a milestone assigned when it's merged, assign it the
# one that's scheduled next.
name: Assign Latest Milestone
on:
pull_request_target:
types: [closed]
branches: [main]
permissions:
pull-requests: write
issues: write
jobs:
sync:
name: Assign Latest Milestone
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
name: Run script
with:
script: |
if (!context.payload.pull_request.merged) {
console.log('PR was not merged, skipping.');
return;
}
if (!!context.payload.pull_request.milestone) {
console.log('PR has existing milestone, skipping.');
return;
}
if (context.payload.pull_request.user.type === 'Bot') {
console.log('Ignoring Bot PR');
return;
}
milestones = await github.rest.issues.listMilestones({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
sort: 'due_on',
direction: 'asc'
})
if (milestones.data.length === 0) {
console.log('There are no milestones, skipping.');
return;
}
console.log(`Adding to milestone: ${milestones.data[0].number}`);
result = await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.number,
milestone: milestones.data[0].number
});
console.log(result);
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
# If a PR doesn't have a milestone assigned when it's merged, assign it the # one that's scheduled next. name: Assign Latest Milestone on: pull_request_target: types: [closed] branches: [main] permissions: pull-requests: write issues: write jobs: sync: timeout-minutes: 30 name: Assign Latest Milestone runs-on: latchkey-small steps: - uses: actions/github-script@v9 name: Run script with: script: | if (!context.payload.pull_request.merged) { console.log('PR was not merged, skipping.'); return; } if (!!context.payload.pull_request.milestone) { console.log('PR has existing milestone, skipping.'); return; } if (context.payload.pull_request.user.type === 'Bot') { console.log('Ignoring Bot PR'); return; } milestones = await github.rest.issues.listMilestones({ owner: context.repo.owner, repo: context.repo.repo, state: 'open', sort: 'due_on', direction: 'asc' }) if (milestones.data.length === 0) { console.log('There are no milestones, skipping.'); return; } console.log(`Adding to milestone: ${milestones.data[0].number}`); result = await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.number, milestone: milestones.data[0].number }); console.log(result);
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.