diff --git a/.github/workflows/release-pr-validation.yml b/.github/workflows/release-pr-validation.yml index 7a4e00cd7f..83f7e5aa86 100644 --- a/.github/workflows/release-pr-validation.yml +++ b/.github/workflows/release-pr-validation.yml @@ -26,22 +26,5 @@ jobs: with: toolchain: stable - - name: Determine release type - id: release-type - env: - PR_TITLE: ${{ github.event.pull_request.title }} - run: | - if [[ "$PR_TITLE" == *"program-libs"* ]]; then - echo "type=program-libs" >> "$GITHUB_OUTPUT" - elif [[ "$PR_TITLE" == *"sdk-libs"* ]]; then - echo "type=sdk-libs" >> "$GITHUB_OUTPUT" - else - echo "Error: Could not determine release type from PR title: $PR_TITLE" - echo "PR title must contain 'program-libs' or 'sdk-libs'" - exit 1 - fi - - name: Validate packages for publishing - env: - RELEASE_TYPE: ${{ steps.release-type.outputs.type }} - run: ./scripts/release/validate-packages.sh "$RELEASE_TYPE" + run: ./scripts/release/validate-packages.sh diff --git a/.github/workflows/release-rust.yml b/.github/workflows/release-rust.yml index fe028c1589..63147a961c 100644 --- a/.github/workflows/release-rust.yml +++ b/.github/workflows/release-rust.yml @@ -26,22 +26,6 @@ jobs: git fetch origin "${{ github.event.pull_request.base.sha }}" git fetch origin "${{ github.event.pull_request.head.sha }}" - - name: Determine release type - id: release-type - env: - PR_TITLE: ${{ github.event.pull_request.title }} - run: | - if [[ "$PR_TITLE" == *"program-libs"* ]]; then - echo "type=program-libs" >> "$GITHUB_OUTPUT" - elif [[ "$PR_TITLE" == *"sdk-libs"* ]]; then - echo "type=sdk-libs" >> "$GITHUB_OUTPUT" - else - echo "Error: Could not determine release type from PR title: $PR_TITLE" - echo "PR title must contain 'program-libs' or 'sdk-libs'" - exit 1 - fi - echo "Detected release type: $(cat "$GITHUB_OUTPUT")" - - name: Set up Rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: @@ -56,32 +40,29 @@ jobs: env: BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} - RELEASE_TYPE: ${{ steps.release-type.outputs.type }} run: | echo "=========================================" echo "Phase 1: Validation (dry-run)" echo "=========================================" - ./scripts/release/validate-packages.sh "$RELEASE_TYPE" "$BASE_SHA" "$HEAD_SHA" + ./scripts/release/validate-packages.sh "$BASE_SHA" "$HEAD_SHA" - name: Publish packages to crates.io env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} - RELEASE_TYPE: ${{ steps.release-type.outputs.type }} run: | echo "" echo "=========================================" echo "Phase 2: Publishing (atomic)" echo "=========================================" - ./scripts/release/validate-packages.sh --execute "$RELEASE_TYPE" "$BASE_SHA" "$HEAD_SHA" + ./scripts/release/validate-packages.sh --execute "$BASE_SHA" "$HEAD_SHA" - name: Create GitHub releases env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} - RELEASE_TYPE: ${{ steps.release-type.outputs.type }} run: | echo "" echo "=========================================" @@ -89,7 +70,7 @@ jobs: echo "=========================================" # Detect packages that were published - PACKAGES_STRING=$(./scripts/release/detect-version-changes.sh "$RELEASE_TYPE" "$BASE_SHA" "$HEAD_SHA") + PACKAGES_STRING=$(./scripts/release/detect-version-changes.sh "$BASE_SHA" "$HEAD_SHA") read -ra PACKAGES <<< "$PACKAGES_STRING" for pkg in "${PACKAGES[@]}"; do @@ -102,11 +83,11 @@ jobs: # Generate crate-specific release notes if RELEASE_NOTES=$(./scripts/release/generate-release-notes.sh "$pkg" "$VERSION" 2>&1); then - echo "✓ Generated release notes for $pkg" + echo "Generated release notes for $pkg" # Create release with custom notes if echo "$RELEASE_NOTES" | gh release create "$TAG" --title "$TAG" --notes-file -; then - echo "✓ Created release for $TAG" + echo "Created release for $TAG" else echo "Warning: Failed to create release for $TAG" fi @@ -115,7 +96,7 @@ jobs: echo "Warning: Could not generate crate-specific notes: $RELEASE_NOTES" echo "Falling back to auto-generated notes" if gh release create "$TAG" --generate-notes --title "$TAG"; then - echo "✓ Created release for $TAG" + echo "Created release for $TAG" else echo "Warning: Failed to create release for $TAG" fi @@ -123,4 +104,4 @@ jobs: done echo "" - echo "✓ GitHub releases created" + echo "GitHub releases created" diff --git a/Cargo.lock b/Cargo.lock index 2c1b36ad5b..7630bba204 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3437,7 +3437,7 @@ dependencies = [ [[package]] name = "light-account-checks" -version = "0.6.0" +version = "0.7.0" dependencies = [ "borsh 0.10.4", "pinocchio", @@ -3469,14 +3469,14 @@ dependencies = [ [[package]] name = "light-array-map" -version = "0.1.1" +version = "0.2.0" dependencies = [ "tinyvec", ] [[package]] name = "light-batched-merkle-tree" -version = "0.8.0" +version = "0.9.0" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3502,7 +3502,7 @@ dependencies = [ [[package]] name = "light-bloom-filter" -version = "0.5.0" +version = "0.6.0" dependencies = [ "bitvec", "light-hasher", @@ -3528,7 +3528,7 @@ dependencies = [ [[package]] name = "light-client" -version = "0.18.0" +version = "0.19.0" dependencies = [ "anchor-lang", "async-trait", @@ -3581,7 +3581,7 @@ dependencies = [ [[package]] name = "light-compressed-account" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anchor-lang", "ark-bn254 0.5.0", @@ -3644,7 +3644,7 @@ dependencies = [ [[package]] name = "light-compressible" -version = "0.3.1" +version = "0.4.0" dependencies = [ "aligned-sized", "anchor-lang", @@ -3692,7 +3692,7 @@ dependencies = [ [[package]] name = "light-event" -version = "0.3.0" +version = "0.4.0" dependencies = [ "borsh 0.10.4", "light-compressed-account", @@ -3773,7 +3773,7 @@ dependencies = [ [[package]] name = "light-instruction-decoder" -version = "0.1.0" +version = "0.2.0" dependencies = [ "borsh 0.10.4", "bs58", @@ -3790,12 +3790,11 @@ dependencies = [ [[package]] name = "light-instruction-decoder-derive" -version = "0.1.0" +version = "0.2.0" dependencies = [ "bs58", "darling", "heck 0.5.0", - "light-instruction-decoder", "proc-macro2", "quote", "sha2 0.10.9", @@ -3815,7 +3814,7 @@ dependencies = [ [[package]] name = "light-merkle-tree-metadata" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3887,7 +3886,7 @@ dependencies = [ [[package]] name = "light-program-test" -version = "0.18.0" +version = "0.19.0" dependencies = [ "account-compression", "anchor-lang", @@ -3943,7 +3942,7 @@ dependencies = [ [[package]] name = "light-prover-client" -version = "5.0.1" +version = "6.0.0" dependencies = [ "ark-bn254 0.5.0", "ark-serialize 0.5.0", @@ -3994,7 +3993,7 @@ dependencies = [ [[package]] name = "light-sdk" -version = "0.18.0" +version = "0.19.0" dependencies = [ "anchor-lang", "bincode", @@ -4026,7 +4025,7 @@ dependencies = [ [[package]] name = "light-sdk-macros" -version = "0.18.1" +version = "0.19.0" dependencies = [ "borsh 0.10.4", "darling", @@ -4045,7 +4044,7 @@ dependencies = [ [[package]] name = "light-sdk-pinocchio" -version = "0.18.0" +version = "0.19.0" dependencies = [ "borsh 0.10.4", "light-account-checks", @@ -4061,7 +4060,7 @@ dependencies = [ [[package]] name = "light-sdk-types" -version = "0.18.0" +version = "0.19.0" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -4178,7 +4177,7 @@ dependencies = [ [[package]] name = "light-token" -version = "0.3.0" +version = "0.4.0" dependencies = [ "anchor-lang", "arrayvec", @@ -4233,7 +4232,7 @@ dependencies = [ [[package]] name = "light-token-interface" -version = "0.2.0" +version = "0.3.0" dependencies = [ "aligned-sized", "anchor-lang", @@ -4268,7 +4267,7 @@ dependencies = [ [[package]] name = "light-token-types" -version = "0.3.0" +version = "0.4.0" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -4282,7 +4281,7 @@ dependencies = [ [[package]] name = "light-verifier" -version = "7.0.0" +version = "8.0.0" dependencies = [ "groth16-solana", "light-compressed-account", diff --git a/Cargo.toml b/Cargo.toml index 8c4ca05f39..544311c30a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,22 +187,22 @@ light-hash-set = { version = "4.0.0", path = "program-libs/hash-set" } light-indexed-merkle-tree = { version = "5.0.0", path = "program-libs/indexed-merkle-tree" } light-concurrent-merkle-tree = { version = "5.0.0", path = "program-libs/concurrent-merkle-tree" } light-sparse-merkle-tree = { version = "0.3.0", path = "sparse-merkle-tree" } -light-client = { path = "sdk-libs/client", version = "0.18.0" } -light-event = { path = "sdk-libs/event", version = "0.3.0" } +light-client = { path = "sdk-libs/client", version = "0.19.0" } +light-event = { path = "sdk-libs/event", version = "0.4.0" } light-hasher = { path = "program-libs/hasher", version = "5.0.0", default-features = false } light-macros = { path = "program-libs/macros", version = "2.2.0" } light-merkle-tree-reference = { path = "program-tests/merkle-tree", version = "4.0.0" } light-heap = { path = "program-libs/heap", version = "2.0.0" } -light-prover-client = { path = "prover/client", version = "5.0.1" } -light-sdk = { path = "sdk-libs/sdk", version = "0.18.0" } -light-sdk-pinocchio = { path = "sdk-libs/sdk-pinocchio", version = "0.18.0" } -light-sdk-macros = { path = "sdk-libs/macros", version = "0.18.1" } -light-sdk-types = { path = "sdk-libs/sdk-types", version = "0.18.0", default-features = false } -light-compressed-account = { path = "program-libs/compressed-account", version = "0.8.0", default-features = false } -light-compressible = { path = "program-libs/compressible", version = "0.3.1", default-features = false } -light-token-interface = { path = "program-libs/token-interface", version = "0.2.0" } -light-account-checks = { path = "program-libs/account-checks", version = "0.6.0", default-features = false } -light-verifier = { path = "program-libs/verifier", version = "7.0.0" } +light-prover-client = { path = "prover/client", version = "6.0.0" } +light-sdk = { path = "sdk-libs/sdk", version = "0.19.0" } +light-sdk-pinocchio = { path = "sdk-libs/sdk-pinocchio", version = "0.19.0" } +light-sdk-macros = { path = "sdk-libs/macros", version = "0.19.0" } +light-sdk-types = { path = "sdk-libs/sdk-types", version = "0.19.0", default-features = false } +light-compressed-account = { path = "program-libs/compressed-account", version = "0.9.0", default-features = false } +light-compressible = { path = "program-libs/compressible", version = "0.4.0", default-features = false } +light-token-interface = { path = "program-libs/token-interface", version = "0.3.0" } +light-account-checks = { path = "program-libs/account-checks", version = "0.7.0", default-features = false } +light-verifier = { path = "program-libs/verifier", version = "8.0.0" } light-zero-copy = { path = "program-libs/zero-copy", version = "0.6.0", default-features = false } light-zero-copy-derive = { path = "program-libs/zero-copy-derive", version = "0.6.0" } photon-api = { path = "sdk-libs/photon-api", version = "0.54.0" } @@ -214,8 +214,8 @@ account-compression = { path = "programs/account-compression", version = "2.0.0" light-compressed-token = { path = "programs/compressed-token/program", version = "2.0.0", features = [ "cpi", ] } -light-token-types = { path = "sdk-libs/token-types", version = "0.3.0" } -light-token = { path = "sdk-libs/token-sdk", version = "0.3.0" } +light-token-types = { path = "sdk-libs/token-types", version = "0.4.0" } +light-token = { path = "sdk-libs/token-sdk", version = "0.4.0" } light-token-client = { path = "sdk-libs/token-client", version = "0.1.0" } light-system-program-anchor = { path = "anchor-programs/system", version = "2.0.0", features = [ "cpi", @@ -227,18 +227,18 @@ light-registry = { path = "programs/registry", version = "2.0.0", features = [ create-address-test-program = { path = "program-tests/create-address-test-program", version = "1.0.0", features = [ "cpi", ] } -light-program-test = { path = "sdk-libs/program-test", version = "0.18.0" } -light-instruction-decoder = { path = "sdk-libs/instruction-decoder", version = "0.1.0" } -light-instruction-decoder-derive = { path = "sdk-libs/instruction-decoder-derive", version = "0.1.0" } -light-batched-merkle-tree = { path = "program-libs/batched-merkle-tree", version = "0.8.0" } -light-merkle-tree-metadata = { path = "program-libs/merkle-tree-metadata", version = "0.8.0" } +light-program-test = { path = "sdk-libs/program-test", version = "0.19.0" } +light-instruction-decoder = { path = "sdk-libs/instruction-decoder", version = "0.2.0" } +light-instruction-decoder-derive = { path = "sdk-libs/instruction-decoder-derive", version = "0.2.0" } +light-batched-merkle-tree = { path = "program-libs/batched-merkle-tree", version = "0.9.0" } +light-merkle-tree-metadata = { path = "program-libs/merkle-tree-metadata", version = "0.9.0" } aligned-sized = { path = "program-libs/aligned-sized", version = "1.1.0" } -light-bloom-filter = { path = "program-libs/bloom-filter", version = "0.5.0" } +light-bloom-filter = { path = "program-libs/bloom-filter", version = "0.6.0" } light-bounded-vec = { version = "2.0.1" } light-poseidon = { version = "0.3.0" } light-test-utils = { path = "program-tests/utils", version = "1.2.1" } light-indexed-array = { path = "program-libs/indexed-array", version = "0.3.0" } -light-array-map = { path = "program-libs/array-map", version = "0.1.1" } +light-array-map = { path = "program-libs/array-map", version = "0.2.0" } light-program-profiler = { version = "0.1.0" } create-address-program-test = { path = "program-tests/create-address-test-program", version = "1.0.0" } sdk-compressible-test = { path = "sdk-tests/sdk-compressible-test", version = "0.1.0" } diff --git a/program-libs/CLAUDE.md b/program-libs/CLAUDE.md new file mode 100644 index 0000000000..81359b5151 --- /dev/null +++ b/program-libs/CLAUDE.md @@ -0,0 +1,72 @@ +# Program Libraries + +Core Rust libraries used in on-chain programs and sdk-libs. These crates are designed for Solana program environments with careful attention to compute budget and memory constraints. + +## Reverse Dependency Hierarchy + +For each crate, lists all crates that depend on it (dependents). + +| Crate | Depended On By | +|-------|----------------| +| account-checks | batched-merkle-tree, compressible, token-interface | +| aligned-sized | (none) | +| array-map | token-interface | +| batched-merkle-tree | (none) | +| bloom-filter | batched-merkle-tree | +| compressed-account | batched-merkle-tree, compressible, merkle-tree-metadata, token-interface, verifier | +| compressible | token-interface | +| concurrent-merkle-tree | indexed-merkle-tree | +| hash-set | concurrent-merkle-tree, indexed-merkle-tree | +| hasher | batched-merkle-tree, bloom-filter, compressed-account, compressible, concurrent-merkle-tree, hash-set, indexed-array, indexed-merkle-tree, token-interface | +| heap | compressed-account, compressible, token-interface | +| indexed-array | (none) | +| indexed-merkle-tree | (none) | +| macros | batched-merkle-tree, compressed-account, compressible, token-interface | +| merkle-tree-metadata | batched-merkle-tree | +| token-interface | (none) | +| verifier | batched-merkle-tree | +| zero-copy | batched-merkle-tree, compressed-account, compressible, token-interface | +| zero-copy-derive | zero-copy | + +## Crate Descriptions + +| Crate | Description | +|-------|-------------| +| account-checks | Solana account validation (solana-program + pinocchio) | +| aligned-sized | Macro to get aligned size of Rust structs | +| array-map | Array-based map data structure | +| batched-merkle-tree | Merkle tree updates with ZK proofs | +| bloom-filter | Bloom filter implementation | +| compressed-account | Compressed account types and utilities | +| compressible | Configuration for compressible token accounts | +| concurrent-merkle-tree | Concurrent Merkle tree operations | +| hash-set | Hash set for Solana programs | +| hasher | Poseidon hash implementation | +| heap | Heap data structure for Solana programs | +| indexed-array | Indexed array utilities | +| indexed-merkle-tree | Indexed Merkle tree with address management | +| macros | Procedural macros for Light Protocol | +| merkle-tree-metadata | Metadata types for Merkle trees | +| token-interface | Compressed token types and interfaces | +| verifier | ZKP verification logic in Solana programs | +| zero-copy | Zero-copy serialization for efficient account access | +| zero-copy-derive | Derive macros for zero-copy serialization | + +## External Dependencies + +Some crates depend on external Light Protocol crates not in program-libs: +- `light-poseidon` - Poseidon hash primitive +- `light-bounded-vec` - Bounded vector implementation +- `light-merkle-tree-reference` - Reference Merkle tree implementation for testing +- `light-program-profiler` - Profiling utilities + +## Testing + +Unit tests run with `cargo test`: +```bash +cargo test -p light-hasher --all-features +cargo test -p light-compressed-account --all-features +cargo test -p light-batched-merkle-tree +``` + +Integration tests that require Solana runtime are in `program-tests/`. diff --git a/program-libs/account-checks/Cargo.toml b/program-libs/account-checks/Cargo.toml index 3a7af4c8f1..04007b328e 100644 --- a/program-libs/account-checks/Cargo.toml +++ b/program-libs/account-checks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-account-checks" -version = "0.6.0" +version = "0.7.0" description = "Checks for solana accounts." repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/array-map/Cargo.toml b/program-libs/array-map/Cargo.toml index 7a0f2c0efc..a02da0afef 100644 --- a/program-libs/array-map/Cargo.toml +++ b/program-libs/array-map/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-array-map" -version = "0.1.1" +version = "0.2.0" description = "Generic array-backed map with O(n) lookup for small collections" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/batched-merkle-tree/Cargo.toml b/program-libs/batched-merkle-tree/Cargo.toml index b597ecd044..7eabdd9935 100644 --- a/program-libs/batched-merkle-tree/Cargo.toml +++ b/program-libs/batched-merkle-tree/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-batched-merkle-tree" -version = "0.8.0" +version = "0.9.0" description = "Batch Merkle tree implementation." repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/bloom-filter/Cargo.toml b/program-libs/bloom-filter/Cargo.toml index 20e32d7d52..963a27b735 100644 --- a/program-libs/bloom-filter/Cargo.toml +++ b/program-libs/bloom-filter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-bloom-filter" -version = "0.5.0" +version = "0.6.0" description = "Experimental bloom filter." repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/compressed-account/Cargo.toml b/program-libs/compressed-account/Cargo.toml index 96d0b96732..4295a071de 100644 --- a/program-libs/compressed-account/Cargo.toml +++ b/program-libs/compressed-account/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-compressed-account" -version = "0.8.0" +version = "0.9.0" description = "Compressed account struct and common utility functions used in Light Protocol." repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/compressible/Cargo.toml b/program-libs/compressible/Cargo.toml index 4548d6125a..67b429a05b 100644 --- a/program-libs/compressible/Cargo.toml +++ b/program-libs/compressible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-compressible" -version = "0.3.1" +version = "0.4.0" edition = "2021" description = "Light Protocol compressible data structures" license = "MIT" diff --git a/program-libs/merkle-tree-metadata/Cargo.toml b/program-libs/merkle-tree-metadata/Cargo.toml index f9f10e3306..7d89108742 100644 --- a/program-libs/merkle-tree-metadata/Cargo.toml +++ b/program-libs/merkle-tree-metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-merkle-tree-metadata" -version = "0.8.0" +version = "0.9.0" description = "Merkle tree metadata for light-concurrent-merkle-tree, light-indexed-merkle-tree, light-batched-merkle-tree." repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/token-interface/Cargo.toml b/program-libs/token-interface/Cargo.toml index c151cfd292..aac27dd90f 100644 --- a/program-libs/token-interface/Cargo.toml +++ b/program-libs/token-interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-token-interface" -version = "0.2.0" +version = "0.3.0" edition = { workspace = true } description = "Light Protocol token instruction data types." license = "MIT" diff --git a/program-libs/verifier/Cargo.toml b/program-libs/verifier/Cargo.toml index 3abed08dce..3abe5db16f 100644 --- a/program-libs/verifier/Cargo.toml +++ b/program-libs/verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-verifier" -version = "7.0.0" +version = "8.0.0" description = "ZKP proof verifier used in Light Protocol" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/prover/client/Cargo.toml b/prover/client/Cargo.toml index ffc3875143..fbfb6e0a15 100644 --- a/prover/client/Cargo.toml +++ b/prover/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-prover-client" -version = "5.0.1" +version = "6.0.0" description = "Crate for interacting with Light Protocol circuits" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/scripts/release/check-dependents.sh b/scripts/release/check-dependents.sh new file mode 100755 index 0000000000..9c23a67fe7 --- /dev/null +++ b/scripts/release/check-dependents.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Check that all dependents of released packages are also being released +# Usage: ./scripts/release/check-dependents.sh +# Arguments: +# packages: Space-separated list of package names being released +# Exits with 0 if all dependents are included, 1 if missing dependents + +if [ $# -lt 1 ]; then + echo "Usage: $0 [package2] ..." >&2 + exit 1 +fi + +PACKAGES=("$@") + +# Packages to exclude from dependent checks (e.g., not published to crates.io) +EXCLUDED_PACKAGES="light-token-client" + +# Scan all lib directories +SCAN_DIRS="program-libs sdk-libs prover/client sparse-merkle-tree" + +# Create temp files for tracking +DEPS_FILE=$(mktemp) +RELEASING_FILE=$(mktemp) +MISSING_FILE=$(mktemp) +trap "rm -f $DEPS_FILE $RELEASING_FILE $MISSING_FILE" EXIT + +# Store releasing packages +for pkg in "${PACKAGES[@]}"; do + echo "$pkg" >> "$RELEASING_FILE" +done + +# Find all Cargo.toml files first +CARGO_FILES=$(find $SCAN_DIRS -name "Cargo.toml" 2>/dev/null) + +# Build dependency map: dependent_pkg:depends_on_pkg +for cargo_toml in $CARGO_FILES; do + # Get the package name from this Cargo.toml + pkg_name=$(grep '^name = ' "$cargo_toml" 2>/dev/null | head -1 | sed 's/name = "\([^"]*\)".*/\1/') + + if [ -z "$pkg_name" ]; then + continue + fi + + # Find all light-* dependencies in this Cargo.toml + deps=$(grep -E '^light-[a-zA-Z0-9_-]+ *= *\{' "$cargo_toml" 2>/dev/null || true) + + if [ -n "$deps" ]; then + echo "$deps" | while read -r line; do + # Extract dependency name + dep_name=$(echo "$line" | sed 's/^\([a-zA-Z0-9_-]*\).*/\1/') + + if [ -n "$dep_name" ] && [ "$dep_name" != "$pkg_name" ]; then + echo "$pkg_name:$dep_name" + fi + done >> "$DEPS_FILE" + fi +done + +# Check each released package for missing dependents +for pkg in "${PACKAGES[@]}"; do + # Find all packages that depend on this package + if [ -s "$DEPS_FILE" ]; then + dependents=$(grep ":${pkg}$" "$DEPS_FILE" 2>/dev/null | cut -d: -f1 | sort -u || true) + + for dependent in $dependents; do + # Skip excluded packages + if echo "$EXCLUDED_PACKAGES" | grep -qw "$dependent"; then + continue + fi + # Check if dependent is in the release list + if ! grep -q "^${dependent}$" "$RELEASING_FILE"; then + # Check if dependent is in the scan dirs (it should be since we found it) + echo "$dependent (depends on $pkg)" >> "$MISSING_FILE" + fi + done + fi +done + +# Deduplicate missing file +if [ -s "$MISSING_FILE" ]; then + sort -u "$MISSING_FILE" > "${MISSING_FILE}.sorted" + mv "${MISSING_FILE}.sorted" "$MISSING_FILE" + + echo "ERROR: The following packages depend on released packages but are not being released:" >&2 + echo "" >&2 + while read -r line; do + echo " - $line" >&2 + done < "$MISSING_FILE" + echo "" >&2 + echo "Missing packages: $(cut -d' ' -f1 "$MISSING_FILE" | tr '\n' ' ')" >&2 + echo "" >&2 + echo "To fix: bump versions of these packages and include them in the release." >&2 + exit 1 +fi + +echo "All dependents check passed - no missing packages" +exit 0 diff --git a/scripts/release/create-release-pr.sh b/scripts/release/create-release-pr.sh index 0eae2bf479..04c9a2d6e5 100755 --- a/scripts/release/create-release-pr.sh +++ b/scripts/release/create-release-pr.sh @@ -2,47 +2,22 @@ set -euo pipefail # Create release PR with current changes -# Usage: ./scripts/create-release-pr.sh [target-branch] +# Usage: ./scripts/release/create-release-pr.sh [target-branch] # Arguments: -# release-type: Type of release (program-libs or sdk-libs) # target-branch: Branch to compare against (default: origin/main) -if [ $# -lt 1 ] || [ $# -gt 2 ]; then - echo "Usage: $0 [target-branch]" - exit 1 -fi - -RELEASE_TYPE=$1 -TARGET_BRANCH="${2:-origin/main}" +TARGET_BRANCH="${1:-origin/main}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -if [[ ! "$RELEASE_TYPE" =~ ^(program-libs|sdk-libs)$ ]]; then - echo "Error: Release type must be 'program-libs' or 'sdk-libs'" - exit 1 -fi - # Function to get version changes between two git refs # Output format: One line per package: "package-name old-version new-version" get_version_changes() { - local release_type="$1" - local base_ref="$2" - local head_ref="$3" - - # Set the grep pattern based on release type - local grep_pattern - case "$release_type" in - program-libs) - grep_pattern='program-libs/' - ;; - sdk-libs) - grep_pattern='(sdk-libs|program-tests/merkle-tree|sparse-merkle-tree|prover)/' - ;; - *) - echo "Error: Release type must be 'program-libs' or 'sdk-libs'" >&2 - return 1 - ;; - esac + local base_ref="$1" + local head_ref="$2" + + # Scan all lib directories + local grep_pattern='(program-libs|sdk-libs|prover/client|sparse-merkle-tree)/' # Fetch if comparing against remote refs if [[ "$base_ref" == origin/* ]]; then @@ -60,7 +35,7 @@ get_version_changes() { diff_args=("$base_ref...$head_ref") fi - # Get list of changed Cargo.toml files in the specified directory + # Get list of changed Cargo.toml files in the specified directories while IFS= read -r file; do # Extract old and new version from the diff local versions=$(git diff "${diff_args[@]}" -- "$file" | grep -E '^\+version|^-version' | grep -v '+++\|---') @@ -88,7 +63,7 @@ if git diff --quiet; then fi echo "=========================================" -echo "Creating $RELEASE_TYPE release PR" +echo "Creating libs release PR" echo "=========================================" echo "" @@ -103,7 +78,7 @@ echo "Comparing against: $TARGET_BRANCH" echo "" # Get version changes using the function -VERSION_CHANGES_RAW=$(get_version_changes "$RELEASE_TYPE" "$TARGET_BRANCH" "HEAD") +VERSION_CHANGES_RAW=$(get_version_changes "$TARGET_BRANCH" "HEAD") # Build packages array and formatted version changes PACKAGES=() @@ -112,7 +87,7 @@ while IFS= read -r line; do if [ -n "$line" ]; then read -r pkg old_ver new_ver <<< "$line" PACKAGES+=("$pkg") - VERSION_CHANGES="${VERSION_CHANGES} ${pkg}: ${old_ver} → ${new_ver}\n" + VERSION_CHANGES="${VERSION_CHANGES} ${pkg}: ${old_ver} -> ${new_ver}\n" fi done <<< "$VERSION_CHANGES_RAW" @@ -129,7 +104,7 @@ echo "" # Validate packages using the validation script (comparing against target branch) # Note: Changes are in working directory but not yet committed -if "$SCRIPT_DIR/validate-packages.sh" "$RELEASE_TYPE" "$TARGET_BRANCH" "HEAD"; then +if "$SCRIPT_DIR/validate-packages.sh" "$TARGET_BRANCH" "HEAD"; then echo "" echo "All crates validated successfully" else @@ -148,8 +123,8 @@ fi echo "" # Create release branch -BRANCH_NAME="release/${RELEASE_TYPE}" -PR_TITLE="chore: bump ${RELEASE_TYPE} versions" +BRANCH_NAME="release/libs" +PR_TITLE="chore: bump lib versions" echo "Will create:" echo " Branch: $BRANCH_NAME" @@ -167,7 +142,7 @@ git checkout -b "$BRANCH_NAME" # Commit changes git add -A -git commit -m "chore(${RELEASE_TYPE}): bump versions" +git commit -m "chore(libs): bump versions" # Push branch echo "Pushing branch to origin..." @@ -177,13 +152,10 @@ git push -u origin "$BRANCH_NAME" echo "" echo "Creating pull request..." -# Capitalize first letter of release type (bash 3.2 compatible) -RELEASE_TYPE_CAPS="$(echo ${RELEASE_TYPE:0:1} | tr '[:lower:]' '[:upper:]')${RELEASE_TYPE:1}" - # Build PR body with proper escaping -PR_BODY="## ${RELEASE_TYPE_CAPS} Release +PR_BODY="## Libs Release -This PR bumps versions for ${RELEASE_TYPE} crates. +This PR bumps versions for program-libs and sdk-libs crates. ### Version Bumps @@ -197,7 +169,7 @@ ${VERSION_CHANGES} 3. After merge, GitHub Action will publish each crate individually to crates.io and create releases --- -*Generated by \`scripts/create-release-pr.sh ${RELEASE_TYPE}\`*" +*Generated by \`scripts/release/create-release-pr.sh\`*" gh pr create \ --title "$PR_TITLE" \ diff --git a/scripts/release/detect-version-changes.sh b/scripts/release/detect-version-changes.sh index 6c3f107d5e..09d54783a6 100755 --- a/scripts/release/detect-version-changes.sh +++ b/scripts/release/detect-version-changes.sh @@ -2,35 +2,17 @@ set -euo pipefail # Detect packages with version changes between two git refs -# Usage: ./scripts/detect-version-changes.sh [base-ref] [head-ref] +# Usage: ./scripts/release/detect-version-changes.sh [base-ref] [head-ref] # Arguments: -# release-type: Type of release (program-libs or sdk-libs) # base-ref: Base reference to compare against (default: origin/main) # head-ref: Head reference to compare (default: HEAD) # Outputs: Space-separated list of package names to stdout -if [ $# -lt 1 ]; then - echo "Usage: $0 [base-ref] [head-ref]" >&2 - exit 1 -fi - -RELEASE_TYPE=$1 -BASE_REF="${2:-origin/main}" -HEAD_REF="${3:-HEAD}" +BASE_REF="${1:-origin/main}" +HEAD_REF="${2:-HEAD}" -# Set the grep pattern based on release type -case "$RELEASE_TYPE" in - program-libs) - GREP_PATTERN='program-libs/' - ;; - sdk-libs) - GREP_PATTERN='(sdk-libs|program-tests/merkle-tree|sparse-merkle-tree|prover)/' - ;; - *) - echo "Error: Release type must be 'program-libs' or 'sdk-libs'" >&2 - exit 1 - ;; -esac +# Scan all lib directories +GREP_PATTERN='(program-libs|sdk-libs|prover/client|sparse-merkle-tree)/' # Fetch if comparing against remote refs if [[ "$BASE_REF" == origin/* ]]; then @@ -50,7 +32,7 @@ else DIFF_ARGS=("$BASE_REF...$HEAD_REF") fi -# Get list of changed Cargo.toml files in the specified directory +# Get list of changed Cargo.toml files in the specified directories for file in $(git diff "${DIFF_ARGS[@]}" --name-only -- '**/Cargo.toml' | grep -E "$GREP_PATTERN"); do # Extract old and new version from the diff versions=$(git diff "${DIFF_ARGS[@]}" -- "$file" | grep -E '^\+version|^-version' | grep -v '+++\|---') @@ -69,7 +51,7 @@ for file in $(git diff "${DIFF_ARGS[@]}" --name-only -- '**/Cargo.toml' | grep - done if [ ${#PACKAGES[@]} -eq 0 ]; then - echo "No packages with version changes detected in $RELEASE_TYPE" >&2 + echo "No packages with version changes detected" >&2 exit 1 fi diff --git a/scripts/release/find-dependents.sh b/scripts/release/find-dependents.sh new file mode 100755 index 0000000000..20e798da87 --- /dev/null +++ b/scripts/release/find-dependents.sh @@ -0,0 +1,320 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Find all packages that need version bumps when releasing a given package +# Usage: ./scripts/release/find-dependents.sh [--all] +# Arguments: +# package-name: The package to find dependents for +# --all: Include all dependents, even if unchanged since last release +# Outputs: List of packages that need to be bumped +# +# This script checks BOTH directions: +# 1. Dependencies: packages that the input package depends on (must be released first) +# 2. Dependents: packages that depend on the input package (must be released after) + +if [ $# -lt 1 ]; then + echo "Usage: $0 [--all]" >&2 + echo "" >&2 + echo "Find all packages that need version bumps when releasing the given package." >&2 + echo "By default, only shows packages with changes since their last release." >&2 + echo "" >&2 + echo "Checks both directions:" >&2 + echo " - Dependencies (packages it depends on) - must be released first" >&2 + echo " - Dependents (packages that depend on it) - must be released after" >&2 + echo "" >&2 + echo "Options:" >&2 + echo " --all Include all packages, even if unchanged since last release" >&2 + exit 1 +fi + +ROOT_PACKAGE=$1 +SHOW_ALL=false +if [ "${2:-}" = "--all" ]; then + SHOW_ALL=true +fi + +# Scan all lib directories +SCAN_DIRS="program-libs sdk-libs prover/client sparse-merkle-tree" + +# Create temp files +DEPS_FILE=$(mktemp) +ALL_PKGS_FILE=$(mktemp) +VISITED_FILE=$(mktemp) +PKG_PATHS_FILE=$(mktemp) +trap "rm -f $DEPS_FILE $ALL_PKGS_FILE $VISITED_FILE $PKG_PATHS_FILE" EXIT + +# Find all Cargo.toml files and build package path map +CARGO_FILES=$(find $SCAN_DIRS -name "Cargo.toml" 2>/dev/null) + +# Build dependency map and package paths +for cargo_toml in $CARGO_FILES; do + # Get the package name from this Cargo.toml + pkg_name=$(grep '^name = ' "$cargo_toml" 2>/dev/null | head -1 | sed 's/name = "\([^"]*\)".*/\1/') + + if [ -z "$pkg_name" ]; then + continue + fi + + # Store package path (directory containing Cargo.toml) + pkg_dir=$(dirname "$cargo_toml") + echo "$pkg_name:$pkg_dir" >> "$PKG_PATHS_FILE" + + # Find all light-* dependencies in this Cargo.toml + deps=$(grep -E '^light-[a-zA-Z0-9_-]+ *= *\{' "$cargo_toml" 2>/dev/null || true) + + if [ -n "$deps" ]; then + echo "$deps" | while read -r line; do + # Extract dependency name + dep_name=$(echo "$line" | sed 's/^\([a-zA-Z0-9_-]*\).*/\1/') + + if [ -n "$dep_name" ] && [ "$dep_name" != "$pkg_name" ]; then + # Format: dependent:dependency (dependent depends on dependency) + echo "$pkg_name:$dep_name" + fi + done >> "$DEPS_FILE" + fi +done + +# Check if the root package exists +pkg_exists=false +for cargo_toml in $CARGO_FILES; do + pkg_name=$(grep '^name = ' "$cargo_toml" 2>/dev/null | head -1 | sed 's/name = "\([^"]*\)".*/\1/') + if [ "$pkg_name" = "$ROOT_PACKAGE" ]; then + pkg_exists=true + break + fi +done + +if [ "$pkg_exists" = false ]; then + echo "Error: Package '$ROOT_PACKAGE' not found in: $SCAN_DIRS" >&2 + exit 1 +fi + +# Function to get the last release tag for a package +get_last_release_tag() { + local pkg=$1 + # Tags are in format: package-name-vX.Y.Z + git tag -l "${pkg}-v*" 2>/dev/null | sort -V | tail -1 +} + +# Function to get package directory +get_pkg_dir() { + local pkg=$1 + grep "^${pkg}:" "$PKG_PATHS_FILE" 2>/dev/null | head -1 | cut -d: -f2 +} + +# Function to check if package has changes since last release +has_changes_since_release() { + local pkg=$1 + local pkg_dir=$(get_pkg_dir "$pkg") + + if [ -z "$pkg_dir" ]; then + # Can't find package dir, assume it has changes + return 0 + fi + + local last_tag=$(get_last_release_tag "$pkg") + + if [ -z "$last_tag" ]; then + # No previous release, needs to be released + echo "new" + return 0 + fi + + # Check if there are any commits affecting this package since the last tag + local changes=$(git log "${last_tag}..HEAD" --oneline -- "$pkg_dir" 2>/dev/null | head -1) + + if [ -n "$changes" ]; then + echo "changed" + return 0 + else + echo "unchanged" + return 1 + fi +} + +# Recursive function to find all dependents (packages that depend on pkg) +find_dependents() { + local pkg=$1 + + # Skip if already visited + if grep -q "^dependents:${pkg}$" "$VISITED_FILE" 2>/dev/null; then + return + fi + echo "dependents:$pkg" >> "$VISITED_FILE" + + # Find direct dependents + if [ -s "$DEPS_FILE" ]; then + local dependents=$(grep ":${pkg}$" "$DEPS_FILE" 2>/dev/null | cut -d: -f1 | sort -u || true) + + for dependent in $dependents; do + echo "$dependent" >> "$ALL_PKGS_FILE" + find_dependents "$dependent" + done + fi +} + +# Recursive function to find all dependencies (packages that pkg depends on) +find_dependencies() { + local pkg=$1 + + # Skip if already visited + if grep -q "^dependencies:${pkg}$" "$VISITED_FILE" 2>/dev/null; then + return + fi + echo "dependencies:$pkg" >> "$VISITED_FILE" + + # Find direct dependencies + if [ -s "$DEPS_FILE" ]; then + local dependencies=$(grep "^${pkg}:" "$DEPS_FILE" 2>/dev/null | cut -d: -f2 | sort -u || true) + + for dependency in $dependencies; do + echo "$dependency" >> "$ALL_PKGS_FILE" + find_dependencies "$dependency" + done + fi +} + +# Add the root package +echo "$ROOT_PACKAGE" >> "$ALL_PKGS_FILE" + +# Find both directions +find_dependencies "$ROOT_PACKAGE" +find_dependents "$ROOT_PACKAGE" + +# Get unique list of all packages +ALL_PACKAGES=$(sort -u "$ALL_PKGS_FILE") + +# Analyze and categorize packages +echo "Analyzing packages for changes since last release..." +echo "" + +CHANGED_DEPS="" +UNCHANGED_DEPS="" +NEW_DEPS="" +CHANGED_DEPENDENTS="" +UNCHANGED_DEPENDENTS="" +NEW_DEPENDENTS="" +ROOT_STATUS="" + +# Get dependencies and dependents lists for categorization +DEPENDENCIES=$(grep "^${ROOT_PACKAGE}:" "$DEPS_FILE" 2>/dev/null | cut -d: -f2 | sort -u || true) +# Recursively get all dependencies +ALL_DEPENDENCIES="" +for dep in $DEPENDENCIES; do + ALL_DEPENDENCIES="$ALL_DEPENDENCIES $dep" + # Add transitive dependencies + transitive=$(grep "^${dep}:" "$DEPS_FILE" 2>/dev/null | cut -d: -f2 | sort -u || true) + ALL_DEPENDENCIES="$ALL_DEPENDENCIES $transitive" +done +ALL_DEPENDENCIES=$(echo $ALL_DEPENDENCIES | tr ' ' '\n' | sort -u | tr '\n' ' ') + +for pkg in $ALL_PACKAGES; do + status=$(has_changes_since_release "$pkg" || true) + last_tag=$(get_last_release_tag "$pkg") + + # Determine if this is the root, a dependency, or a dependent + if [ "$pkg" = "$ROOT_PACKAGE" ]; then + category="root" + ROOT_STATUS="$status" + ROOT_TAG="$last_tag" + elif echo "$ALL_DEPENDENCIES" | grep -qw "$pkg"; then + category="dependency" + else + category="dependent" + fi + + if [ "$status" = "new" ]; then + if [ "$category" = "dependency" ]; then + NEW_DEPS="$NEW_DEPS $pkg" + elif [ "$category" = "dependent" ]; then + NEW_DEPENDENTS="$NEW_DEPENDENTS $pkg" + fi + if [ "$category" != "root" ]; then + echo " [NEW] $pkg (no previous release) [$category]" + fi + elif [ "$status" = "changed" ]; then + if [ "$category" = "dependency" ]; then + CHANGED_DEPS="$CHANGED_DEPS $pkg" + elif [ "$category" = "dependent" ]; then + CHANGED_DEPENDENTS="$CHANGED_DEPENDENTS $pkg" + fi + if [ "$category" != "root" ]; then + echo " [CHANGED] $pkg (since $last_tag) [$category]" + fi + else + if [ "$category" = "dependency" ]; then + UNCHANGED_DEPS="$UNCHANGED_DEPS $pkg" + elif [ "$category" = "dependent" ]; then + UNCHANGED_DEPENDENTS="$UNCHANGED_DEPENDENTS $pkg" + fi + if [ "$SHOW_ALL" = true ] && [ "$category" != "root" ]; then + echo " [--] $pkg (unchanged since $last_tag) [$category]" + fi + fi +done + +echo "" +echo "========================================" +echo "Summary for releasing '$ROOT_PACKAGE':" +echo "========================================" +echo "" + +# Show root package status +if [ "$ROOT_STATUS" = "new" ]; then + echo "Target package: $ROOT_PACKAGE [NEW - no previous release]" +elif [ "$ROOT_STATUS" = "changed" ]; then + echo "Target package: $ROOT_PACKAGE [CHANGED since $ROOT_TAG]" +else + echo "Target package: $ROOT_PACKAGE [UNCHANGED since $ROOT_TAG]" +fi +echo "" + +# Show dependencies that need bumps +DEPS_NEED_BUMP="$NEW_DEPS $CHANGED_DEPS" +DEPS_NEED_BUMP=$(echo $DEPS_NEED_BUMP | tr ' ' '\n' | grep -v '^$' | sort -u | tr '\n' ' ' || true) + +if [ -n "$(echo $DEPS_NEED_BUMP | tr -d ' ')" ]; then + DEPS_COUNT=$(echo $DEPS_NEED_BUMP | wc -w | tr -d ' ') + echo "DEPENDENCIES that need release FIRST ($DEPS_COUNT):" + for pkg in $DEPS_NEED_BUMP; do + echo " $pkg" + done + echo "" +fi + +# Show dependents that need bumps +DEPENDENTS_NEED_BUMP="$NEW_DEPENDENTS $CHANGED_DEPENDENTS" +DEPENDENTS_NEED_BUMP=$(echo $DEPENDENTS_NEED_BUMP | tr ' ' '\n' | grep -v '^$' | sort -u | tr '\n' ' ' || true) + +if [ -n "$(echo $DEPENDENTS_NEED_BUMP | tr -d ' ')" ]; then + DEPENDENTS_COUNT=$(echo $DEPENDENTS_NEED_BUMP | wc -w | tr -d ' ') + echo "DEPENDENTS that need release AFTER ($DEPENDENTS_COUNT):" + for pkg in $DEPENDENTS_NEED_BUMP; do + echo " $pkg" + done + echo "" +fi + +# Combined list for release +ALL_NEED_BUMP="$DEPS_NEED_BUMP $ROOT_PACKAGE $DEPENDENTS_NEED_BUMP" +ALL_NEED_BUMP=$(echo $ALL_NEED_BUMP | tr ' ' '\n' | grep -v '^$' | sort -u | tr '\n' ' ' || true) + +if [ -n "$ALL_NEED_BUMP" ]; then + TOTAL_COUNT=$(echo $ALL_NEED_BUMP | wc -w | tr -d ' ') + echo "----------------------------------------" + echo "ALL packages to bump ($TOTAL_COUNT total):" + echo "$ALL_NEED_BUMP" + echo "" +fi + +# Show unchanged counts +UNCHANGED_DEPS_COUNT=$(echo "$UNCHANGED_DEPS" | wc -w | tr -d ' ') +UNCHANGED_DEPENDENTS_COUNT=$(echo "$UNCHANGED_DEPENDENTS" | wc -w | tr -d ' ') +TOTAL_UNCHANGED=$((UNCHANGED_DEPS_COUNT + UNCHANGED_DEPENDENTS_COUNT)) + +if [ "$TOTAL_UNCHANGED" -gt 0 ] && [ "$SHOW_ALL" = false ]; then + echo "($TOTAL_UNCHANGED packages unchanged since last release - use --all to see)" +fi + +exit 0 diff --git a/scripts/release/validate-packages.sh b/scripts/release/validate-packages.sh index 4ab19e579f..82804f6fcd 100755 --- a/scripts/release/validate-packages.sh +++ b/scripts/release/validate-packages.sh @@ -3,11 +3,10 @@ set -euo pipefail # Validate or publish packages using cargo-release # Usage: -# ./scripts/validate-packages.sh [base-ref] [head-ref] # Dry-run validation -# ./scripts/validate-packages.sh --execute [base-ref] [head-ref] # Actual publish +# ./scripts/release/validate-packages.sh [base-ref] [head-ref] # Dry-run validation +# ./scripts/release/validate-packages.sh --execute [base-ref] [head-ref] # Actual publish # Arguments: # --execute: Actually publish to crates.io (default: dry-run only) -# release-type: Type of release (program-libs or sdk-libs) # base-ref: Base reference to compare against (default: origin/main) # head-ref: Head reference to compare (default: HEAD) # Exits with 0 on success, 1 on failure @@ -21,22 +20,15 @@ if [ "${1:-}" = "--execute" ]; then shift fi -if [ $# -lt 1 ]; then - echo "Usage: $0 [--execute] [base-ref] [head-ref]" >&2 - exit 1 -fi - -RELEASE_TYPE=$1 -BASE_REF="${2:-origin/main}" -HEAD_REF="${3:-HEAD}" +BASE_REF="${1:-origin/main}" +HEAD_REF="${2:-HEAD}" echo "Detecting packages with version changes..." -echo "Release type: $RELEASE_TYPE" echo "Comparing: $BASE_REF...$HEAD_REF" echo "" # Detect packages using the detection script -PACKAGES_STRING=$("$SCRIPT_DIR/detect-version-changes.sh" "$RELEASE_TYPE" "$BASE_REF" "$HEAD_REF") +PACKAGES_STRING=$("$SCRIPT_DIR/detect-version-changes.sh" "$BASE_REF" "$HEAD_REF") # Convert to array read -ra PACKAGES <<< "$PACKAGES_STRING" @@ -48,17 +40,55 @@ else fi echo "Packages: ${PACKAGES[*]}" -# Build package args for cargo-release +# Check that all dependents are included in the release +echo "" +echo "Checking that all dependents are included..." +if ! "$SCRIPT_DIR/check-dependents.sh" "${PACKAGES[@]}"; then + echo "ERROR: Dependent packages are missing from the release" >&2 + exit 1 +fi +echo "" + +# Function to check if package is new (no previous release tag) +is_new_package() { + local pkg=$1 + local tag=$(git tag -l "${pkg}-v*" 2>/dev/null | head -1) + [ -z "$tag" ] +} + +# Build package args, excluding new packages for dry-run PACKAGE_ARGS="" +NEW_PACKAGES="" +EXISTING_PACKAGES="" for pkg in "${PACKAGES[@]}"; do - PACKAGE_ARGS="$PACKAGE_ARGS -p $pkg" + if is_new_package "$pkg"; then + NEW_PACKAGES="$NEW_PACKAGES $pkg" + else + EXISTING_PACKAGES="$EXISTING_PACKAGES $pkg" + PACKAGE_ARGS="$PACKAGE_ARGS -p $pkg" + fi done +if [ -n "$NEW_PACKAGES" ]; then + echo "New packages (skipped in dry-run):$NEW_PACKAGES" + echo "" +fi + echo "" if [ -n "$EXECUTE_FLAG" ]; then + # For actual publish, include all packages + PACKAGE_ARGS="" + for pkg in "${PACKAGES[@]}"; do + PACKAGE_ARGS="$PACKAGE_ARGS -p $pkg" + done echo "Running: cargo check (all packages) then cargo publish $PACKAGE_ARGS --no-verify" else - echo "Running: cargo check (all packages) then cargo publish $PACKAGE_ARGS --dry-run --allow-dirty --no-verify" + if [ -z "$PACKAGE_ARGS" ]; then + echo "All packages are new - skipping dry-run validation" + echo "Compilation check will still run" + else + echo "Running: cargo check (all packages) then cargo publish $PACKAGE_ARGS --dry-run --allow-dirty --no-verify" + fi fi echo "----------------------------------------" @@ -74,16 +104,47 @@ for pkg in "${PACKAGES[@]}"; do exit 1 fi done -echo "✓ All packages compile successfully" +echo "All packages compile successfully" echo "" +# Function to check if packages have interdependencies +has_interdependencies() { + local packages=("$@") + for pkg in "${packages[@]}"; do + # Find Cargo.toml for this package + local cargo_toml=$(find program-libs sdk-libs prover/client sparse-merkle-tree -name "Cargo.toml" -exec grep -l "^name = \"$pkg\"" {} \; 2>/dev/null | head -1) + if [ -z "$cargo_toml" ]; then + continue + fi + + # Check if this package depends on any other package in the release + for dep_pkg in "${packages[@]}"; do + if [ "$pkg" != "$dep_pkg" ]; then + if grep -q "^$dep_pkg *= *{" "$cargo_toml" 2>/dev/null; then + echo "Detected interdependency: $pkg depends on $dep_pkg" + return 0 + fi + fi + done + done + return 1 +} + # Then: Either publish or dry-run if [ -n "$EXECUTE_FLAG" ]; then # Publish with --no-verify to avoid cargo bug with unpublished deps cargo publish $PACKAGE_ARGS --no-verify else - # Dry-run validation - allow dirty state and skip verification - cargo publish $PACKAGE_ARGS --dry-run --allow-dirty --no-verify + # Check for interdependencies + if has_interdependencies "${PACKAGES[@]}"; then + echo "Skipping cargo publish dry-run (interdependent packages detected)" + echo "The compilation check above already validated the packages" + elif [ -z "$(echo $PACKAGE_ARGS | tr -d ' ')" ]; then + echo "Skipping cargo publish dry-run (all packages are new)" + else + # Dry-run validation - allow dirty state and skip verification + cargo publish $PACKAGE_ARGS --dry-run --allow-dirty --no-verify + fi fi if [ $? -eq 0 ]; then diff --git a/sdk-libs/client/Cargo.toml b/sdk-libs/client/Cargo.toml index 599bec023e..cdcb1ea347 100644 --- a/sdk-libs/client/Cargo.toml +++ b/sdk-libs/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-client" -version = "0.18.0" +version = "0.19.0" edition = "2021" license = "Apache-2.0" repository = "https://github.com/lightprotocol/light-protocol" diff --git a/sdk-libs/event/Cargo.toml b/sdk-libs/event/Cargo.toml index caf6d42fcc..1240a16af1 100644 --- a/sdk-libs/event/Cargo.toml +++ b/sdk-libs/event/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-event" -version = "0.3.0" +version = "0.4.0" description = "Event types and utilities for Light Protocol" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/sdk-libs/instruction-decoder-derive/Cargo.toml b/sdk-libs/instruction-decoder-derive/Cargo.toml index 6ba650d991..dbddaf7557 100644 --- a/sdk-libs/instruction-decoder-derive/Cargo.toml +++ b/sdk-libs/instruction-decoder-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-instruction-decoder-derive" -version = "0.1.0" +version = "0.2.0" description = "Derive macros for InstructionDecoder implementations in Light Protocol" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" @@ -15,8 +15,5 @@ quote = { workspace = true } sha2 = "0.10" syn = { workspace = true } -[dev-dependencies] -light-instruction-decoder = { workspace = true } - [lib] proc-macro = true diff --git a/sdk-libs/instruction-decoder/Cargo.toml b/sdk-libs/instruction-decoder/Cargo.toml index 54db503a20..46d2bcb8ed 100644 --- a/sdk-libs/instruction-decoder/Cargo.toml +++ b/sdk-libs/instruction-decoder/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-instruction-decoder" -version = "0.1.0" +version = "0.2.0" description = "Instruction decoder library for litsvm tests." repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/sdk-libs/macros/Cargo.toml b/sdk-libs/macros/Cargo.toml index 53f2622175..c61472a235 100644 --- a/sdk-libs/macros/Cargo.toml +++ b/sdk-libs/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-sdk-macros" -version = "0.18.1" +version = "0.19.0" description = "Macros for Programs using the Light SDK for ZK Compression " repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/sdk-libs/program-test/Cargo.toml b/sdk-libs/program-test/Cargo.toml index 9c0f8dcc0c..3db4d55a09 100644 --- a/sdk-libs/program-test/Cargo.toml +++ b/sdk-libs/program-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-program-test" -version = "0.18.0" +version = "0.19.0" description = "A fast local test environment for Solana programs using compressed accounts and tokens." license = "MIT" edition = "2021" diff --git a/sdk-libs/sdk-pinocchio/Cargo.toml b/sdk-libs/sdk-pinocchio/Cargo.toml index 69b636b705..1ae2f22ae6 100644 --- a/sdk-libs/sdk-pinocchio/Cargo.toml +++ b/sdk-libs/sdk-pinocchio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-sdk-pinocchio" -version = "0.18.0" +version = "0.19.0" description = "Rust SDK for ZK Compression on Solana with Pinocchio features" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/sdk-libs/sdk-types/Cargo.toml b/sdk-libs/sdk-types/Cargo.toml index 13eb248cab..7bad4c1b9b 100644 --- a/sdk-libs/sdk-types/Cargo.toml +++ b/sdk-libs/sdk-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-sdk-types" -version = "0.18.0" +version = "0.19.0" edition = "2021" license = "Apache-2.0" repository = "https://github.com/lightprotocol/light-protocol" diff --git a/sdk-libs/sdk/Cargo.toml b/sdk-libs/sdk/Cargo.toml index ffd4f3db1b..63adf65865 100644 --- a/sdk-libs/sdk/Cargo.toml +++ b/sdk-libs/sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "light-sdk" -version = "0.18.0" +version = "0.19.0" description = "Rust SDK for ZK Compression on Solana" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/sdk-libs/token-sdk/Cargo.toml b/sdk-libs/token-sdk/Cargo.toml index 00c297fd72..9da468d082 100644 --- a/sdk-libs/token-sdk/Cargo.toml +++ b/sdk-libs/token-sdk/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "light-token" -version = "0.3.0" +version = "0.4.0" edition = { workspace = true } -description = "SDK for compressed tokens on Light Protocol" +description = "SDK for Light Tokens" license = "Apache-2.0" repository = "https://github.com/Lightprotocol/light-protocol" diff --git a/sdk-libs/token-types/Cargo.toml b/sdk-libs/token-types/Cargo.toml index 2e773a14b5..a02ae8aeb5 100644 --- a/sdk-libs/token-types/Cargo.toml +++ b/sdk-libs/token-types/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "light-token-types" -version = "0.3.0" +version = "0.4.0" edition = "2021" -description = "ctoken and compressed token types for Light Protocol" +description = "Light token sdk types" license = "Apache-2.0" repository = "https://github.com/Lightprotocol/light-protocol"