Skip to content

Commit f590a69

Browse files
Merge pull request #50 from runtimeverification/deploy-release-lifecycle
Fold GitHub release steps into deploy.sh
2 parents a73ee7b + 48b6e46 commit f590a69

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)