Skip to content

Commit baf7f6c

Browse files
authored
ci: group releases instead of publishing on every merge (#263)
- Draft updates on every push to main (no auto-publish) - Publish immediately when a significant PR (feature/fix/security/breaking) merges - Publish on biweekly schedule (1st and 15th) if unreleased changes exist - Publish on manual workflow_dispatch (always) - Add security label to release-drafter config
1 parent ff536ec commit baf7f6c

2 files changed

Lines changed: 69 additions & 3 deletions

File tree

.github/release-drafter.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ version-resolver:
1616
- 'bugfix'
1717
- 'bug'
1818
- 'chore'
19+
- 'security'
1920
default: patch
2021
categories:
2122
- title: '💥 Breaking Changes'
@@ -29,6 +30,12 @@ categories:
2930
exclude-labels:
3031
- 'breaking'
3132
- 'breaking-change'
33+
- title: '🔒 Security'
34+
labels:
35+
- 'security'
36+
exclude-labels:
37+
- 'breaking'
38+
- 'breaking-change'
3239
- title: '🐛 Bug Fixes'
3340
labels:
3441
- 'fix'

.github/workflows/release-drafter.yml

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ on:
1111
# pull_request_target event is required for autolabeler to support PRs from forks
1212
# pull_request_target:
1313
# types: [opened, reopened, synchronize]
14+
workflow_dispatch:
15+
schedule:
16+
- cron: '0 9 1,15 * *' # 1st and 15th of each month (~every 2 weeks)
1417

1518
permissions:
1619
contents: read
@@ -25,12 +28,68 @@ jobs:
2528
pull-requests: write
2629
runs-on: ubuntu-latest
2730
steps:
28-
# Updates draft release notes when PRs are opened/updated against main
29-
# Publishes the release on push to main (including merged PRs)
31+
# On push to main, check whether the merged PR carries a significant label.
32+
# Chore-only merges (e.g. Renovate dependency bumps) update the draft but
33+
# do not trigger an immediate release.
34+
- name: Check merged PR significance
35+
id: pr-check
36+
if: github.event_name == 'push'
37+
uses: actions/github-script@v7
38+
with:
39+
script: |
40+
const prs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
41+
owner: context.repo.owner,
42+
repo: context.repo.repo,
43+
commit_sha: context.sha,
44+
});
45+
if (prs.data.length === 0) {
46+
core.setOutput('publish', 'false');
47+
return;
48+
}
49+
const labels = prs.data[0].labels.map(l => l.name);
50+
const significant = ['feature', 'enhancement', 'fix', 'bugfix', 'bug', 'security', 'breaking', 'breaking-change'];
51+
core.setOutput('publish', labels.some(l => significant.includes(l)) ? 'true' : 'false');
52+
53+
# On the scheduled run, skip publishing if nothing has merged since the last release.
54+
# This avoids creating an empty or chore-only release when there has been no activity.
55+
# workflow_dispatch bypasses this check intentionally — a manual trigger always publishes.
56+
- name: Check for unreleased changes (schedule only)
57+
id: schedule-check
58+
if: github.event_name == 'schedule'
59+
uses: actions/github-script@v7
60+
with:
61+
script: |
62+
const releases = await github.rest.repos.listReleases({
63+
owner: context.repo.owner,
64+
repo: context.repo.repo,
65+
per_page: 10,
66+
});
67+
const latest = releases.data.find(r => !r.draft && !r.prerelease);
68+
const since = latest ? latest.published_at : null;
69+
70+
const prs = await github.rest.pulls.list({
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
state: 'closed',
74+
base: 'main',
75+
sort: 'updated',
76+
direction: 'desc',
77+
per_page: 100,
78+
});
79+
const merged = prs.data.filter(pr =>
80+
pr.merged_at && (!since || new Date(pr.merged_at) > new Date(since))
81+
);
82+
core.setOutput('has_changes', merged.length > 0 ? 'true' : 'false');
83+
84+
# Updates draft release notes when PRs are opened/updated against main.
85+
# Publishes when:
86+
# - triggered manually (workflow_dispatch)
87+
# - the biweekly schedule fires AND there are unreleased merged PRs
88+
# - a significant (non-chore) PR was merged to main
3089
- uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7
3190
with:
3291
commitish: main
33-
publish: ${{ github.event_name == 'push' }}
92+
publish: ${{ github.event_name == 'workflow_dispatch' || steps.pr-check.outputs.publish == 'true' || steps.schedule-check.outputs.has_changes == 'true' }}
3493
prerelease: false
3594
env:
3695
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

0 commit comments

Comments
 (0)