Compare commits

...

10 Commits

Author SHA1 Message Date
Christian Schwarz c9b282bc66 draft for user delegation setups; https://github.com/zrepl/zrepl/discussions/926 2026-02-15 23:04:53 +00:00
Christian Schwarz 2c780b4d4e Merge pull request #927 from zrepl/post-v0.7.0-docs-and-automation
post-v0.7.0 docs changes & release automation
2026-02-15 23:17:51 +01:00
Christian Schwarz d75fe80edb /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 <noreply@anthropic.com>
2026-02-15 22:13:44 +00:00
Christian Schwarz 05d4563f00 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 <noreply@anthropic.com>
2026-02-15 22:13:44 +00:00
Christian Schwarz f81f66315a 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 <noreply@anthropic.com>
2026-02-15 22:13:17 +00:00
Christian Schwarz 5ea0a48224 add claude command to create github draft release 2026-02-15 22:13:17 +00:00
Christian Schwarz efdef1e8b3 add checksum verification and signature step 2026-02-15 22:13:17 +00:00
Christian Schwarz 79118ada70 release: details on how to get right number for artifact download script 2026-02-15 22:13:17 +00:00
Christian Schwarz b1ea121d53 release: artifact download: source from circleci 2026-02-15 22:13:17 +00:00
Christian Schwarz d7ee92f213 release: improvements: README 2026-02-15 22:13:17 +00:00
8 changed files with 360 additions and 16 deletions
+9 -1
View File
@@ -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')
+95
View File
@@ -0,0 +1,95 @@
---
description: Generate GitHub release notes from docs/changelog.rst and create a draft release with artifacts
argument-hint: <version-tag, e.g. v0.7.0>
model: sonnet
allowed-tools: Read, Write
---
# Task
Create a draft GitHub release for zrepl version $ARGUMENTS and upload release artifacts.
## Inputs
Here is the current changelog RST source:
!`cat docs/changelog.rst`
## Instructions
### 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=<num>"
test -f artifacts/release/sha512sum.txt && echo "✓ sha512sum.txt exists" || echo "✗ Missing sha512sum.txt - run: make download-circleci-release JOB_NUM=<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 <anchor>\`` → 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 <url>`_ `` → 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).
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 <url>`
- Report any broken links (non-200 status codes)
- If any links are broken, stop and notify the user before creating the release
### 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
```
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)
```
+149
View File
@@ -0,0 +1,149 @@
---
description: Update supporters list from git history and changelog contributors
argument-hint: <time-range-or-release>
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 <https://github.com/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 <range> --author="email" --format="%ai" -1`
- Format as: `* |supporter-code| `Name <https://github.com/username>`_`
- 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 <actual-range-used>
```
Replace `<actual-range-used>` 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 <range> --author="<email>" --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)
```
+4 -3
View File
@@ -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
@@ -222,7 +223,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 #####################
+28 -7
View File
@@ -93,19 +93,40 @@ 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`).
```
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=<circleci-build-number>`
* 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/*
* 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 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
```
* Review the draft release, edit the changelog, then publish.
make download-circleci-release JOB_NUM=66079
```
* Verify checksums and sign the checksums file:
```
make verify-and-sign
```
* Create GitHub draft release and upload artifacts:
```bash
claude --permission-mode default '/draft-release v0.7.0'
```
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)
* Update docs version list:
+5
View File
@@ -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 <https://github.com/dsh2dsh>`_).
* |bugfix| Allow different jobs to use the same ``root_fs`` for sinks (:commit:`27012e5`, thanks, `@dsh2dsh <https://github.com/dsh2dsh>`_).
* |docs| Add installation instructions for openSUSE (:commit:`40c4827`, thanks, `@findesgh <https://github.com/findesgh>`_).
* |docs| Improve documentation on ``send_properties`` configuration and NFS/SMB considerations (:commit:`b5d8538`, thanks, `@Malvineous <https://github.com/Malvineous>`_).
* |docs| Warn more prominently about the risks of the ``not_replicated`` keep rule (:commit:`affe00a`, thanks, `@wxiaoguang <https://github.com/wxiaoguang>`_).
* |docs| Improve TLS/EasyRSA setup instructions (:commit:`e524b60`, thanks, `@alorimer <https://github.com/alorimer>`_).
* |docs| Remove dead Bountysource link (:commit:`440b074`, thanks, `@lpulley <https://github.com/lpulley>`_).
* |docs| Fix missing newline in compile-from-source documentation (:commit:`e2fcf9f`, thanks, `@Raupinger <https://github.com/Raupinger>`_).
* |docs| Fix apt repository installation snippet (:commit:`8305367`, thanks, `@fermino <https://github.com/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
+51 -5
View File
@@ -3,10 +3,56 @@
User Privileges
---------------
It is possible to run zrepl as an unprivileged user in combination with
`ZFS delegation <https://www.freebsd.org/doc/handbook/zfs-zfs-allow.html>`_.
Also, there is the possibility to run it in a jail on FreeBSD by delegating a dataset to the jail.
zrepl can run as an unprivileged user with `ZFS delegation <https://www.freebsd.org/doc/handbook/zfs-zfs-allow.html>`_.
**Help us document working setups on this page** by opening a PR!
.. TIP::
.. NOTE::
Note: check out the :ref:`installation-freebsd-jail-with-iocage` for FreeBSD jail setup instructions.
Keep in mind that ``zfs send``/``recv`` was never designed with
untrusted input in mind. An attacker controlling the send-recv stream could probably crash the
receive-side kernel, exploit bugs to get code execution, or induce stateful damage to the receive-side pool.
Known Working Setups
^^^^^^^^^^^^^^^^^^^^
.. list-table::
:header-rows: 1
:widths: 15 40 20
* - OS
- Use Case
- Last Tested Version
* - Linux
- sink job (receiving)
- v0.7.0
.. _installation-user-privileges-my-example-setup:
My Example Setup
^^^^^^^^^^^^^^^^
I'm on Linux (Ubuntu ...) and run ``zrepl daemon`` as an unprivileged user, using a custom systemd unit file.
:: code-block:: bash
...
[Service]
User=zrepl
Group=zrepl
...
I set up the ZFS persmissions as follows:
.. code-block:: bash
# receiving side root filesystem
zfs allow -u zrepl bookmark,create,destroy,hold,mount,mountpoint,receive,refreservation,userprop backuppool/zrepl
# sending side
zfs allow -u zrepl bookmark,destroy,hold,send,userprop prodpool
**Notes:**
* ``snapshot`` is NOT needed for receiving (only for pruning operations)
* ``refreservation`` avoids non-sparse volume issues on receiving side
* Add ``snapshot`` if your jobs perform sender or receiver-side pruning
* Encryption and other features may require additional permissions
+19
View File
@@ -32,6 +32,25 @@ We would like to thank the following people and organizations for supporting zre
<div class="fa fa-code" style="width: 1em;"></div>
..
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 <https://github.com/bakhtiyarneyman>`_
* |supporter-code| `Zeyad Tamimi <https://github.com/ZeyadTamimi>`_
* |supporter-code| `Orsiris de Jong <https://github.com/deajan>`_
* |supporter-code| `Martin Glatzle <https://github.com/findesgh>`_
* |supporter-code| `Andrew Lorimer <https://github.com/alorimer>`_
* |supporter-code| `Adam Nielsen <https://github.com/Malvineous>`_
* |supporter-code| `wxiaoguang <https://github.com/wxiaoguang>`_
* |supporter-code| `Logan Pulley <https://github.com/lpulley>`_
* |supporter-code| `Florian <https://github.com/Raupinger>`_
* |supporter-code| `Fermín Olaiz <https://github.com/fermino>`_
* |supporter-code| `Denis Shaposhnikov <https://github.com/dsh2dsh>`_
..
↓ Before /update-supporters
* |supporter-gold| `Hostsharing eG die Hosting-Genossenschaft <https://www.hostsharing.net/>`_
* |supporter-std| `Max Christian Pohle <https://coderonline.de>`_
* |supporter-gold| Prominic.NET, Inc.