From d7ee92f213de15486ec6d40ca0869a62a05c89fa Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 18:32:27 +0000 Subject: [PATCH 1/8] release: improvements: README --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0352fcf..f06c549 100644 --- a/README.md +++ b/README.md @@ -96,10 +96,18 @@ The procedure to issue a release is as follows: * Merge the PR. Docs are auto-published to zrepl.github.io on merge. * Tag the release: * Git tag the release on the `master` branch (e.g., `vMAJOR.MINOR.0`). + ``` + make tag-release ZREPL_TAG_VERSION=v0.7.0 + ``` * Push the tag. * Build and publish: - * Run the `release` pipeline (trigger via CircleCI UI). - * Download artifacts: `make download-circleci-release BUILD_NUM=` + * Run the `release` pipeline against the `master` branch (trigger via CircleCI UI). + This URL: https://app.circleci.com/pipelines/github/zrepl/zrepl?branch=master. + Example pipeline: https://app.circleci.com/pipelines/github/zrepl/zrepl/8547 + * Download artifacts: + ``` + make download-circleci-release BUILD_NUM=8547 + ``` * Create GitHub release and upload artifacts: ```bash gh release create vX.Y.Z --title "vX.Y.Z" --notes "See changelog" --draft From b1ea121d5306132f291013a61e4272ab4f510da5 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 18:32:47 +0000 Subject: [PATCH 2/8] release: artifact download: source from circleci --- .circleci/download_artifacts.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.circleci/download_artifacts.py b/.circleci/download_artifacts.py index 809d9c3..ef4da20 100644 --- a/.circleci/download_artifacts.py +++ b/.circleci/download_artifacts.py @@ -7,13 +7,21 @@ import requests import time import os +import yaml import argparse from pathlib import Path circle_token = os.environ.get('CIRCLE_TOKEN') if not circle_token: - raise ValueError('CIRCLE_TOKEN environment variable not set') + cli_yml = Path.home() / ".circleci" / "cli.yml" + if cli_yml.exists(): + with open(cli_yml) as f: + data = yaml.safe_load(f) + if data: + circle_token = data.get("token") +if not circle_token: + raise ValueError('CIRCLE_TOKEN not set and no token found in ~/.circleci/cli.yml') parser = argparse.ArgumentParser(description='Download artifacts from CircleCI') parser.add_argument('build_num', type=str, help='Build number') From 79118ada70ffb16192c9116f86b7231f0756b641 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 18:48:04 +0000 Subject: [PATCH 3/8] release: details on how to get right number for artifact download script --- Makefile | 2 +- README.md | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2bf3506..c185cc5 100644 --- a/Makefile +++ b/Makefile @@ -222,7 +222,7 @@ clean: docs-clean download-circleci-release: rm -rf "$(ARTIFACTDIR)" mkdir -p "$(ARTIFACTDIR)/release" - python3 .circleci/download_artifacts.py --prefix 'artifacts/release/' "$(BUILD_NUM)" "$(ARTIFACTDIR)/release" + python3 .circleci/download_artifacts.py --prefix 'artifacts/release/' "$(JOB_NUM)" "$(ARTIFACTDIR)/release" ##################### MULTI-ARCH HELPERS ##################### diff --git a/README.md b/README.md index f06c549..b230f0b 100644 --- a/README.md +++ b/README.md @@ -104,9 +104,13 @@ The procedure to issue a release is as follows: * Run the `release` pipeline against the `master` branch (trigger via CircleCI UI). This URL: https://app.circleci.com/pipelines/github/zrepl/zrepl?branch=master. Example pipeline: https://app.circleci.com/pipelines/github/zrepl/zrepl/8547 - * Download artifacts: + * Download artifacts using this handy makefile target. + Note: `JOB_NUM` must be the **job number** from the `release-upload` job, **not the pipeline number**. + Find it via: pipeline → `release` workflow → `release-upload` job number. + Example URL: https://app.circleci.com/pipelines/github/zrepl/zrepl/8547/workflows/65feb2c9-15d7-46ab-a551-46d62a5769b0/jobs/66079/steps + ``` - make download-circleci-release BUILD_NUM=8547 + make download-circleci-release JOB_NUM=66079 ``` * Create GitHub release and upload artifacts: ```bash From efdef1e8b3d6ff3c114b544949c7dbaf9d3508c0 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 18:52:13 +0000 Subject: [PATCH 4/8] add checksum verification and signature step --- Makefile | 5 +++-- README.md | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c185cc5..29e93b9 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ release-docker-mkcachemount: endif ##################### PRODUCING A RELEASE ############# -.PHONY: release wrapup-and-checksum check-git-clean sign clean ensure-release-toolchain +.PHONY: release wrapup-and-checksum check-git-clean verify-and-sign clean ensure-release-toolchain ensure-release-toolchain: # ensure the toolchain is actually the one we expect @@ -211,7 +211,8 @@ tag-release: test -n "$(ZREPL_TAG_VERSION)" || exit 1 git tag -u '328A6627FA98061D!' -m "$(ZREPL_TAG_VERSION)" "$(ZREPL_TAG_VERSION)" -sign: +verify-and-sign: + cd "$(ARTIFACTDIR)/release" && sha512sum -c sha512sum.txt gpg -u '328A6627FA98061D!' \ --armor \ --detach-sign $(ARTIFACTDIR)/release/sha512sum.txt diff --git a/README.md b/README.md index b230f0b..df43b2a 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,10 @@ The procedure to issue a release is as follows: ``` make download-circleci-release JOB_NUM=66079 ``` + * Verify checksums and sign the checksums file: + ``` + make verify-and-sign + ``` * Create GitHub release and upload artifacts: ```bash gh release create vX.Y.Z --title "vX.Y.Z" --notes "See changelog" --draft From 5ea0a4822405e0086a463d36f41e17cc6fcf8e4f Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 19:07:30 +0000 Subject: [PATCH 5/8] add claude command to create github draft release --- .claude/commands/draft-release.md | 74 +++++++++++++++++++++++++++++++ README.md | 6 +-- 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 .claude/commands/draft-release.md diff --git a/.claude/commands/draft-release.md b/.claude/commands/draft-release.md new file mode 100644 index 0000000..d359038 --- /dev/null +++ b/.claude/commands/draft-release.md @@ -0,0 +1,74 @@ +--- +description: Generate GitHub release notes from docs/changelog.rst and create a draft release +argument-hint: +model: sonnet +allowed-tools: Read, Write +--- + +# Task + +Create a draft GitHub release for zrepl version $ARGUMENTS. + +## Inputs + +Here is the current changelog RST source: + +!`cat docs/changelog.rst` + +## Instructions + +1. Extract the changelog section for version $ARGUMENTS from the RST source above. +2. Extract all GitHub usernames mentioned in that changelog section (look for @username patterns or other contributor attributions). +3. Write a short "Highlights" section (2-4 bullets) summarizing the most impactful user-facing changes in plain language. Do NOT include commit/issue links. +4. Write a "Contributors" thank you line for all GitHub users found in step 2. Format as: "Thanks to @user1, @user2, and @user3 for their contributions to this release!" +5. Write a "Breaking Changes" section. Convert RST formatting to plain Markdown text (no commit or issue links): + - `:commit:\`abc123\`` → just remove it or describe what it changed + - `:issue:\`123\`` → just remove it or describe the issue in plain text + - `:ref:\`display text \`` → just use `display text` as plain text + - `:repomasterlink:\`path\`` → just mention the path without a link + - RST inline code ` ``code`` ` → markdown `` `code` `` + - RST links `` `text `_ `` → just use `text` without the link + If there are no breaking changes, write "No breaking changes. vX.Y.Z-1 is interoperable with vX.Y.Z." (fill in actual versions). +6. Assemble the full release notes using the template below. **IMPORTANT**: Do NOT include a detailed changelog list. Only include what is specified in the template. +7. Write the result to `artifacts/release-notes.md`. +8. Validate all links in the release notes by checking HTTP status codes with curl: + - Extract all URLs from the markdown file + - Check each URL with `curl -sI -w "%{http_code}" -o /dev/null ` + - Report any broken links (non-200 status codes) + - If any links are broken, stop and notify the user before creating the release +9. Run: `gh release create $ARGUMENTS --title "$ARGUMENTS" --notes-file artifacts/release-notes.md --draft` +10. Print the release URL. + +## Template + +``` +The full changelog is [on the docs site](https://zrepl.github.io/changelog.html). + +## Highlights + +{2-4 bullet plain-language summary of the most impactful changes} + +{Thank all GitHub users mentioned in the changelog, e.g., "Thanks to @user1, @user2, and @user3 for their contributions to this release!"} + +## Breaking Changes + +{breaking changes, or "No breaking changes."} + +## New Users + +We provide [quick-start guides](https://zrepl.github.io/quickstart.html) for different usage scenarios. +We also recommend studying the [overview section of the configuration chapter](https://zrepl.github.io/configuration/overview.html). + +## Testing & Upgrading + +* Read the [Changelog](https://zrepl.github.io/changelog.html) +* [Run the platform tests](https://zrepl.github.io/usage.html#platform-tests) on a test system. +* Download & deploy the `zrepl` binary / distro package. + +## Donations + +zrepl is a spare-time project primarily developed by [Christian Schwarz](https://cschwarz.com). +Express your support through a donation to keep maintenance and feature development going. + +[![Support me on Patreon](https://img.shields.io/badge/dynamic/json?color=yellow&label=Patreon&query=data.attributes.patron_count&suffix=%20patrons&url=https%3A%2F%2Fwww.patreon.com%2Fapi%2Fcampaigns%2F3095079)](https://patreon.com/zrepl) [![Donate via GitHub Sponsors](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&style=flat&color=yellow)](https://github.com/sponsors/problame) [![Donate via Liberapay](https://img.shields.io/liberapay/patrons/zrepl.svg?logo=liberapay)](https://liberapay.com/zrepl/donate) [![Donate via PayPal](https://img.shields.io/badge/donate-paypal-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=R5QSXJVYHGX96) +``` diff --git a/README.md b/README.md index df43b2a..751c678 100644 --- a/README.md +++ b/README.md @@ -118,10 +118,10 @@ The procedure to issue a release is as follows: ``` * Create GitHub release and upload artifacts: ```bash - gh release create vX.Y.Z --title "vX.Y.Z" --notes "See changelog" --draft - gh release upload vX.Y.Z artifacts/release/* + claude --permission-mode default '/draft-release v0.7.0' + gh release upload v0.7.0 artifacts/release/* ``` - * Review the draft release, edit the changelog, then publish. + * Review the draft release on GitHub, then publish. * Add the .rpm and .deb files to the official zrepl repos. * Code for management of these repos: https://github.com/zrepl/package-repo-ops (private repo at this time) * Update docs version list: From f81f66315a8414e227b37122bf36db13f296853b Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 19:30:07 +0000 Subject: [PATCH 6/8] add `/update-supporters`: claude command to maintain contributor list - Creates new skill to automatically update docs/supporters.rst - Extracts contributors from git history and changelog.rst - Supports time ranges (--since) and commit ranges (v0.6.0..v0.7.0) - Handles new contributors and recurring contributors (moves them up) - Records processed range in RST comment - Integrated into release workflow in README.md Co-Authored-By: Claude Sonnet 4.5 --- .claude/commands/update-supporters.md | 149 ++++++++++++++++++++++++++ README.md | 9 +- docs/supporters.rst | 3 + 3 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 .claude/commands/update-supporters.md diff --git a/.claude/commands/update-supporters.md b/.claude/commands/update-supporters.md new file mode 100644 index 0000000..7632f56 --- /dev/null +++ b/.claude/commands/update-supporters.md @@ -0,0 +1,149 @@ +--- +description: Update supporters list from git history and changelog contributors +argument-hint: +model: sonnet +--- + +# Task + +Automatically update `docs/supporters.rst` by extracting GitHub contributors from: +1. Git commit history (code contributors) +2. `docs/changelog.rst` (all mentioned GitHub users) + +## Arguments + +Specify a time range or release range to filter contributors: + +**Time range examples:** +- `--since="2024-01-01"` - Contributors since a specific date +- `--since="1 year ago"` - Contributors in the last year +- `--since="6 months ago"` - Contributors in the last 6 months + +**Release range examples:** +- `v0.6.0..HEAD` - Contributors between v0.6.0 and current HEAD +- `v0.6.0..v0.7.0` - Contributors between two releases +- `--all` - All contributors (default if no argument provided) + +## Instructions + +### Step 1: Extract Contributors from Git History + +Parse the arguments to determine the git log range: +- If `--since="..."` is provided, use: `git log --since="..." --format='%aN <%aE>' | sort -u` +- If a commit range like `v0.6.0..HEAD` is provided, use: `git log v0.6.0..HEAD --format='%aN <%aE>' | sort -u` +- If `--all` or no argument, use: `git log --format='%aN <%aE>' | sort -u` + +Parse the output to identify: +- GitHub users (look for @users.noreply.github.com emails or known GitHub patterns) +- Real names of code contributors +- Filter out the main maintainer (Christian Schwarz / problame) as they're already credited + +### Step 2: Extract GitHub Users from Changelog + +Read `docs/changelog.rst` and extract all GitHub usernames mentioned: +- Pattern: `` `@username `_ `` +- Pattern: `@username` in text +- Collect all unique usernames + +### Step 3: Categorize Contributors + +For each contributor, determine their tier: + +**Code contributors** (`|supporter-code|`): +- Anyone who appears in git history as a commit author +- Prioritize those with substantial contributions (multiple commits) + +**Other contributors** (keep existing `|supporter-gold|` and `|supporter-std|`): +- Keep all existing gold/std supporters as-is (monetary supporters) +- Only update code contributors + +### Step 4: Read Current Supporters File + +Read `docs/supporters.rst` and parse existing entries to: +- Preserve all `|supporter-gold|` entries (monetary supporters - don't touch these) +- Preserve all `|supporter-std|` entries (monetary supporters - don't touch these) +- Preserve ALL existing `|supporter-code|` entries in their current order +- Extract list of existing code contributor names/GitHub usernames to avoid duplicates + +### Step 5: Identify Contributors to Promote/Add + +**IMPORTANT: Find contributors in the range, and either ADD them (if new) or MOVE them up (if recurring).** + +For each GitHub user found in changelog or git history for the specified range: +1. Check if they're already listed as `|supporter-code|` in the existing file +2. Categorize them: + - **NEW**: Not currently in the file → will be added + - **RECURRING**: Already in the file with new contributions in this range → will be moved to top + - **UNCHANGED**: Not in this range → stays in original position +3. For both NEW and RECURRING contributors: + - Get their latest contribution date from the range: `git log --author="email" --format="%ai" -1` + - Format as: `* |supporter-code| `Name `_` + - Use their real name if available from git history, otherwise use GitHub username +4. Sort NEW + RECURRING contributors together by their contribution date (newest first) +5. Keep list of UNCHANGED contributors in their original order + +**The final order will be: [NEW + RECURRING from range, sorted newest first] + [UNCHANGED in original order]** + +### Step 6: Generate Updated File + +Create the updated supporters list: +- Keep all `|supporter-gold|` entries unchanged and in their exact positions +- Keep all `|supporter-std|` entries unchanged and in their exact positions +- For `|supporter-code|` entries, reorganize as follows: + 1. **Top section**: Contributors from the analyzed range (NEW + RECURRING), sorted newest first + 2. **Bottom section**: UNCHANGED contributors (not in this range), in their original order +- Update the spacer comment showing the range that was just processed: + ```rst + .. + ↓ claude --permission-mode default /update-supporters + ``` + Replace `` with the actual argument passed (e.g., `v0.6.1..v0.7.0`) + This comment should appear immediately before the first code contributor entry + If there's an existing comment in this format, replace it; otherwise add it +- Maintain all other file structure and RST formatting, including the "Before /update-supporters" marker comment + +### Step 7: Apply Changes + +- Use Edit tool to update the `docs/supporters.rst` file +- Display summary of changes made: + - Time/release range analyzed + - Number of contributors found + - New code contributors added + - Final counts by tier + +## Implementation Notes + +- **DO NOT modify, remove, or re-sort** any `|supporter-gold|` or `|supporter-std|` entries +- **For code contributors**: ADD new ones and MOVE UP recurring ones (those with contributions in the analyzed range) +- When extracting from git history, focus on substantial contributors (filter out single-commit or trivial changes if needed) +- **CRITICAL:** Contributors from the analyzed range go to the top + - Use `git log --author="" --format="%ai" -1` to get latest contribution date in the range + - Both NEW and RECURRING contributors from this range are sorted together (newest first) and placed at the TOP + - UNCHANGED contributors (not in this range) stay in their original relative order below + - This creates a chronological history: most recent release's contributors appear first +- Add/update the spacer comment showing the processed range +- Handle edge cases: + - Contributors mentioned in changelog but not in git history (external contributors, reporters) + - Contributors in git history but not mentioned in changelog (decide whether to include) + +## Example Output + +``` +Analyzing contributors for range: v0.6.0..v0.7.0 +- Found 8 code contributors in git history +- Found 12 GitHub users mentioned in changelog.rst (v0.7.0 section) +- Current supporters.rst has 8 gold, 12 std, 10 code contributors + +New contributors: ++ Jane Doe (@janedoe) ++ John Smith (@jsmith) + +Promoted (recurring) contributors: +↑ Alice Developer (@alice) - new contributions in v0.6.0..v0.7.0 + +Updated docs/supporters.rst: +- Gold supporters: 8 (unchanged) +- Std supporters: 12 (unchanged) +- Code contributors: 10 → 12 +- Promoted to top: 3 contributors (2 new + 1 recurring) +``` diff --git a/README.md b/README.md index 751c678..4386b4d 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,11 @@ The procedure to issue a release is as follows: * Prepare the release (as a PR to `master`): * Finalize `docs/changelog.rst` for the release. + * Update the supporters list based on contributors for this release: + ```bash + claude --permission-mode default '/update-supporters v0.6.1..v0.7.0' + ``` + Replace version tags with the appropriate range for your release. * Merge the PR. Docs are auto-published to zrepl.github.io on merge. * Tag the release: * Git tag the release on the `master` branch (e.g., `vMAJOR.MINOR.0`). @@ -116,11 +121,11 @@ The procedure to issue a release is as follows: ``` make verify-and-sign ``` - * Create GitHub release and upload artifacts: + * Create GitHub draft release and upload artifacts: ```bash claude --permission-mode default '/draft-release v0.7.0' - gh release upload v0.7.0 artifacts/release/* ``` + This command will verify that artifacts are ready, create the draft release, and upload all artifacts. * Review the draft release on GitHub, then publish. * Add the .rpm and .deb files to the official zrepl repos. * Code for management of these repos: https://github.com/zrepl/package-repo-ops (private repo at this time) diff --git a/docs/supporters.rst b/docs/supporters.rst index 39781b2..6206beb 100644 --- a/docs/supporters.rst +++ b/docs/supporters.rst @@ -32,6 +32,9 @@ We would like to thank the following people and organizations for supporting zre
+.. + The list below is (roughly) sorted by date of latest contribution, newest first. + * |supporter-gold| `Hostsharing eG – die Hosting-Genossenschaft `_ * |supporter-std| `Max Christian Pohle `_ * |supporter-gold| Prominic.NET, Inc. From 05d4563f00ed0db0c574b310718001a5dfa7b506 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 21:38:25 +0000 Subject: [PATCH 7/8] docs: supporters & changelog: credit all v0.6.1..v0.7.0 contributors Added 11 code contributors from v0.6.1..v0.7.0 to supporters.rst: - Direct committers: @bakhtiyarneyman, @ZeyadTamimi, @findesgh, @Malvineous, @wxiaoguang, @lpulley, @Raupinger, @fermino, @dsh2dsh - Co-authors: @deajan, @alorimer Added missing changelog entries for: - @dsh2dsh: last_n keep rule fix, root_fs fix - @lpulley: Bountysource link removal - @Raupinger: docs newline fix - @fermino: apt repo snippet fix Co-Authored-By: Claude Sonnet 4.5 --- docs/changelog.rst | 5 +++++ docs/supporters.rst | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6a7ef72..b66fdde 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -26,10 +26,15 @@ Changelog * |bugfix| Detect duplicate and internal job names at config parse time. zrepl will now refuse to load a config with duplicate or internally reserved job names, instead of failing later at daemon startup. (:commit:`860a9be`). +* |bugfix| Fix ``last_n`` keep rule behavior (:commit:`ebc46cf`, thanks, `@dsh2dsh `_). +* |bugfix| Allow different jobs to use the same ``root_fs`` for sinks (:commit:`27012e5`, thanks, `@dsh2dsh `_). * |docs| Add installation instructions for openSUSE (:commit:`40c4827`, thanks, `@findesgh `_). * |docs| Improve documentation on ``send_properties`` configuration and NFS/SMB considerations (:commit:`b5d8538`, thanks, `@Malvineous `_). * |docs| Warn more prominently about the risks of the ``not_replicated`` keep rule (:commit:`affe00a`, thanks, `@wxiaoguang `_). * |docs| Improve TLS/EasyRSA setup instructions (:commit:`e524b60`, thanks, `@alorimer `_). +* |docs| Remove dead Bountysource link (:commit:`440b074`, thanks, `@lpulley `_). +* |docs| Fix missing newline in compile-from-source documentation (:commit:`e2fcf9f`, thanks, `@Raupinger `_). +* |docs| Fix apt repository installation snippet (:commit:`8305367`, thanks, `@fermino `_). * |docs| ``zrepl.github.io``: auto-publish from ``master`` branch, retire ``stable`` branch (:commit:`4f950bb`). * |maint| ``zrepl status``: switch from the unmaintained ``cview`` fork back to the actively maintained ``tview`` library (:commit:`d7ede3f`). * |maint| Update to Go 1.25 toolchain with Go 1.24 language level & Go dependencies diff --git a/docs/supporters.rst b/docs/supporters.rst index 6206beb..9bbc352 100644 --- a/docs/supporters.rst +++ b/docs/supporters.rst @@ -35,6 +35,22 @@ We would like to thank the following people and organizations for supporting zre .. The list below is (roughly) sorted by date of latest contribution, newest first. + .. + ↓ claude --permission-mode default /update-supporters v0.6.1..v0.7.0 + +* |supporter-code| `Bakhtiyar Neyman `_ +* |supporter-code| `Zeyad Tamimi `_ +* |supporter-code| `Orsiris de Jong `_ +* |supporter-code| `Martin Glatzle `_ +* |supporter-code| `Andrew Lorimer `_ +* |supporter-code| `Adam Nielsen `_ +* |supporter-code| `wxiaoguang `_ +* |supporter-code| `Logan Pulley `_ +* |supporter-code| `Florian `_ +* |supporter-code| `Fermín Olaiz `_ +* |supporter-code| `Denis Shaposhnikov `_ + .. + ↓ Before /update-supporters * |supporter-gold| `Hostsharing eG – die Hosting-Genossenschaft `_ * |supporter-std| `Max Christian Pohle `_ * |supporter-gold| Prominic.NET, Inc. From d75fe80edb4444e530bee5c282456fda902f0524 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 15 Feb 2026 21:40:19 +0000 Subject: [PATCH 8/8] /draft-release: add artifact upload with pre-flight checks Extends the draft-release command to automatically upload release artifacts after creating the draft release. Adds sanity checks to verify that artifacts have been downloaded and signed before proceeding. Co-Authored-By: Claude Sonnet 4.5 --- .claude/commands/draft-release.md | 45 ++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/.claude/commands/draft-release.md b/.claude/commands/draft-release.md index d359038..3b9a68e 100644 --- a/.claude/commands/draft-release.md +++ b/.claude/commands/draft-release.md @@ -1,5 +1,5 @@ --- -description: Generate GitHub release notes from docs/changelog.rst and create a draft release +description: Generate GitHub release notes from docs/changelog.rst and create a draft release with artifacts argument-hint: model: sonnet allowed-tools: Read, Write @@ -7,7 +7,7 @@ allowed-tools: Read, Write # Task -Create a draft GitHub release for zrepl version $ARGUMENTS. +Create a draft GitHub release for zrepl version $ARGUMENTS and upload release artifacts. ## Inputs @@ -17,11 +17,27 @@ Here is the current changelog RST source: ## Instructions -1. Extract the changelog section for version $ARGUMENTS from the RST source above. -2. Extract all GitHub usernames mentioned in that changelog section (look for @username patterns or other contributor attributions). -3. Write a short "Highlights" section (2-4 bullets) summarizing the most impactful user-facing changes in plain language. Do NOT include commit/issue links. -4. Write a "Contributors" thank you line for all GitHub users found in step 2. Format as: "Thanks to @user1, @user2, and @user3 for their contributions to this release!" -5. Write a "Breaking Changes" section. Convert RST formatting to plain Markdown text (no commit or issue links): +### Phase 1: Pre-flight Sanity Checks + +Before creating the release, verify that the previous build steps have been completed. +Run these checks using bash commands: + +```bash +test -d artifacts/release && echo "✓ artifacts/release directory exists" || echo "✗ Missing artifacts/release directory - run: make download-circleci-release JOB_NUM=" +test -f artifacts/release/sha512sum.txt && echo "✓ sha512sum.txt exists" || echo "✗ Missing sha512sum.txt - run: make download-circleci-release JOB_NUM=" +test -f artifacts/release/sha512sum.txt.asc && echo "✓ sha512sum.txt.asc exists (signed)" || echo "✗ Missing signature - run: make verify-and-sign" +ls artifacts/release/zrepl-* >/dev/null 2>&1 && echo "✓ Release artifacts present" || echo "✗ No release artifacts found" +``` + +If ANY check fails (shows ✗), **STOP** and print the error messages. Do not proceed with release creation. + +### Phase 2: Generate Release Notes + +2. Extract the changelog section for version $ARGUMENTS from the RST source above. +3. Extract all GitHub usernames mentioned in that changelog section (look for @username patterns or other contributor attributions). +4. Write a short "Highlights" section (2-4 bullets) summarizing the most impactful user-facing changes in plain language. Do NOT include commit/issue links. +5. Write a "Contributors" thank you line for all GitHub users found in step 3. Format as: "Thanks to @user1, @user2, and @user3 for their contributions to this release!" +6. Write a "Breaking Changes" section. Convert RST formatting to plain Markdown text (no commit or issue links): - `:commit:\`abc123\`` → just remove it or describe what it changed - `:issue:\`123\`` → just remove it or describe the issue in plain text - `:ref:\`display text \`` → just use `display text` as plain text @@ -29,15 +45,20 @@ Here is the current changelog RST source: - RST inline code ` ``code`` ` → markdown `` `code` `` - RST links `` `text `_ `` → just use `text` without the link If there are no breaking changes, write "No breaking changes. vX.Y.Z-1 is interoperable with vX.Y.Z." (fill in actual versions). -6. Assemble the full release notes using the template below. **IMPORTANT**: Do NOT include a detailed changelog list. Only include what is specified in the template. -7. Write the result to `artifacts/release-notes.md`. -8. Validate all links in the release notes by checking HTTP status codes with curl: +7. Assemble the full release notes using the template below. **IMPORTANT**: Do NOT include a detailed changelog list. Only include what is specified in the template. +8. Write the result to `artifacts/release-notes.md`. +9. Validate all links in the release notes by checking HTTP status codes with curl: - Extract all URLs from the markdown file - Check each URL with `curl -sI -w "%{http_code}" -o /dev/null ` - Report any broken links (non-200 status codes) - If any links are broken, stop and notify the user before creating the release -9. Run: `gh release create $ARGUMENTS --title "$ARGUMENTS" --notes-file artifacts/release-notes.md --draft` -10. Print the release URL. + +### Phase 3: Create Draft Release and Upload Artifacts + +10. Run: `gh release create $ARGUMENTS --title "$ARGUMENTS" --notes-file artifacts/release-notes.md --draft` +11. Upload all artifacts: `gh release upload $ARGUMENTS artifacts/release/*` +12. Verify upload succeeded: `gh release view $ARGUMENTS --json assets --jq '.assets | length'` +13. Print the release URL and confirm that artifacts were uploaded successfully. ## Template