diff --git a/.github/workflows/cron-daily-bindings.yml b/.github/workflows/cron-daily-bindings.yml new file mode 100644 index 000000000..5da0b4e0e --- /dev/null +++ b/.github/workflows/cron-daily-bindings.yml @@ -0,0 +1,25 @@ +name: Daily language bindings + +# Runs every language binding's build, package and smoke checks on master +# with the same platform coverage as a bindings release, so a platform +# regression surfaces before the release tag does. + +on: + schedule: + - cron: "0 5 * * *" # runs daily at 05:00 UTC + workflow_dispatch: # allows manual triggering + +permissions: + contents: read + +jobs: + python: + uses: $/.github/workflows/python.yml + javascript: + uses: $/.github/workflows/javascript.yml + csharp: + uses: $/.github/workflows/csharp.yml + dart: + uses: $/.github/workflows/dart.yml + kotlin: + uses: $/.github/workflows/kotlin.yml diff --git a/.github/workflows/csharp.yml b/.github/workflows/csharp.yml index 72a7d45ec..0f2d1ee77 100644 --- a/.github/workflows/csharp.yml +++ b/.github/workflows/csharp.yml @@ -13,12 +13,37 @@ permissions: contents: read jobs: - build-csharp-and-test-unix: + # Pull requests run only the Linux build and test job. The other jobs + # cover macOS, Windows and packaging, and run on bindings releases and + # the daily run. + build-csharp-and-test-linux: name: "Build and test csharp" - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-26.04, macos-latest] + runs-on: ubuntu-26.04 + env: + RUSTUP_TOOLCHAIN: 1.85.0 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # unneeded: no git auth beyond checkout + - name: "Install Rust 1.85.0" + uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1 + with: + toolchain: 1.85.0 + - name: "Use cache" + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + with: + lookup-only: ${{ startsWith(github.ref, 'refs/tags/') }} + shared-key: msrv-workspace + - name: Set up nix + uses: $/.github/actions/setup-nix + - name: "Build and test" + run: nix develop .#csharp -c ./payjoin-ffi/csharp/contrib/test.sh + + build-csharp-and-test-macos: + name: "Build and test csharp (macos)" + if: github.event_name != 'pull_request' + runs-on: macos-latest env: RUSTUP_TOOLCHAIN: 1.85.0 steps: @@ -42,6 +67,7 @@ jobs: build-csharp-and-test-windows: name: "Build and test csharp (windows)" + if: github.event_name != 'pull_request' runs-on: windows-latest env: RUSTUP_TOOLCHAIN: 1.85 @@ -87,6 +113,7 @@ jobs: # Microsoft CRT/SDK. The per-RID smoke jobs verify each produced asset on # real hardware. name: "Build NuGet native asset" + if: github.event_name != 'pull_request' runs-on: ubuntu-26.04 env: # Must match the dtolnay/rust-toolchain version exactly: the cross-target @@ -172,6 +199,7 @@ jobs: pack-nuget: name: "Pack C# NuGet package" + if: github.event_name != 'pull_request' runs-on: ubuntu-26.04 needs: build-nuget-native env: @@ -230,6 +258,7 @@ jobs: smoke-nuget: name: "Smoke test C# NuGet package" + if: github.event_name != 'pull_request' runs-on: ${{ matrix.os }} needs: pack-nuget defaults: diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 12c7e3787..7dd811e0e 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -13,12 +13,37 @@ permissions: contents: read jobs: + # Pull requests run only the Linux build and test job. The other jobs + # cover macOS, Windows and packaging, and run on bindings releases and + # the daily run. build-dart-and-test: name: "Build and test dart" - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-26.04, macos-latest] + runs-on: ubuntu-26.04 + env: + RUSTUP_TOOLCHAIN: 1.85.0 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # unneeded: no git auth beyond checkout + - name: "Install Rust 1.85.0" + uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1 + with: + toolchain: 1.85.0 + - name: "Use cache" + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + with: + lookup-only: ${{ startsWith(github.ref, 'refs/tags/') }} + shared-key: msrv-workspace + - name: Set up nix + uses: $/.github/actions/setup-nix + - name: "Build and test" + run: nix develop .#dart -c bash ./payjoin-ffi/dart/contrib/test.sh + + build-dart-and-test-macos: + name: "Build and test dart (macos)" + if: github.event_name != 'pull_request' + runs-on: macos-latest env: RUSTUP_TOOLCHAIN: 1.85.0 steps: @@ -42,6 +67,7 @@ jobs: verify-pub-package: name: "Verify pub.dev package" + if: github.event_name != 'pull_request' runs-on: ubuntu-26.04 steps: - name: Checkout @@ -56,11 +82,12 @@ jobs: uses: $/.github/actions/setup-nix - name: Generate production bindings and dry-run publish run: | - # Pull requests may change payjoin or payjoin-mailroom without a - # version bump, so they stage those crates from the checkout. - # Releases stage against crates.io, as consumers build them. + # A release tag stages payjoin and payjoin-mailroom against + # crates.io, as consumers build them. Any other run may wrap + # changes to those crates that are not published yet, so it + # stages them from the checkout. flags=() - if [[ $GITHUB_EVENT_NAME == pull_request ]]; then + if [[ $GITHUB_REF != refs/tags/* ]]; then flags+=(--core-from-revision) fi nix develop .#dart -c ./payjoin-ffi/dart/contrib/prepare-publish.sh "${flags[@]}" "$RUNNER_TEMP/payjoin-pub" @@ -81,6 +108,7 @@ jobs: # the Cargo, rustup and pub caches. reproducible-linux: name: "Reproduce the Linux native library" + if: github.event_name != 'pull_request' needs: verify-pub-package runs-on: ubuntu-26.04 timeout-minutes: 60 diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml index 29aca5da9..4cd6d9cf3 100644 --- a/.github/workflows/javascript.yml +++ b/.github/workflows/javascript.yml @@ -13,12 +13,37 @@ permissions: contents: read jobs: + # Pull requests run only the Linux build and test job. The other jobs + # cover macOS, Windows and packaging, and run on bindings releases and + # the daily run. build-js-and-test: name: "Build and test javascript" - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-26.04, macos-latest] + runs-on: ubuntu-26.04 + env: + RUSTUP_TOOLCHAIN: 1.85.0 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # unneeded: no git auth beyond checkout + - name: "Install Rust 1.85.0" + uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1 + with: + toolchain: 1.85.0 + - name: "Use cache" + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + with: + lookup-only: ${{ startsWith(github.ref, 'refs/tags/') }} + shared-key: msrv-workspace + - name: Set up nix + uses: $/.github/actions/setup-nix + - name: "Build and test" + run: nix develop .#javascript -c ./payjoin-ffi/javascript/contrib/test.sh + + build-js-and-test-macos: + name: "Build and test javascript (macos)" + if: github.event_name != 'pull_request' + runs-on: macos-latest env: RUSTUP_TOOLCHAIN: 1.85.0 steps: @@ -44,6 +69,7 @@ jobs: # The package ships only dist/ (wasm + compiled TypeScript), which is # platform-independent, so one pack on Linux is the entire release build. name: "Pack npm package" + if: github.event_name != 'pull_request' runs-on: ubuntu-26.04 steps: - name: Checkout @@ -67,6 +93,7 @@ jobs: smoke-npm: name: "Smoke test npm package" + if: github.event_name != 'pull_request' runs-on: ${{ matrix.os }} needs: pack-npm strategy: diff --git a/.github/workflows/kotlin.yml b/.github/workflows/kotlin.yml index 4a8680279..550ab54e1 100644 --- a/.github/workflows/kotlin.yml +++ b/.github/workflows/kotlin.yml @@ -14,12 +14,40 @@ permissions: contents: read jobs: + # Pull requests run only the Linux build and test job. The macOS job + # runs on bindings releases and the daily run. build-kotlin-and-test: name: "Build and test kotlin" - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-26.04, macos-latest] + runs-on: ubuntu-26.04 + env: + RUSTUP_TOOLCHAIN: 1.85.0 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # unneeded: no git auth beyond checkout + - name: "Install Rust 1.85.0" + uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1 + with: + toolchain: 1.85.0 + - name: "Use cache" + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + with: + lookup-only: ${{ startsWith(github.ref, 'refs/tags/') }} + shared-key: msrv-workspace + - name: Set up nix + uses: $/.github/actions/setup-nix + - name: "Build and test" + run: nix develop .#kotlin -c bash ./payjoin-ffi/kotlin/contrib/test.sh + - name: "Compile production bindings" + run: | + nix develop .#kotlin -c env PAYJOIN_FFI_FEATURES= bash ./payjoin-ffi/kotlin/scripts/generate_bindings.sh + nix develop .#kotlin -c bash -c 'cd payjoin-ffi/kotlin && ./gradlew --no-daemon compileKotlin' + + build-kotlin-and-test-macos: + name: "Build and test kotlin (macos)" + if: github.event_name != 'pull_request' + runs-on: macos-latest env: RUSTUP_TOOLCHAIN: 1.85.0 steps: diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 57ba5dc68..770f40a39 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -13,12 +13,37 @@ permissions: contents: read jobs: + # Pull requests run only the Linux build and test job. The other jobs + # cover macOS, Windows and packaging, and run on bindings releases and + # the daily run. build-python-and-test: name: "Build and test python" - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-26.04, macos-latest] + runs-on: ubuntu-26.04 + env: + RUSTUP_TOOLCHAIN: 1.85.0 + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # unneeded: no git auth beyond checkout + - name: "Install Rust 1.85.0" + uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1 + with: + toolchain: 1.85.0 + - name: "Use cache" + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + with: + lookup-only: ${{ startsWith(github.ref, 'refs/tags/') }} + shared-key: msrv-workspace + - name: Set up nix + uses: $/.github/actions/setup-nix + - name: "Build and test" + run: nix develop .#python --command bash ./payjoin-ffi/python/contrib/test.sh + + build-python-and-test-macos: + name: "Build and test python (macos)" + if: github.event_name != 'pull_request' + runs-on: macos-latest env: RUSTUP_TOOLCHAIN: 1.85.0 steps: @@ -46,6 +71,7 @@ jobs: # auditwheel) and a fat universal2 dylib for macOS. Both wheels build # on a Linux host. The smoke jobs below verify each wheel on real hardware. name: "Build wheel" + if: github.event_name != 'pull_request' runs-on: ubuntu-26.04 strategy: fail-fast: false @@ -75,6 +101,7 @@ jobs: smoke-wheel: name: "Smoke test wheel" + if: github.event_name != 'pull_request' runs-on: ${{ matrix.os }} needs: build-wheel strategy: diff --git a/payjoin-ffi/csharp/RELEASING.md b/payjoin-ffi/csharp/RELEASING.md index b726e2aaf..ada426152 100644 --- a/payjoin-ffi/csharp/RELEASING.md +++ b/payjoin-ffi/csharp/RELEASING.md @@ -16,8 +16,9 @@ NuGet retains the historical `0.24.0-preview.1` release. The common ## Producing a release candidate -CI is the release path. On every pull request touching `payjoin-ffi/**`, the -`Build and Test CSharp` workflow: +CI is the release path. On every bindings release and in the +`Daily language bindings` run on `master`, the `Build and Test CSharp` +workflow: 1. builds release-profile native assets for each supported RID (`linux-arm64`, `linux-x64`, `osx-arm64`, `osx-x64`, `win-arm64`, @@ -27,8 +28,10 @@ CI is the release path. On every pull request touching `payjoin-ffi/**`, the 3. installs the package into a clean console app and runs a smoke test on each supported RID. -To cut a candidate, download the `payjoin-csharp-nuget-package` artifact from -the workflow run on the release commit in `master`. Do not pack from a +Pull requests run only the Linux build and test job. To cut a candidate, +download the `payjoin-csharp-nuget-package` artifact from a +`Daily language bindings` run on the release commit in `master`, starting +one by hand if the latest daily run is on an older commit. Do not pack from a development machine for publication; a local pack only contains the native assets present on that host. @@ -40,8 +43,8 @@ Review before every publish to nuget.org. Grounded in the NuGet ### Package correctness -- [ ] Every job of the `Build and Test CSharp` workflow is green on the - release commit, including the per-RID smoke tests. +- [ ] Every C# job of the `Daily language bindings` workflow is green on + the release commit, including the per-RID smoke tests. - [ ] `unzip -l Payjoin..nupkg` shows the expected layout: - `README.md` - `ref/net10.0/Payjoin.dll` diff --git a/payjoin-ffi/dart/CONTRIBUTING.md b/payjoin-ffi/dart/CONTRIBUTING.md index 455284441..f4f093465 100644 --- a/payjoin-ffi/dart/CONTRIBUTING.md +++ b/payjoin-ffi/dart/CONTRIBUTING.md @@ -70,9 +70,10 @@ Earlier versions carried it as build metadata, for example ### Publishing -CI is the publish path. On every pull request touching `payjoin-ffi/**`, -the `Build and Test Dart` workflow regenerates the production bindings and -validates the archive with a publish dry run +CI is the publish path. On every bindings release and in the +`Daily language bindings` run on `master`, the `Build and Test Dart` +workflow regenerates the production bindings and validates the archive +with a publish dry run ([`contrib/prepare-publish.sh`](contrib/prepare-publish.sh)). 1. The preparation script stages a separate package and pins its Rust @@ -84,11 +85,11 @@ validates the archive with a publish dry run Dart consumers through `Cargo-recent.lock` and a new release. Staging fetches the pinned commit from GitHub, so it must be pushed. The `payjoin` and `payjoin-mailroom` crates come from crates.io, except - with `--core-from-revision`, which pull requests use since they may - change those crates without a version bump. That option takes them - from the same revision and writes an `UNPUBLISHED_CORE` marker, which - `contrib/publish.sh` refuses. Both the publish dry run and - publication use the staged package. For local checks: + with `--core-from-revision`, which every run but a release tag uses + since it may wrap core changes not yet on crates.io. That option + takes them from the same revision and writes an `UNPUBLISHED_CORE` + marker, which `contrib/publish.sh` refuses. Both the publish dry run + and publication use the staged package. For local checks: ```shell nix develop .#dart -c ./payjoin-ffi/dart/contrib/prepare-publish.sh /tmp/payjoin-pub diff --git a/payjoin-ffi/python/RELEASING.md b/payjoin-ffi/python/RELEASING.md index c234c2788..46153efd4 100644 --- a/payjoin-ffi/python/RELEASING.md +++ b/payjoin-ffi/python/RELEASING.md @@ -13,8 +13,9 @@ the wrapped payjoin core. ## Producing the wheels -CI is the release path. On every pull request touching `payjoin-ffi/**`, -the `Build and Test Python` workflow builds release wheels with +CI is the release path. On every bindings release and in the +`Daily language bindings` run on `master`, the `Build and Test Python` +workflow builds release wheels with [`contrib/build-wheel.sh`](contrib/build-wheel.sh) (release profile, no `_test-utils`) and smoke-installs them on every supported platform: