diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 37d34f7bf..38adda101 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -111,9 +111,9 @@ echo "✓ Pre-commit hook passed" ### Changelog -Each release crate (`payjoin`, `payjoin-cli`, `payjoin-mailroom`) keeps a `CHANGELOG.md` with an `## Unreleased` section at the top. If your pull request changes what a user of that crate sees, add a line there in the same commit. Write it for the person reading the release notes, not for the reviewer. The release PR renames the heading to the version number and nothing else. +Each release crate (`payjoin`, `payjoin-cli`, `payjoin-mailroom`) and `payjoin-ffi` keeps a `CHANGELOG.md` with an `## Unreleased` section at the top. If your pull request changes what a user of that crate sees, add a line there in the same commit. Write it for the person reading the release notes, not for the reviewer. The release PR renames the heading to the version number and nothing else. `payjoin-ffi/CHANGELOG.md` is the release notes for the Python, JavaScript, C# and Dart packages, which are released together at its version. -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 a release crate's `src/` without either a changelog line or that label. +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. ### Nix Development Shells diff --git a/.github/ISSUE_TEMPLATE/minor-release.md b/.github/ISSUE_TEMPLATE/minor-release.md index a45dba8ef..bc76242b4 100644 --- a/.github/ISSUE_TEMPLATE/minor-release.md +++ b/.github/ISSUE_TEMPLATE/minor-release.md @@ -29,10 +29,6 @@ landed since the last release, so there is nothing to compile here. `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. -- [ ] For a `payjoin` bump, prepare the common bindings version bump in this PR - as well, following the [bindings instructions](../../payjoin-ffi/RELEASING.md). - The checker requires the FFI core dependency and binding metadata to agree. - Publish the Rust core before pushing the corresponding FFI tag. - [ ] Read the new changelog section once; fix wording, do not add history. - [ ] One commit, "Bump CRATE version to MAJOR.MINOR+1.0". Open the PR against `master`. The `Check release version bump` job runs check-invariants, a publish dry run and, @@ -55,10 +51,12 @@ changelog line. The bump PR is not edited for it. #### After a `payjoin` release -- [ ] Confirm the prepared bindings bump is merged and follow the +- [ ] Prepare the bindings bump with `contrib/release/bump.sh payjoin-ffi X.Y.Z`, + which also sets the language package manifests, their lock files and + changelogs, and follow the [bindings release instructions](../../payjoin-ffi/RELEASING.md). Dart's published native source is pinned automatically to the release checkout. - Create one signed tag with + Once merged, create one signed tag with `nix develop .#release -c contrib/release/tag.sh payjoin-ffi`, then push it. - [ ] Bump dependent release crates (`payjoin-cli`, `payjoin-mailroom`) on their own schedule, each with this checklist. Their tags verify that `payjoin` is already on diff --git a/.github/workflows/bindings-release.yml b/.github/workflows/bindings-release.yml index 18e782f97..97c477b45 100644 --- a/.github/workflows/bindings-release.yml +++ b/.github/workflows/bindings-release.yml @@ -1,10 +1,10 @@ name: Release language bindings -# Pushing a signed `payjoin-ffi-+payjoin-` tag verifies the -# tag and the shared binding version, runs every language's build, package -# and smoke checks at that commit, then publishes Python, JavaScript, C#, -# and Dart through the `release` environment (required reviewer) with -# keyless OIDC and cuts one GitHub release holding every package. +# Pushing a signed `payjoin-ffi-` tag verifies the tag and the +# shared binding version, runs every language's build, package and smoke +# checks at that commit, then publishes Python, JavaScript, C#, and Dart +# through the `release` environment (required reviewer) with keyless OIDC +# and cuts one GitHub release holding every package. # # Each registry has its own publish job. All four wait on every language # build, so they reach the environment gate together and one approval @@ -55,17 +55,13 @@ jobs: source contrib/release/crates.sh { echo "version=$version" - # A hyphen in the version proper marks a pre-release; the - # +payjoin- build metadata never does. - is_prerelease "${version%%+*}" && echo "prerelease=true" || echo "prerelease=false" + is_prerelease "$version" && echo "prerelease=true" || echo "prerelease=false" } >>"$GITHUB_OUTPUT" - name: Verify the wrapped payjoin core is on crates.io - env: - VERSION: ${{ steps.meta.outputs.version }} run: | set -euo pipefail source contrib/release/crates.sh - core="${VERSION##*+payjoin-}" + core="$(nix --quiet develop .#release -c bash -c 'source contrib/release/crates.sh && manifest_version payjoin')" # Dart consumers build the bindings from source against it. crate_published payjoin "$core" || { echo "::error::payjoin $core is not on crates.io; publish it before the bindings" @@ -297,7 +293,7 @@ jobs: run: | { echo "body<>"$GITHUB_OUTPUT" - name: Create release diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index 7e7066d72..0a502ac04 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -1,9 +1,9 @@ # .github/workflows/changelog-check.yml # -# A pull request that changes a release crate's source must add a line to -# that crate's CHANGELOG.md under "## Unreleased", or carry the -# "changelog: none" label. The bump PR then only renames the heading, so a -# merge under an open bump PR never requires editing it. +# A pull request that changes a release crate's or payjoin-ffi's source +# must add a line to that crate's CHANGELOG.md under "## Unreleased", or +# carry the "changelog: none" label. The bump PR then only renames the +# heading, so a merge under an open bump PR never requires editing it. name: Changelog on: @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v6 with: fetch-depth: 0 - - name: Require a changelog line for each changed release crate + - name: Require a changelog line for each changed crate env: BASE: ${{ github.event.pull_request.base.sha }} HEAD: ${{ github.event.pull_request.head.sha }} @@ -31,7 +31,7 @@ jobs: source contrib/release/crates.sh changed="$(git diff --name-only "$BASE" "$HEAD")" status=0 - for crate in $RELEASE_CRATES; do + for crate in $RELEASE_CRATES payjoin-ffi; do grep -q "^$crate/src/" <<<"$changed" || continue if ! grep -q "^$crate/CHANGELOG.md$" <<<"$changed"; then echo "::error::$crate/src changed but $crate/CHANGELOG.md did not; add a line under '## Unreleased', or say in the PR description that there is no user-visible change so a maintainer can label it 'changelog: none'" diff --git a/.github/workflows/crates-release.yml b/.github/workflows/crates-release.yml index 385c03b21..88afc473a 100644 --- a/.github/workflows/crates-release.yml +++ b/.github/workflows/crates-release.yml @@ -1,7 +1,9 @@ name: Release # A pull request that bumps a release crate's version is checked for -# consistency and publishability. Pushing a `-` tag verifies +# consistency and publishability; one that bumps payjoin-ffi's version is +# checked for consistency across the binding packages, which +# bindings-release.yml publishes. Pushing a `-` tag verifies # the tag, waits for CI at that commit, then publishes to crates.io through # the `release` environment (required reviewer) with keyless OIDC, # cuts the GitHub release, and confirms the upload. @@ -12,6 +14,7 @@ on: - payjoin/Cargo.toml - payjoin-cli/Cargo.toml - payjoin-mailroom/Cargo.toml + - payjoin-ffi/Cargo.toml push: tags: - payjoin-[0-9]* diff --git a/contrib/release/bindings-version.sh b/contrib/release/bindings-version.sh index 5435643b3..a78aa3485 100755 --- a/contrib/release/bindings-version.sh +++ b/contrib/release/bindings-version.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # # Check that every binding package carries the shared payjoin-ffi version -# and print the version a payjoin-ffi release tag names: -# +payjoin-. With --tag , also require -# that exact tag. +# and print it: the version a payjoin-ffi- release tag names. +# With --tag , also require that exact tag. # -# PyPI and npm cannot carry build metadata, so their manifests hold the -# bare version and package.json records the full one in releaseTag. -# Python spells a -rc.N pre-release as rcN (PEP 440). +# The manifests hold the bare version; the wrapped payjoin release is +# recorded in payjoin-ffi/CHANGELOG.md, and payjoin-ffi's own requirement +# on it must match the payjoin manifest. Python spells a -rc.N pre-release +# as rcN (PEP 440). # # usage: bindings-version.sh [--tag ] set -euo pipefail @@ -34,7 +34,6 @@ ffi="$(manifest_version payjoin-ffi)" core="$(manifest_version payjoin)" [[ $ffi =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]] || die "payjoin-ffi version $ffi must be MAJOR.MINOR.PATCH, optionally followed by -rc.N" -full="$ffi+payjoin-$core" python="${ffi/-rc./rc}" status=0 @@ -52,12 +51,10 @@ expect "python/pyproject.toml version" "$python" \ "$(sed -n 's/^version = "\(.*\)"$/\1/p' payjoin-ffi/python/pyproject.toml | head -1)" expect "javascript/package.json version" "$ffi" \ "$(jq -r .version payjoin-ffi/javascript/package.json)" -expect "javascript/package.json releaseTag" "$full" \ - "$(jq -r .releaseTag payjoin-ffi/javascript/package.json)" -expect "dart/pubspec.yaml version" "$full" \ +expect "dart/pubspec.yaml version" "$ffi" \ "$(sed -n 's/^version: *//p' payjoin-ffi/dart/pubspec.yaml)" -expect "csharp/Payjoin.csproj Version" "$full" \ +expect "csharp/Payjoin.csproj Version" "$ffi" \ "$(sed -n 's/.*\(.*\)<\/Version>.*/\1/p' payjoin-ffi/csharp/Payjoin.csproj | head -1)" -[ -z "$tag" ] || expect "release tag" "payjoin-ffi-$full" "$tag" +[ -z "$tag" ] || expect "release tag" "payjoin-ffi-$ffi" "$tag" [ "$status" -eq 0 ] || exit 1 -printf '%s\n' "$full" +printf '%s\n' "$ffi" diff --git a/contrib/release/bump.sh b/contrib/release/bump.sh index f6f05d31d..577237b64 100755 --- a/contrib/release/bump.sh +++ b/contrib/release/bump.sh @@ -6,7 +6,15 @@ # empty one above it, 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 +# set in the Python, JavaScript, Dart and C# package manifests, the uv and +# npm lock files, and the language changelogs, which open with a stock +# entry that points at payjoin-ffi/CHANGELOG.md. bindings-version.sh then +# confirms the packages agree. +# # usage: bump.sh [--no-lock] +# crate a release crate, or payjoin-ffi for the language bindings # --no-lock skip contrib/update-lock-files.sh (then check-invariants # reports the stale lock files, as it should) # @@ -24,7 +32,7 @@ if [ "${1:-}" = "--no-lock" ]; then shift fi [ "$#" -eq 2 ] || { - sed -n '2,14p' "$0" >&2 + sed -n '2,22p' "$0" >&2 exit 1 } crate="$1" @@ -34,11 +42,91 @@ die() { exit 1 } -case " $RELEASE_CRATES " in +# Rename a changelog's "## Unreleased" section to , open a fresh +# empty one above it, and make the first entry of the renamed +# section, above any lines pull requests left there. The list stays tight, +# without a blank line after , so prettier does not reflow it. +open_section() { # + awk -v h="$2" -v l="$3" ' + !seen && $0 == "## Unreleased" { seen = 1; print; print ""; print h; print ""; print l; next } + seen == 1 { seen = 2; if ($0 == "") { held = 1; next } } + held { held = 0; if ($0 !~ /^- /) print "" } + { print } + ' "$1" >"$1.tmp" && mv "$1.tmp" "$1" +} + +# 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 +# skipped. The lock files are edited the same way rather than regenerated, +# so the only change in them is the version. +bump_bindings() { # + local old="$1" new="$2" old_py new_py f line + # Python spells a -rc.N pre-release as rcN (PEP 440), in uv.lock too. + old_py="${old/-rc./rc}" + new_py="${new/-rc./rc}" + + f=payjoin-ffi/python/pyproject.toml + sed -i "0,/^version = \"$old_py\"/s//version = \"$new_py\"/" "$f" + [ "$(sed -n 's/^version = "\(.*\)"$/\1/p' "$f" | head -1)" = "$new_py" ] || + die "could not set version in $f" + echo " $f: version -> $new_py" + + # The package's own entry: the version line that follows its name. + f=payjoin-ffi/python/uv.lock + sed -i "/^name = \"payjoin\"$/{n;s/^version = \"$old_py\"$/version = \"$new_py\"/}" "$f" + [ "$(grep -A1 '^name = "payjoin"$' "$f" | sed -n 's/^version = "\(.*\)"$/\1/p')" = "$new_py" ] || + die "could not set version in $f" + echo " $f: version -> $new_py" + + # The root entry of package.json and, in the lock, of packages[""]. + for f in payjoin-ffi/javascript/package.json payjoin-ffi/javascript/package-lock.json; do + sed -i "/^ *\"name\": \"payjoin\",$/{n;s/^\( *\"version\": \"\)$old\"/\1$new\"/}" "$f" + [ "$(jq -r '[.version, .packages[""].version // .version] | unique | join(" ")' "$f")" = "$new" ] || + die "could not set version in $f" + echo " $f: version -> $new" + done + + f=payjoin-ffi/dart/pubspec.yaml + sed -i "s/^version: $old$/version: $new/" "$f" + [ "$(sed -n 's/^version: *//p' "$f")" = "$new" ] || die "could not set version in $f" + echo " $f: version -> $new" + + f=payjoin-ffi/csharp/Payjoin.csproj + sed -i "s#$old#$new#" "$f" + [ "$(sed -n 's/.*\(.*\)<\/Version>.*/\1/p' "$f" | head -1)" = "$new" ] || + die "could not set Version in $f" + echo " $f: Version -> $new" + + # Each language changelog opens the new section with a stock entry that + # points at the shared changelog, above any language-specific lines a + # pull request left under "## Unreleased". The URL is absolute because + # pub.dev renders Dart's changelog and cannot resolve ../CHANGELOG.md. + line="- Wraps payjoin-ffi $new; see its [changelog](https://github.com/payjoin/rust-payjoin/blob/payjoin-ffi-$new/payjoin-ffi/CHANGELOG.md)." + for f in payjoin-ffi/python/CHANGELOG.md payjoin-ffi/javascript/CHANGELOG.md payjoin-ffi/dart/CHANGELOG.md; do + if grep -qx '## Unreleased' "$f"; then + open_section "$f" "## [$new]" "$line" + echo " $f: '## Unreleased' -> '## [$new]', fresh Unreleased section added" + else + { printf '## [%s]\n\n%s\n\n' "$new" "$line" && cat "$f"; } >"$f.tmp" && mv "$f.tmp" "$f" + echo " $f: '## [$new]' section added" + fi + { grep -qxF -e "## [$new]" "$f" && grep -qxF -e "$line" "$f"; } || + die "could not add the $new section to $f" + done +} + +case " $RELEASE_CRATES payjoin-ffi " in *" $crate "*) ;; - *) die "$crate is not a release crate ($RELEASE_CRATES)" ;; + *) die "$crate is not a release crate ($RELEASE_CRATES) or payjoin-ffi" ;; esac -[[ $new =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]] || die "$new is not a semver version" +if [ "$crate" = payjoin-ffi ]; then + # The rule bindings-version.sh enforces: pre-releases are -rc.N only. + [[ $new =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]] || + die "$new must be MAJOR.MINOR.PATCH, optionally followed by -rc.N" +else + [[ $new =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]] || die "$new is not a semver version" +fi [ -z "$(git status --porcelain --untracked-files=no)" ] || die "commit or discard your changes first" RELEASE_METADATA="$(cargo_metadata)" @@ -61,11 +149,29 @@ while IFS= read -r manifest; do fi done < <(cargo_metadata | jq -r '.packages[].manifest_path') +[ "$crate" != payjoin-ffi ] || bump_bindings "$old" "$new" + +# The crate's changelog keeps its heading style: the binding changelogs +# bracket versions, the crates do not. changelog="$crate/CHANGELOG.md" grep -qx '## Unreleased' "$changelog" || die "$changelog has no '## Unreleased' section; add the lines for this release under one first" -sed -i "0,/^## Unreleased$/s//## Unreleased\n\n## $new/" "$changelog" -echo " $changelog: '## Unreleased' -> '## $new', fresh Unreleased section added" +if grep -q '^## \[' "$changelog"; then + heading="## [$new]" +else + heading="## $new" +fi +if [ "$crate" = payjoin-ffi ]; then + # The entry names the wrapped payjoin release first; the manifests no + # longer carry it, and the package docs point readers here for it. + line="- Wraps payjoin $(manifest_version payjoin)" + open_section "$changelog" "$heading" "$line" + grep -qxF -e "$line" "$changelog" || die "could not add '$line' to $changelog" + echo " $changelog: '## Unreleased' -> '$heading' opening with '$line', fresh Unreleased section added" +else + sed -i "0,/^## Unreleased$/s//## Unreleased\n\n$heading/" "$changelog" + echo " $changelog: '## Unreleased' -> '$heading', fresh Unreleased section added" +fi if [ "$lock" -eq 1 ]; then echo "Regenerating lock files (contrib/update-lock-files.sh)" @@ -73,6 +179,15 @@ if [ "$lock" -eq 1 ]; then fi "$DIR/check-invariants.sh" "$crate" +if [ "$crate" = payjoin-ffi ]; then + # Assigned first so a failing check stops the script under set -e. + agreed="$("$DIR/bindings-version.sh")" + echo "Binding packages agree at $agreed" +fi echo -echo "Review the '## $new' section of $changelog, then commit as:" +if [ "$crate" = payjoin-ffi ]; then + echo "Review the '$heading' sections of $changelog and the language changelogs, then commit as:" +else + echo "Review the '$heading' section of $changelog, then commit as:" +fi echo " git commit -am 'Bump $crate version to $new'" diff --git a/contrib/release/check-bump.sh b/contrib/release/check-bump.sh index 1b43fc2ee..9e36b7619 100755 --- a/contrib/release/check-bump.sh +++ b/contrib/release/check-bump.sh @@ -4,8 +4,11 @@ # to the base commit, confirm the bump is consistent (check-invariants), the # crate still publishes (cargo publish --dry-run), and the bump is large # enough for the API changes since the base version (cargo semver-checks). -# No-ops when no release version changed. A sibling release crate not yet on -# crates.io is skipped, not failed, since a PR may bump two crates at once. +# A payjoin-ffi bump is checked for consistency only, including that every +# binding package carries its version (bindings-version), since it is not +# published to crates.io. No-ops when no release version changed. A sibling +# release crate not yet on crates.io is skipped, not failed, since a PR may +# bump two crates at once. set -euo pipefail DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=contrib/release/crates.sh @@ -31,12 +34,23 @@ changed=() for crate in $RELEASE_CRATES; do [ "$(version_at "$base" "$crate")" = "$(manifest_version "$crate")" ] || changed+=("$crate") done +ffi=0 +[ "$(version_at "$base" payjoin-ffi)" = "$(manifest_version payjoin-ffi)" ] || ffi=1 -if [ "${#changed[@]}" -eq 0 ]; then +if [ "${#changed[@]}" -eq 0 ] && [ "$ffi" -eq 0 ]; then echo "No release crate version changed" exit 0 fi +if [ "$ffi" -eq 1 ]; then + echo "Version changed for: payjoin-ffi" + "$DIR/check-invariants.sh" payjoin-ffi + # Assigned first so a failing check stops the script under set -e. + agreed="$("$DIR/bindings-version.sh")" + echo "Binding packages agree at $agreed" +fi +[ "${#changed[@]}" -gt 0 ] || exit 0 + echo "Version changed for: ${changed[*]}" "$DIR/check-invariants.sh" "${changed[@]}" diff --git a/payjoin-ffi/CHANGELOG.md b/payjoin-ffi/CHANGELOG.md index 78ea889c6..31f103cda 100644 --- a/payjoin-ffi/CHANGELOG.md +++ b/payjoin-ffi/CHANGELOG.md @@ -1,9 +1,21 @@ +## Unreleased + ## [0.25.0] - Publish the Python, JavaScript, C#, and Dart packages from one signed `payjoin-ffi` tag at this common version. Each package jumps from its own sequence (Python and JavaScript 0.3.0, C# 0.2.0, Dart - 0.3.0+payjoin-1.2.0) with no API changes. + 0.3.0+payjoin-1.2.0); the version jump itself changes no API. +- Add typed `InputPair` constructors so bindings can contribute inputs + without building the `TxIn` and PSBT input by hand: `new_p2wpkh`, + `new_p2tr_keyspend` and `new_p2tr_scriptpath_spend`, `new_p2wsh` for + witness script spends such as multisig, and `new_p2pkh`, which takes + the consensus encoded funding transaction. The key path and P2WPKH + constructors supply the expected input weight; the script spends + still take it from the caller. +- Add `InputPairError::InvalidTransaction` for a funding transaction + that does not decode. Bindings that match exhaustively on + `InputPairError` need to handle the new variant. - Wraps payjoin 1.2.0, unchanged. ## [0.24.0] diff --git a/payjoin-ffi/RELEASING.md b/payjoin-ffi/RELEASING.md index d92b59007..1dbcbf011 100644 --- a/payjoin-ffi/RELEASING.md +++ b/payjoin-ffi/RELEASING.md @@ -1,38 +1,51 @@ # Releasing the language bindings Python, JavaScript, C#, and Dart share the `payjoin-ffi` version and are -released together from one signed tag, -`payjoin-ffi-+payjoin-`, where `` is the wrapped -`payjoin` release. The first shared release is -`payjoin-ffi-0.25.0+payjoin-1.2.0`. Kotlin has no published package yet; -the tag only runs its checks. The `payjoin-ffi` crate itself is not -published to crates.io. +released together from one signed tag, `payjoin-ffi-`. The +first shared release is `payjoin-ffi-0.25.0`. Kotlin has no published +package yet; the tag only runs its checks. The `payjoin-ffi` crate itself +is not published to crates.io. ## Versions `payjoin-ffi/Cargo.toml` holds the shared version. Each package manifest -repeats it in the form its registry accepts: +repeats it: -| Manifest | Carries | -| ------------------------- | --------------------------------------------- | -| `python/pyproject.toml` | bare version, PEP 440 spelling | -| `javascript/package.json` | bare `version`, full version in `releaseTag` | -| `dart/pubspec.yaml` | full version | -| `csharp/Payjoin.csproj` | full version (NuGet drops the metadata again) | +| Manifest | Carries | +| ------------------------- | ------------------------- | +| `python/pyproject.toml` | version, PEP 440 spelling | +| `javascript/package.json` | `version` | +| `dart/pubspec.yaml` | `version` | +| `csharp/Payjoin.csproj` | `Version` | Pre-releases are `-rc.N` only; Python spells `0.26.0-rc.1` as `0.26.0rc1`, -and npm publishes pre-releases to the `next` dist-tag. Every release bumps -the version, including one that only changes the wrapped core, because -PyPI, npm, and NuGet ignore the build metadata when deciding whether a -version already exists. - -A bump PR changes all five manifests, both Cargo lockfiles -(`contrib/update-lock-files.sh`), `python/uv.lock`, -`javascript/package-lock.json`, and the changelogs. +and npm publishes pre-releases to the `next` dist-tag. The wrapped +`payjoin` release is not part of the version; the changelog entry names +it, and `payjoin-ffi/Cargo.toml` requires exactly that version. Every +release bumps the version, including one that only changes the wrapped +core. + +Prepare the bump PR with: + +```shell +nix develop .#release -c contrib/release/bump.sh --no-lock payjoin-ffi X.Y.Z +``` + +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 +`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. + `payjoin-ffi/CHANGELOG.md` is the canonical changelog and becomes the -GitHub release body. The language changelogs record only language-specific -changes and link to it; pub.dev displays Dart's. Check the manifests agree -with: +GitHub release body; pull requests write to its `## Unreleased` section +as they do for the release crates. The language changelogs record only +language-specific changes and link to it; pub.dev displays Dart's. Check +the manifests agree with: ```shell nix develop .#release -c contrib/release/bindings-version.sh diff --git a/payjoin-ffi/csharp/Payjoin.csproj b/payjoin-ffi/csharp/Payjoin.csproj index 2bcad112d..0b827c3d8 100644 --- a/payjoin-ffi/csharp/Payjoin.csproj +++ b/payjoin-ffi/csharp/Payjoin.csproj @@ -7,7 +7,7 @@ true true Payjoin - 0.25.0+payjoin-1.2.0 + 0.25.0 Payjoin Payjoin Dev Kit Contributors C# bindings for payjoin-ffi, generated from rust-payjoin via UniFFI. diff --git a/payjoin-ffi/csharp/README.md b/payjoin-ffi/csharp/README.md index 15a593c1c..25a0000c3 100644 --- a/payjoin-ffi/csharp/README.md +++ b/payjoin-ffi/csharp/README.md @@ -38,7 +38,7 @@ Sessions persist each step to an event log through a persister you implement ove ## Stability -The package is pre-1.0 while the C# API stabilizes; expect breaking changes between 0.x releases. The version's build metadata names the wrapped payjoin core release, so `0.2.0+payjoin-1.2.0` packages payjoin 1.2.0. +The package is pre-1.0 while the C# API stabilizes; expect breaking changes between 0.x releases. Each version's [changelog entry](https://github.com/payjoin/rust-payjoin/blob/master/payjoin-ffi/CHANGELOG.md) names the wrapped payjoin core release. ## Documentation and help diff --git a/payjoin-ffi/csharp/RELEASING.md b/payjoin-ffi/csharp/RELEASING.md index 6145337e2..b726e2aaf 100644 --- a/payjoin-ffi/csharp/RELEASING.md +++ b/payjoin-ffi/csharp/RELEASING.md @@ -8,9 +8,8 @@ package readme. All published bindings share the payjoin-ffi version, starting with 0.25.0. Follow the [shared release instructions](../RELEASING.md) to bump -versions and publish using one signed FFI tag. Retained build metadata -identifies the wrapped payjoin core, and registries that omit metadata -publish the bare FFI version. +versions and publish using one signed FFI tag. The changelog entry names +the wrapped payjoin core. NuGet retains the historical `0.24.0-preview.1` release. The common `0.25.0` release supersedes it as well as the independent C# sequence. @@ -56,9 +55,8 @@ Review before every publish to nuget.org. Grounded in the NuGet - [ ] Native assets are release-profile builds without `_test-utils` (the pack step's validation target enforces both; confirm it ran in CI). - [ ] The package is under nuget.org's 250 MB size limit. -- [ ] Package version in `Payjoin.csproj` carries the common FFI version - and its `+payjoin-{version}` build metadata matches the wrapped - payjoin core release. +- [ ] Package version in `Payjoin.csproj` is the common FFI version, and + the changelog entry for it names the wrapped payjoin core release. ### Metadata and trust @@ -97,10 +95,9 @@ Review before every publish to nuget.org. Grounded in the NuGet ## Publishing Follow the [shared release procedure](../RELEASING.md). The -`payjoin-ffi-+payjoin-` tag reruns this language's -build and smoke checks before publishing through the existing `release` -environment with OIDC. The package version must match the common FFI -version, and its core metadata must match the declared core dependency. +`payjoin-ffi-` tag reruns this language's build and smoke checks +before publishing through the existing `release` environment with OIDC. +The package version must match the common FFI version. The GitHub release includes all language packages and `SHA256SUMS`. Optional local signatures use diff --git a/payjoin-ffi/dart/CHANGELOG.md b/payjoin-ffi/dart/CHANGELOG.md index 3179933dc..eb03a055b 100644 --- a/payjoin-ffi/dart/CHANGELOG.md +++ b/payjoin-ffi/dart/CHANGELOG.md @@ -1,8 +1,9 @@ -## [0.25.0+payjoin-1.2.0] +## [0.25.0] - Version aligned with payjoin-ffi 0.25.0. Releases now share one tag - and the [payjoin-ffi changelog](../CHANGELOG.md). No API changes since - 0.3.0+payjoin-1.2.0. + and the [payjoin-ffi changelog](../CHANGELOG.md), which lists the + `InputPair` constructors added since 0.3.0+payjoin-1.2.0; the version jump + itself changes no API. ## [0.3.0+payjoin-1.2.0] diff --git a/payjoin-ffi/dart/CONTRIBUTING.md b/payjoin-ffi/dart/CONTRIBUTING.md index b018b92ff..f450935d9 100644 --- a/payjoin-ffi/dart/CONTRIBUTING.md +++ b/payjoin-ffi/dart/CONTRIBUTING.md @@ -32,16 +32,12 @@ Maintainer instructions for publishing to ### Versioning -Versions take the form `+payjoin-`, for -example `0.2.1+payjoin-1.0.0-rc.8`. The part before the `+` is the package's -own semantic version, and is what consumers write version constraints -against. The build metadata after it records which `payjoin` release the -bindings wrap, so the pub.dev listing names the supported protocol version -without a changelog lookup. - -Bump the package version for changes to the Dart API or to packaging. Update -the build metadata whenever the wrapped `payjoin` release changes, which is a -patch bump at minimum, since the same Dart API gets new behavior. +Starting with 0.25.0, `pubspec.yaml` carries the common `payjoin-ffi` +version shared by every published binding. The wrapped `payjoin` release +is named in the changelog entry rather than in the version, so a release +that only changes the wrapped core still bumps the common version. +Earlier versions carried it as build metadata, for example +`0.2.1+payjoin-1.0.0-rc.8`. ### Publishing @@ -61,9 +57,8 @@ validates the archive with a publish dry run ``` 2. Follow the [shared bindings release instructions](../RELEASING.md). - `pubspec.yaml` carries the common FFI version and the wrapped core - metadata, for example `0.25.0+payjoin-1.2.0`. One signed - `payjoin-ffi-+payjoin-` tag starts all publishers. + `pubspec.yaml` carries the common FFI version, for example `0.25.0`. + One signed `payjoin-ffi-` tag starts all publishers. 3. Configure pub.dev automated publishing with tag pattern `payjoin-ffi-{{version}}` and environment `release` before the first shared release. Approve the release environment when prompted. diff --git a/payjoin-ffi/dart/pubspec.yaml b/payjoin-ffi/dart/pubspec.yaml index 037557182..5fb643b07 100644 --- a/payjoin-ffi/dart/pubspec.yaml +++ b/payjoin-ffi/dart/pubspec.yaml @@ -1,6 +1,6 @@ name: payjoin description: Dart bindings for payjoin -version: 0.25.0+payjoin-1.2.0 +version: 0.25.0 homepage: https://github.com/payjoin/rust-payjoin repository: https://github.com/payjoin/rust-payjoin diff --git a/payjoin-ffi/javascript/CHANGELOG.md b/payjoin-ffi/javascript/CHANGELOG.md index a643596cd..577c712cb 100644 --- a/payjoin-ffi/javascript/CHANGELOG.md +++ b/payjoin-ffi/javascript/CHANGELOG.md @@ -1,8 +1,9 @@ ## [0.25.0] - Version aligned with payjoin-ffi 0.25.0. Releases now share one tag - and the [payjoin-ffi changelog](../CHANGELOG.md). No API changes since - 0.3.0. + and the [payjoin-ffi changelog](../CHANGELOG.md), which lists the + `InputPair` constructors added since 0.3.0; the version jump + itself changes no API. ## [0.3.0] diff --git a/payjoin-ffi/javascript/RELEASING.md b/payjoin-ffi/javascript/RELEASING.md index d06aa5ab1..0cf0e7e6c 100644 --- a/payjoin-ffi/javascript/RELEASING.md +++ b/payjoin-ffi/javascript/RELEASING.md @@ -2,16 +2,14 @@ Follow the [shared bindings release instructions](../RELEASING.md) for version bumps, registry configuration, and tagging. One -`payjoin-ffi-+payjoin-` tag releases every -binding. +`payjoin-ffi-` tag releases every binding. ## Versioning -Starting with 0.25.0, `package.json` uses the common FFI version. Its -`releaseTag` field appends the wrapped payjoin core as build metadata. -Keep both version entries in `package-lock.json` synchronized. npm -publishes the bare version, so changing only metadata requires another -common version bump. +Starting with 0.25.0, `package.json` uses the common FFI version. Keep +both version entries in `package-lock.json` synchronized. The wrapped +payjoin core is named in the changelog entry, not in the version, so a +release that only changes the core still bumps the common version. ## Package checks diff --git a/payjoin-ffi/javascript/package.json b/payjoin-ffi/javascript/package.json index 2b6e40e9a..0a0b334f2 100644 --- a/payjoin-ffi/javascript/package.json +++ b/payjoin-ffi/javascript/package.json @@ -1,7 +1,6 @@ { "name": "payjoin", "version": "0.25.0", - "releaseTag": "0.25.0+payjoin-1.2.0", "description": "JavaScript/WASM bindings for rust-payjoin (EXPERIMENTAL)", "scripts": { "ubrn:nodejs": "ubrn build web --release --and-generate --config ubrn.nodejs.config.yaml", diff --git a/payjoin-ffi/python/CHANGELOG.md b/payjoin-ffi/python/CHANGELOG.md index a3423e325..606bd058c 100644 --- a/payjoin-ffi/python/CHANGELOG.md +++ b/payjoin-ffi/python/CHANGELOG.md @@ -1,8 +1,9 @@ ## [0.25.0] - Version aligned with payjoin-ffi 0.25.0. Releases now share one tag - and the [payjoin-ffi changelog](../CHANGELOG.md). No API changes since - 0.3.0. + and the [payjoin-ffi changelog](../CHANGELOG.md), which lists the + `InputPair` constructors added since 0.3.0; the version jump + itself changes no API. ## [0.3.0] diff --git a/payjoin-ffi/python/RELEASING.md b/payjoin-ffi/python/RELEASING.md index 17412dee9..c234c2788 100644 --- a/payjoin-ffi/python/RELEASING.md +++ b/payjoin-ffi/python/RELEASING.md @@ -8,9 +8,8 @@ Maintainer documentation for publishing the `payjoin` package to All published bindings share the payjoin-ffi version, starting with 0.25.0. Follow the [shared release instructions](../RELEASING.md) to bump -versions and publish using one signed FFI tag. Retained build metadata -identifies the wrapped payjoin core, and registries that omit metadata -publish the bare FFI version. +versions and publish using one signed FFI tag. The changelog entry names +the wrapped payjoin core. ## Producing the wheels @@ -32,10 +31,9 @@ CPython satisfying `requires-python` can install them. ## Publishing Follow the [shared release procedure](../RELEASING.md). The -`payjoin-ffi-+payjoin-` tag reruns this language's -build and smoke checks before publishing through the existing `release` -environment with OIDC. The package version must match the common FFI -version, and its core metadata must match the declared core dependency. +`payjoin-ffi-` tag reruns this language's build and smoke checks +before publishing through the existing `release` environment with OIDC. +The package version must match the common FFI version. The GitHub release includes all language packages and `SHA256SUMS`. Optional local signatures use