Skip to content

Commit 48b6e46

Browse files
Fold GitHub release steps into deploy.sh
Add release-draft, release-cut, and release-abort subcommands so the release lifecycle (draft the GitHub release, publish it, delete the draft on failure) lives in the same single source of truth as the cache and Docker deploy steps. The Release workflow's draft-release, cut-release, and failure-cleanup steps now call these subcommands instead of inlining gh, and the CONTRIBUTING.md runbook uses them too. The runbook also now states that a manual release must be built from a commit on main, since kup resolves komet-node versions against main.
1 parent a73ee7b commit 48b6e46

3 files changed

Lines changed: 79 additions & 52 deletions

File tree

.github/workflows/release.yml

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,14 @@ jobs:
1212
steps:
1313
- name: 'Check out code'
1414
uses: actions/checkout@v4
15-
- name: 'Make release'
16-
id: 'make-release'
15+
# Drafting logic lives in scripts/deploy.sh so CI and manual releases stay
16+
# in sync (single source of truth). See CONTRIBUTING.md.
17+
- name: 'Draft the release'
1718
env:
1819
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19-
run: |
20-
set -x
21-
VERSION=v$(cat package/version)
22-
gh release create "${VERSION}" \
23-
--repo "${GITHUB_REPOSITORY}" \
24-
--draft \
25-
--title "${VERSION}" \
26-
--target ${{ github.sha }}
27-
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
20+
OWNER_REPO: '${{ github.repository }}'
21+
REV: '${{ github.sha }}'
22+
run: ./scripts/deploy.sh release-draft
2823

2924
nix-cache:
3025
name: 'Populate Nix Caches'
@@ -55,13 +50,8 @@ jobs:
5550
if: failure()
5651
env:
5752
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58-
run: |
59-
set -x
60-
VERSION=v$(cat package/version)
61-
gh release delete "${VERSION}" \
62-
--repo "${GITHUB_REPOSITORY}" \
63-
--yes \
64-
--cleanup-tag || true
53+
OWNER_REPO: '${{ github.repository }}'
54+
run: ./scripts/deploy.sh release-abort
6555

6656
dockerhub:
6757
name: 'Build and Publish Docker Image'
@@ -85,13 +75,8 @@ jobs:
8575
if: failure()
8676
env:
8777
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
88-
run: |
89-
set -x
90-
VERSION=v$(cat package/version)
91-
gh release delete "${VERSION}" \
92-
--repo "${GITHUB_REPOSITORY}" \
93-
--yes \
94-
--cleanup-tag || true
78+
OWNER_REPO: '${{ github.repository }}'
79+
run: ./scripts/deploy.sh release-abort
9580

9681
cut-release:
9782
name: 'Cut Release'
@@ -104,12 +89,10 @@ jobs:
10489
ref: ${{ github.sha }}
10590
fetch-depth: 0
10691

92+
# Finalizing logic lives in scripts/deploy.sh so CI and manual releases
93+
# stay in sync (single source of truth). See CONTRIBUTING.md.
10794
- name: 'Finalize Release'
10895
env:
10996
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
110-
run: |
111-
set -x
112-
VERSION=v$(cat package/version)
113-
gh release edit "${VERSION}" \
114-
--repo "${GITHUB_REPOSITORY}" \
115-
--draft=false
97+
OWNER_REPO: '${{ github.repository }}'
98+
run: ./scripts/deploy.sh release-cut

CONTRIBUTING.md

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,14 @@ where `<version>` comes from `package/version`.
7979

8080
### Prerequisites
8181

82-
Both subcommands run from a checkout of the revision you are releasing, with the
82+
The subcommands run from a checkout of the revision you are releasing, with the
8383
following tools on `PATH`:
8484

8585
- `nix-cache` needs `nix` and `cachix`. It fetches `kup` from
8686
`github:runtimeverification/kup` itself, so you do not install kup separately.
8787
- `docker` needs `docker`.
88+
- `release-draft`, `release-cut`, and `release-abort` need `gh`, authenticated
89+
via `gh auth login` or a `GH_TOKEN`/`GITHUB_TOKEN` in the environment.
8890

8991
Each subcommand checks its tools up front and exits with a clear message if one
9092
is missing, before starting the build.
@@ -102,14 +104,16 @@ further setup.
102104
| ----------- | ------------------------------ |
103105
| `nix-cache` | `CACHIX_PUBLIC_TOKEN`, `CACHIX_PRIVATE_KFB_TOKEN` |
104106
| `docker` | `DOCKERHUB_PASSWORD` |
107+
| `release-*` | none — `gh` supplies its own authentication |
105108

106109
`OWNER_REPO` and `REV` default to the current checkout's `origin` remote and
107110
`HEAD`. Override them if you are publishing a revision other than the one checked
108111
out. `DOCKERHUB_USERNAME`, `DOCKERHUB_NAMESPACE`, and `DOCKERHUB_REPO` default to
109112
the release account and repository; override them only to publish elsewhere.
110113

111-
Both subcommands refuse to run if the working tree is not clean. CI builds from a
112-
fresh checkout, so a manual build must too: uncommitted changes and untracked
114+
The `nix-cache` and `docker` subcommands refuse to run if the working tree is not
115+
clean. CI builds from a fresh checkout, so a manual build must too: uncommitted
116+
changes and untracked
113117
files would otherwise be baked into the published image or flake build without
114118
matching the `REV` they are published under. Commit, stash, or clean the tree
115119
first. `git status --porcelain` ignores `.gitignore`d paths, so runtime artifacts
@@ -118,26 +122,27 @@ deliberately want to publish an uncommitted state.
118122

