Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ Each release crate (`payjoin`, `payjoin-cli`, `payjoin-mailroom`) and `payjoin-f

If the change has no user-visible effect (refactoring, tests, CI, comments), say so in the pull request description and a maintainer will apply the `changelog: none` label. CI fails a pull request that touches one of those crates' `src/` without either a changelog line or that label.

### Deprecations

Mark a deprecation with the version placeholder instead of guessing the next release:

```rust
#[deprecated(since = "0.0.0-unreleased", note = "use `Receiver<Monitor>::classify`")]
```

`contrib/release/bump.sh` replaces it with the crate's version in the release PR, and the release checks fail if one is left. rustc warns callers about it like any other deprecation. Don't use `TBD`, which rustc treats as a future deprecation and does not warn about.

UniFFI does not carry deprecation attributes into the bindings, so `payjoin-ffi` states a deprecation in the doc comment and names the crate whose release deprecates the item, e.g. `Deprecated since payjoin 0.0.0-unreleased`. The payjoin-ffi bump fills in the version that crate is at.

### Nix Development Shells

Where [nix](https://nixos.org/) is available (NixOS or
Expand Down
5 changes: 3 additions & 2 deletions .github/ISSUE_TEMPLATE/minor-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ landed since the last release, so there is nothing to compile here.
- [ ] Branch `bump-CRATE-MAJOR-MINOR+1` from `master`.
- [ ] Run `contrib/release/bump.sh CRATE MAJOR.MINOR+1.0`. It sets the version, rewrites
every workspace member's requirement on the crate, renames `## Unreleased` to
`## MAJOR.MINOR+1.0` with a fresh empty `## Unreleased` above it, regenerates both
lock files and runs check-invariants. It needs jq, and the lock file step calls
`## MAJOR.MINOR+1.0` with a fresh empty `## Unreleased` above it, fills in the
`0.0.0-unreleased` placeholders in the crate's source, regenerates both lock files
and runs check-invariants. It needs jq, and the lock file step calls
`cargo +nightly`, so run it where rustup has a nightly toolchain. `nix develop .#release`
has jq but no rustup; there, pass `--no-lock`, then run `contrib/update-lock-files.sh`
from a rustup shell and `contrib/release/check-invariants.sh CRATE` again.
Expand Down
28 changes: 26 additions & 2 deletions contrib/release/bump.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
# Prepare a release crate's bump commit. Sets the crate's version, rewrites
# every workspace member's version requirement on it, renames the
# "## Unreleased" changelog section to the new version and opens a fresh
# empty one above it, regenerates both lock files, then runs
# check-invariants. Leaves the changes uncommitted for review.
# empty one above it, fills in the version placeholders in the crate's
# source, regenerates both lock files, then runs check-invariants. Leaves
# the changes uncommitted for review.
#
# payjoin-ffi is bumped the same way, except that its changelog entry
# opens by naming the wrapped payjoin release, and its version is also
Expand Down Expand Up @@ -55,6 +56,27 @@ open_section() { # <file> <heading> <line>
' "$1" >"$1.tmp" && mv "$1.tmp" "$1"
}

# Replace the version placeholder in the crate's source. A bare
# `since = "0.0.0-unreleased"` (a deprecation attribute) takes the new
# version. `since <crate> 0.0.0-unreleased` in prose takes that workspace
# crate's version: the bindings' doc comments name the payjoin release, since
# UniFFI does not carry Rust deprecation attributes into the bindings.
fill_unreleased() { # <new>
local placeholder="${UNRELEASED//./\\.}" name version f
while IFS= read -r f; do
sed -i "s/since = \"$placeholder\"/since = \"$1\"/g" "$f"
while IFS= read -r name; do
if [ "$name" = "$crate" ]; then
version="$1"
else
version="$(manifest_version "$name")"
fi
sed -i "s/since $name $placeholder/since $name $version/g" "$f"
done < <(cargo_metadata | jq -r '.packages[].name')
echo " $f: $UNRELEASED filled in"
done < <(git grep -l -F -e "$UNRELEASED" -- "$crate/src")
}

