Repository navigation
136 lines (125 loc) · 6.25 KB
/
Copy pathrelease-drafter.yml
File metadata and controls
136 lines (125 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
name: Release Drafter
# Push to main, plus manual dispatch.
#
# It used to also run on pull_request (opened/reopened/synchronize). On a PR
# event release-drafter does nothing but apply autolabels, and no autolabeler
# is configured — so every one of those runs accomplished nothing while
# holding `contents: write` on pull-request-triggered code. They also produced
# the duplicate v0.2.7 drafts sitting in Releases.
on:
push:
branches: [main]
# Manual runs, because the draft's version comes from tags but the trigger
# above comes from commits, and those two move independently.
#
# Tagging is the thing that tells this workflow which version the pending
# release is -- the "Resolve version from tags" step below reads the newest
# tag and uses it directly when it has no published release. But pushing a
# tag triggers nothing here, so the draft kept whatever title it was last
# given until some unrelated commit happened to land on main.
#
# Concretely: with v0.2.6 the last published release, this workflow
# proposes v0.2.7 and keeps regenerating a draft under that name. Tagging
# v0.3.1 makes the resolution correct but does not make it run, so the
# draft went on advertising the wrong version -- holding, by then, ~23,800
# characters of 0.3.1 release notes. Publishing that draft as-is ships
# 0.3.1's notes under a version that does not exist.
#
# The workaround was an empty commit to main: it pollutes history and runs
# the full three-OS CI matrix to correct a release title. This does the
# same job with neither.
workflow_dispatch:
# Only what the draft update needs. `pull-requests: write` went with the
# pull_request trigger; nothing here labels a PR.
permissions:
contents: write
# Shared with publish-release.yml, which holds the same group while it flips
# a draft to public.
#
# The action below rewrites its draft by listing every release, taking the
# first one whose `draft` is true, then PATCHing that release by id -- with
# no re-check in between and a payload that always carries `draft: true`.
# A publish landing in that gap gets overwritten. It happened: run
# 34597984827 wrote to v0.3.1 one second after it went public, and the
# release came back with its tag replaced by an `untagged-...` placeholder.
# Nothing failed and nothing reported it.
#
# `cancel-in-progress: false` matters on both sides. The setting comes from
# the workflow of the run joining the group, so cancelling here would kill an
# in-progress publish and strand a public release with no pipeline started.
# Serialising drafter runs instead costs a few seconds -- they take ~30.
concurrency:
group: release-draft
cancel-in-progress: false
jobs:
update_release_draft:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
# Needed only for the tags; release-drafter itself works over the API.
# `fetch-depth: 0` because a shallow clone carries no tag history.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
fetch-depth: 0
# Resolve the version from tags rather than letting release-drafter
# derive it.
#
# Left to itself it counts forward from the last *published* release
# and applies a label-based bump. This repo tags well before it
# publishes, and no autolabeler is configured, so it read "latest
# release is v0.2.6, default bump is patch" and proposed v0.2.7 --
# while the repo was tagged v0.3.0 and every version file said 0.3.0.
# Publishing that draft would have cut a v0.2.7 release out of 0.3.0
# code. It was deleted twice; it came back both times, because nothing
# about the situation had changed.
#
# Tags know better. If the newest tag has no published release, that
# tag *is* the pending release and the draft should carry its version.
# Only once it has actually shipped does the next draft move on.
- name: Resolve version from tags
id: version
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
latest=$(git tag --list 'v[0-9]*' --sort=-v:refname | head -1)
if [[ -z "$latest" ]]; then
echo "No version tags yet; leaving the version to release-drafter."
echo "version=" >> "$GITHUB_OUTPUT"
exit 0
fi
stripped="${latest#v}"
published=false
if draft=$(gh release view "$latest" --json isDraft --jq '.isDraft' 2>/dev/null); then
# A draft for this tag still means the version has not shipped.
[[ "$draft" == "false" ]] && published=true
fi
if [[ "$published" == "true" ]]; then
IFS='.' read -r major minor patch <<< "$stripped"
version="${major}.${minor}.$((patch + 1))"
echo "$latest is published; next draft is v${version}."
else
version="$stripped"
echo "$latest is tagged but unpublished; the draft is that release."
fi
# The version that actually ships is set by hand across the files
# docs/PUBLISHING.md lists. If the tag and the workspace disagree,
# one of them is wrong and the draft is about to inherit it -- so
# say so here rather than let it pass silently.
workspace=$(grep -m1 '^version = ' crates/netscli-core/Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
if [[ "$version" != "$workspace" ]]; then
echo "::warning::Draft version v${version} does not match the workspace version ${workspace}. One of the tag, the draft, or docs/PUBLISHING.md's file list is out of step."
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
# SHA-pinned like every action in release.yml. `@v7` is a tag the
# upstream owner can move at any time, and this job hands whatever it
# resolves to a `contents: write` token on main.
- uses: release-drafter/release-drafter@34d80673e067bdc0c24568d3af899c216adcfaa9 # v7.7.0
with:
# Empty falls back to release-drafter's own resolution, which is
# the right behaviour for a repo with no tags yet.
version: ${{ steps.version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}