diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 25cb22333..0007670e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,6 +16,38 @@ concurrency: cancel-in-progress: false jobs: + # Everything downstream is keyed on this version, and publishing to crates.io + # cannot be undone. Read and check it before that point, not after, so a bad + # version costs a failed job instead of published crates with no tag, no + # release and no image. + preflight: + name: Preflight + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + tag: ${{ steps.version.outputs.tag }} + steps: + - uses: actions/checkout@v6 + + - name: Extract and validate version + id: version + run: | + VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + # Build metadata is rejected even though Cargo takes it. `+` is not a + # legal Docker tag character, so docker/metadata-action rewrites it to + # `-`: 0.7.0+build.5 would ship as the image 0.7.0-build.5, which is + # the tag a real prerelease of that name would claim. Being stricter + # than Cargo is only safe because this runs ahead of publish; as a + # post-publish check it would strand the release between crates.io + # and the tag. + if ! printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "Refusing to release '$VERSION': expected MAJOR.MINOR.PATCH[-prerelease], no build metadata" >&2 + exit 1 + fi + echo "Releasing $VERSION" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "tag=v$VERSION" >> "$GITHUB_OUTPUT" + validate: name: Validate uses: ./.github/workflows/main.yml @@ -27,7 +59,7 @@ jobs: publish: name: Publish to crates.io - needs: [validate, validate-e2e] + needs: [preflight, validate, validate-e2e] runs-on: ubuntu-latest environment: release steps: @@ -55,25 +87,18 @@ jobs: github-release: name: Create GitHub Release - needs: publish + needs: [preflight, publish] runs-on: ubuntu-latest - outputs: - version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - - name: Extract version - id: version - run: | - VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "tag=v$VERSION" >> "$GITHUB_OUTPUT" - - name: Create tag + env: + RELEASE_TAG: ${{ needs.preflight.outputs.tag }} run: | - TAG="${{ steps.version.outputs.tag }}" + TAG="$RELEASE_TAG" if git ls-remote --exit-code --tags origin "refs/tags/$TAG" > /dev/null 2>&1; then echo "Tag $TAG already exists on origin, skipping." else @@ -83,26 +108,32 @@ jobs: - name: Create GitHub Release env: + RELEASE_TAG: ${{ needs.preflight.outputs.tag }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - if gh release view "${{ steps.version.outputs.tag }}" > /dev/null 2>&1; then - echo "Release ${{ steps.version.outputs.tag }} already exists, skipping." + TAG="$RELEASE_TAG" + # Hand-written notes win when the release has them: --generate-notes + # emits one bullet per PR, which for a release this size is thousands + # of lines with no structure. Falls back to the generated list so a + # release without a notes file still publishes. + NOTES=".github/release-notes/$TAG.md" + if gh release view "$TAG" > /dev/null 2>&1; then + echo "Release $TAG already exists, skipping." + elif [ -f "$NOTES" ]; then + gh release create "$TAG" --title "$TAG" --notes-file "$NOTES" --latest else - gh release create "${{ steps.version.outputs.tag }}" \ - --title "${{ steps.version.outputs.tag }}" \ - --generate-notes \ - --latest + gh release create "$TAG" --title "$TAG" --generate-notes --latest fi # The tag pushed above with GITHUB_TOKEN can't trigger docker.yml's tag event, # so invoke it directly and pass the version for the :X.Y.Z image tag. publish-docker: name: Publish Docker image - needs: github-release + needs: [preflight, github-release] # docker.yml logs into GHCR and pushes the multi-arch image manifest. permissions: contents: read packages: write uses: ./.github/workflows/docker.yml with: - version: ${{ needs.github-release.outputs.version }} + version: ${{ needs.preflight.outputs.version }} diff --git a/Cargo.lock b/Cargo.lock index 8943d7156..02fe54b7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3829,7 +3829,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wacore" -version = "0.6.0" +version = "0.7.0" dependencies = [ "aes 0.9.2", "aes-gcm 0.11.0", @@ -3884,7 +3884,7 @@ dependencies = [ [[package]] name = "wacore-appstate" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "buffa", @@ -3905,7 +3905,7 @@ dependencies = [ [[package]] name = "wacore-binary" -version = "0.6.0" +version = "0.7.0" dependencies = [ "bytes", "codspeed-divan-compat", @@ -3924,7 +3924,7 @@ dependencies = [ [[package]] name = "wacore-derive" -version = "0.6.0" +version = "0.7.0" dependencies = [ "proc-macro2", "quote", @@ -3933,7 +3933,7 @@ dependencies = [ [[package]] name = "wacore-libsignal" -version = "0.6.0" +version = "0.7.0" dependencies = [ "aes 0.9.2", "async-lock", @@ -3965,7 +3965,7 @@ dependencies = [ [[package]] name = "wacore-noise" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "buffa", @@ -4011,7 +4011,7 @@ dependencies = [ [[package]] name = "waproto" -version = "0.6.0" +version = "0.7.0" dependencies = [ "buffa", "buffa-build", @@ -4216,7 +4216,7 @@ dependencies = [ [[package]] name = "whatsapp-rust" -version = "0.6.0" +version = "0.7.0" dependencies = [ "aes 0.9.2", "anyhow", @@ -4307,7 +4307,7 @@ dependencies = [ [[package]] name = "whatsapp-rust-sqlite-storage" -version = "0.6.0" +version = "0.7.0" dependencies = [ "async-trait", "buffa", @@ -4327,7 +4327,7 @@ dependencies = [ [[package]] name = "whatsapp-rust-tokio-transport" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "async-channel", @@ -4346,7 +4346,7 @@ dependencies = [ [[package]] name = "whatsapp-rust-ureq-http-client" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "async-trait", @@ -4357,7 +4357,7 @@ dependencies = [ [[package]] name = "whatsapp-rust-voip-cli" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "async-channel", diff --git a/Cargo.toml b/Cargo.toml index 1faf10726..92cb2e75e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "whatsapp-rust" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] @@ -124,13 +124,13 @@ uuid = { version = "1", default-features = false } zeroize = { version = "1.9", default-features = false, features = ["alloc"] } # Internal workspace crates -wacore = { path = "./wacore", default-features = false, version = "0.6.0" } -wacore-appstate = { path = "./wacore/appstate", default-features = false, version = "0.6.0" } -wacore-binary = { path = "./wacore/binary", default-features = false, version = "0.6.0" } -wacore-derive = { path = "./wacore/derive", version = "0.6.0" } -wacore-libsignal = { path = "./wacore/libsignal", version = "0.6.0" } -wacore-noise = { path = "./wacore/noise", version = "0.6.0" } -waproto = { path = "./waproto", version = "0.6.0" } +wacore = { path = "./wacore", default-features = false, version = "0.7.0" } +wacore-appstate = { path = "./wacore/appstate", default-features = false, version = "0.7.0" } +wacore-binary = { path = "./wacore/binary", default-features = false, version = "0.7.0" } +wacore-derive = { path = "./wacore/derive", version = "0.7.0" } +wacore-libsignal = { path = "./wacore/libsignal", version = "0.7.0" } +wacore-noise = { path = "./wacore/noise", version = "0.7.0" } +waproto = { path = "./waproto", version = "0.7.0" } yoke = { version = "0.8", features = ["derive"] } zerocopy = { version = "0.8.55", default-features = false, features = ["derive"] } zlib-rs = { version = "0.6.6", default-features = false, features = ["std", "rust-allocator"] } @@ -238,9 +238,9 @@ webrtc-dtls = { version = "0.12", optional = true } webrtc-sctp = { version = "0.17", optional = true } webrtc-util = { version = "0.17", optional = true } webrtc-util-011 = { package = "webrtc-util", version = "0.11", optional = true } -whatsapp-rust-sqlite-storage = { path = "./storages/sqlite-storage", version = "0.6.0", optional = true } -whatsapp-rust-tokio-transport = { path = "./transports/tokio-transport", version = "0.6.0", optional = true } -whatsapp-rust-ureq-http-client = { path = "./http_clients/ureq-client", version = "0.6.0", optional = true } +whatsapp-rust-sqlite-storage = { path = "./storages/sqlite-storage", version = "0.7.0", optional = true } +whatsapp-rust-tokio-transport = { path = "./transports/tokio-transport", version = "0.7.0", optional = true } +whatsapp-rust-ureq-http-client = { path = "./http_clients/ureq-client", version = "0.7.0", optional = true } # wasm32-unknown-unknown has no default getrandom backend, so make the browser # one available (the only valid choice there) to build the crate standalone: diff --git a/README.md b/README.md index 9c9361dc1..aee714f6a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ For the full API reference and guides, see the **[documentation](https://whatsap ```toml [dependencies] -whatsapp-rust = "0.6" +whatsapp-rust = "0.7" tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] } ``` diff --git a/examples/voip-cli/Cargo.toml b/examples/voip-cli/Cargo.toml index 655e1a6c5..f564a30cb 100644 --- a/examples/voip-cli/Cargo.toml +++ b/examples/voip-cli/Cargo.toml @@ -5,7 +5,7 @@ # it explicitly with `cargo run -p whatsapp-rust-voip-cli`. [package] name = "whatsapp-rust-voip-cli" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true license = "MIT" diff --git a/http_clients/ureq-client/Cargo.toml b/http_clients/ureq-client/Cargo.toml index 2ca7a272a..6daa83556 100644 --- a/http_clients/ureq-client/Cargo.toml +++ b/http_clients/ureq-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whatsapp-rust-ureq-http-client" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/storages/chat-store/Cargo.toml b/storages/chat-store/Cargo.toml index aa70df4a2..83d008a3b 100644 --- a/storages/chat-store/Cargo.toml +++ b/storages/chat-store/Cargo.toml @@ -7,6 +7,9 @@ authors = ["João Lucas "] license = "MIT" repository = "https://github.com/jlucaso1/whatsapp-rust" description = "SQLite-backed chat/message history store for whatsapp-rust" +# Held back from crates.io: the schema and the query surface are still moving, +# and publishing pins both. Drop this line to release it alongside the rest. +publish = false [features] default = [] @@ -28,7 +31,7 @@ tokio = { workspace = true, features = ["sync", "rt", "macros"] } wacore = { workspace = true } wacore-binary = { workspace = true } waproto = { workspace = true } -whatsapp-rust-sqlite-storage = { path = "../sqlite-storage", version = "0.6.0" } +whatsapp-rust-sqlite-storage = { path = "../sqlite-storage", version = "0.7.0" } [dev-dependencies] flate2 = { workspace = true } diff --git a/storages/sqlite-storage/Cargo.toml b/storages/sqlite-storage/Cargo.toml index 4d5128776..a432dba25 100644 --- a/storages/sqlite-storage/Cargo.toml +++ b/storages/sqlite-storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whatsapp-rust-sqlite-storage" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/transports/tokio-transport/Cargo.toml b/transports/tokio-transport/Cargo.toml index 529edfbca..d68ba27c0 100644 --- a/transports/tokio-transport/Cargo.toml +++ b/transports/tokio-transport/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whatsapp-rust-tokio-transport" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/wacore/Cargo.toml b/wacore/Cargo.toml index f161e9043..b9b2b263c 100644 --- a/wacore/Cargo.toml +++ b/wacore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wacore" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/wacore/appstate/Cargo.toml b/wacore/appstate/Cargo.toml index e06618236..fccbb0b5b 100644 --- a/wacore/appstate/Cargo.toml +++ b/wacore/appstate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wacore-appstate" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/wacore/binary/Cargo.toml b/wacore/binary/Cargo.toml index 2e20ff587..0531adc77 100644 --- a/wacore/binary/Cargo.toml +++ b/wacore/binary/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wacore-binary" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/wacore/derive/Cargo.toml b/wacore/derive/Cargo.toml index a1bd3d90c..2a1ccc640 100644 --- a/wacore/derive/Cargo.toml +++ b/wacore/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wacore-derive" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/wacore/libsignal/Cargo.toml b/wacore/libsignal/Cargo.toml index 77d2c7afd..5747943fd 100644 --- a/wacore/libsignal/Cargo.toml +++ b/wacore/libsignal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wacore-libsignal" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/wacore/noise/Cargo.toml b/wacore/noise/Cargo.toml index 54ead65e9..f7410c01d 100644 --- a/wacore/noise/Cargo.toml +++ b/wacore/noise/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wacore-noise" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "] diff --git a/waproto/Cargo.toml b/waproto/Cargo.toml index b59e7000b..6ffda4251 100644 --- a/waproto/Cargo.toml +++ b/waproto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "waproto" -version = "0.6.0" +version = "0.7.0" edition = "2024" rust-version.workspace = true authors = ["João Lucas "]