# Set the binding packages to the payjoin-ffi version. Each manifest is
# edited in place with sed and read back, as the Cargo.toml edit is, so a
# line that no longer looks the way this expects fails instead of being
Expand Down Expand Up @@ -173,6 +195,8 @@ else
echo " $changelog: '## Unreleased' -> '$heading', fresh Unreleased section added"
fi

fill_unreleased "$new"

if [ "$lock" -eq 1 ]; then
echo "Regenerating lock files (contrib/update-lock-files.sh)"
./contrib/update-lock-files.sh
Expand Down
8 changes: 6 additions & 2 deletions contrib/release/check-invariants.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#
# Check that each release crate is internally consistent: every dependent's
# version requirement on it matches its manifest version, both tracked lock
# files record that version, and its CHANGELOG.md has a section for it.
# files record that version, its CHANGELOG.md has a section for it, and its
# source has no version placeholder left for bump.sh to fill in.
# Offline, a few seconds. Checks all release crates, or the ones named.
set -euo pipefail
# shellcheck source=contrib/release/crates.sh
Expand Down Expand Up @@ -35,13 +36,16 @@ mismatches="$(cargo_metadata | jq -r --argjson t "$(printf '%s' "$crates" | jq -

for crate in $crates; do
version="$(manifest_version "$crate")"
echo "Checking $crate $version: lock files and CHANGELOG.md"
echo "Checking $crate $version: lock files, CHANGELOG.md and placeholders"
for lock in Cargo-minimal.lock Cargo-recent.lock; do
recorded="$(lockfile_version "$REPO_ROOT/$lock" "$crate")"
[ "$recorded" = "$version" ] || problem "$lock records $crate ${recorded:-<missing>}, expected $version"
done
grep -qxF -e "## $version" -e "## [$version]" "$REPO_ROOT/$crate/CHANGELOG.md" ||
problem "$crate/CHANGELOG.md has no ## $version section"
if git -C "$REPO_ROOT" grep -n -F -e "$UNRELEASED" -- "$crate/src"; then
problem "$crate/src still has the $UNRELEASED placeholder; bump.sh fills it in"
fi
done

[ "$status" -eq 0 ] && echo "Release invariants hold for: $crates"
Expand Down
7 changes: 7 additions & 0 deletions contrib/release/crates.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

RELEASE_CRATES="payjoin payjoin-cli payjoin-mailroom"

# Stands in for the version a pending change will ship in, as in
# `#[deprecated(since = "0.0.0-unreleased")]`. bump.sh replaces it. It is
# valid semver so clippy's deprecated_semver lint accepts it, unlike "TBD",
# which rustc reads as a future deprecation and does not warn about.
# shellcheck disable=SC2034 # read by the scripts that source this file
UNRELEASED="0.0.0-unreleased"

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

# `cargo metadata` for the workspace. Command substitutions run in a subshell
Expand Down
6 changes: 4 additions & 2 deletions payjoin-ffi/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ It sets the version in `payjoin-ffi/Cargo.toml`, the four package
manifests, `python/uv.lock` and `javascript/package-lock.json`, renames
`## Unreleased` in `payjoin-ffi/CHANGELOG.md` to the version with a fresh
empty `## Unreleased` above it and a first entry naming the wrapped
`payjoin` release, and opens a section in each language changelog with a
stock entry pointing at it. The lock file step calls
`payjoin` release, opens a section in each language changelog with a
stock entry pointing at it, and fills in the `0.0.0-unreleased`
placeholders in `payjoin-ffi/src`, such as `Deprecated since payjoin
0.0.0-unreleased`, with the version each names. The lock file step calls
`cargo +nightly`, which the release shell lacks, so pass `--no-lock`
there, then run `contrib/update-lock-files.sh` from a rustup shell and
`contrib/release/check-invariants.sh payjoin-ffi` again.
Expand Down
Loading