119123
### Manual release while CI is down
120124

121-
The workflow also drafts, cleans up, and finalizes the GitHub release around the
122-
deployment jobs. When you deploy by hand, run those `gh` steps yourself in this
123-
order. `nix-cache` runs once per architecture (the workflow uses an `x86_64` and
124-
an `ARM64` runner), so run it on a machine of each architecture that should be
125+
`deploy.sh` wraps the GitHub-release steps too, so a manual release runs the same
126+
subcommands the workflow does, in the same order. Run them from a checkout of the
127+
`main` commit you are releasing: `release-draft` targets `REV` (the current
128+
`HEAD` by default), and kup resolves komet-node versions against `main`, so a
129+
release built from an unmerged commit will not be installable with `kup`.
130+
`nix-cache` runs once per architecture (the workflow uses an `x86_64` and an
131+
`ARM64` runner), so run it on a machine of each architecture that should be
125132
cached.
126133

127134
```sh
128-
VERSION=v$(cat package/version)
129-
130135
# 1. Draft the release.
131-
gh release create "$VERSION" --draft --title "$VERSION" --target "$(git rev-parse HEAD)"
136+
./scripts/deploy.sh release-draft
132137

133138
# 2. Deploy. Export the secrets first (see the table above).
134139
# Run nix-cache once per architecture; docker once.
135140
./scripts/deploy.sh nix-cache
136141
./scripts/deploy.sh docker
137142

138143
# 3. Finalize the release once every deployment has succeeded.
139-
gh release edit "$VERSION" --draft=false
144+
./scripts/deploy.sh release-cut
140145

141146
# If a deployment fails, remove the draft instead:
142-
# gh release delete "$VERSION" --yes --cleanup-tag
147+
# ./scripts/deploy.sh release-abort
143148
```

scripts/deploy.sh

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ set -euo pipefail
1313
# unavailable. See CONTRIBUTING.md ("Deploying a release") for the runbook.
1414
#
1515
# Subcommands:
16-
# nix-cache Build komet-node and push it to both Nix caches (the
17-
# k-framework closure + the k-framework-binary kup binary).
18-
# docker Build the Docker image, smoke-test it, and push to Docker Hub.
19-
# all Run nix-cache then docker.
16+
# nix-cache Build komet-node and push it to both Nix caches (the
17+
# k-framework closure + the k-framework-binary kup binary).
18+
# docker Build the Docker image, smoke-test it, and push to Docker Hub.
19+
# all Run nix-cache then docker.
20+
# release-draft Create the draft GitHub release for this version and revision.
21+
# release-cut Publish (un-draft) the release once its artifacts are up.
22+
# release-abort Delete the draft release and its tag (failure cleanup).
2023
#
2124
# Usage:
22-
# scripts/deploy.sh <nix-cache|docker|all>
25+
# scripts/deploy.sh <nix-cache|docker|all|release-draft|release-cut|release-abort>
2326

2427
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
2528
cd "${REPO_ROOT}"
@@ -156,15 +159,51 @@ deploy_docker() {
156159
docker image push "${tag}"
157160
}
158161
162+
# --- release lifecycle -----------------------------------------------------
163+
# The GitHub release is drafted before the artifacts are published and finalized
164+
# after, so it only becomes visible once its Docker image and cache pins exist.
165+
# These wrap the `gh` calls the Release workflow makes, keeping the release
166+
# lifecycle in the same single source of truth as the deploy steps. `gh`
167+
# authenticates via its own login or GH_TOKEN/GITHUB_TOKEN; no secret is read
168+
# here directly. The release is drafted against REV, which must be the commit you
169+
# deployed -- and, for a real release, a commit on `main`, since kup resolves
170+
# komet-node versions against `main`.
171+
release_tag() { echo "v${KOMET_NODE_VERSION}"; }
172+
173+
deploy_release_draft() {
174+
require_cmd gh git
175+
local tag; tag="$(release_tag)"
176+
echo ":: drafting release ${tag} targeting ${REV}"
177+
gh release create "${tag}" --repo "${OWNER_REPO}" --draft --title "${tag}" --target "${REV}"
178+
}
179+
180+
deploy_release_cut() {
181+
require_cmd gh git
182+
local tag; tag="$(release_tag)"
183+
echo ":: publishing release ${tag}"
184+
gh release edit "${tag}" --repo "${OWNER_REPO}" --draft=false
185+
}
186+
187+
deploy_release_abort() {
188+
require_cmd gh git
189+
local tag; tag="$(release_tag)"
190+
echo ":: deleting drafted release ${tag}"
191+
# Best-effort: the cleanup path must never fail on its own account.
192+
gh release delete "${tag}" --repo "${OWNER_REPO}" --yes --cleanup-tag || true
193+
}
194+
159195
usage() {
160-
sed -n '8,22p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
196+
sed -n '8,25p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
161197
}
162198
163199
main() {
164200
case "${1:-}" in
165-
nix-cache) deploy_nix_cache ;;
166-
docker) deploy_docker ;;
167-
all) deploy_nix_cache; deploy_docker ;;
201+
nix-cache) deploy_nix_cache ;;
202+
docker) deploy_docker ;;
203+
all) deploy_nix_cache; deploy_docker ;;
204+
release-draft) deploy_release_draft ;;
205+
release-cut) deploy_release_cut ;;
206+
release-abort) deploy_release_abort ;;
168207
-h | --help | help | "")
169208
usage
170209
[ -n "${1:-}" ] # exit non-zero when no subcommand was given

0 commit comments

Comments
 (0)