All versions - #30
Conversation
* Separated builder-stage rust image from final-stage using cli_rust_version * Added cli_rust_image_digest to publish matrix and workflow * Defaulted CLI_RUST_IMAGE_DIGEST to RUST_IMAGE_DIGEST when unset
* Made --rust-image-digest optional when unambiguous * Addressed PR review comments on rust digest resolution * Update CI to make --rust-image-digest optional
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR makes --rust-image-digest optional by resolving the digest from builds.json when unambiguous, and introduces a separate cli_rust_version/CLI_RUST_IMAGE_DIGEST path so the builder stage can use a different Rust base than the final image stage.
Changes:
- Add
builds.resolve_rust_digest()and updatebuild_image.pyto infer the Rust image digest (or require it only when ambiguous). - Extend the build matrix and CI publish workflow to pass
CLI_RUST_IMAGE_DIGEST, sourced from newcli_rust_versionmetadata inbuilds.json. - Update docs and tests to reflect the new digest-inference behavior.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_resolve_matrix.py | Updates matrix expectations to include the new cli_rust_image_digest key. |
| tests/unit/test_builds.py | Adds unit coverage for digest inference, explicit digest handling, and ambiguity errors. |
| tests/unit/test_build_image.py | Adds integration-ish tests for build_image.main() digest inference/ambiguity behavior. |
| scripts/resolve_matrix.py | Emits cli_rust_image_digest into the build matrix, defaulting to the row’s rust digest if unset. |
| scripts/lib/builds.py | Introduces resolve_rust_digest() with explicit/implicit digest resolution rules. |
| scripts/build_image.py | Makes --rust-image-digest optional, resolves digest internally, and supplies CLI_RUST_IMAGE_DIGEST. |
| builds.schema.json | Adds cli_rust_version to the schema for per-cli build Rust base pinning. |
| builds.json | Adds cli_rust_version for releases and expands rust pin history. |
| Dockerfile | Switches builder stage base to CLI_RUST_IMAGE_DIGEST (defaulting to RUST_IMAGE_DIGEST). |
| .github/workflows/publish.yml | Passes CLI_RUST_IMAGE_DIGEST from the resolved matrix into docker build args. |
| .github/workflows/build.yml | Stops passing --rust-image-digest to build/smoke steps. |
| README.md | Updates local-build instructions to omit --rust-image-digest unless needed. |
| RELEASE.md | Updates release instructions to reflect automatic digest resolution. |
| tags.csv | Adds tag statistics dataset. |
| tag_info.txt | Adds tag statistics summary writeup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pins = [pin for pin in entry.get("rust_versions", []) if label_of(pin) == label] | ||
| if not pins: | ||
| raise ValueError(f"stellar-cli {cli} is not declared with rust base {label} in builds.json") | ||
| if len(pins) > 1: | ||
| choices = ", ".join(digest_of(pin) for pin in pins) | ||
| raise ValueError( | ||
| f"stellar-cli {cli} declares multiple digests for rust base {label}; " | ||
| f"pass --rust-image-digest to select one of: {choices}" | ||
| ) | ||
| return digest_of(pins[0]) |
| entry = builds.find_cli(data, args.stellar_cli_version) | ||
| cli_rust_pin = entry.get("cli_rust_version") if entry else None | ||
| cli_rust_digest = builds.digest_of(cli_rust_pin) if cli_rust_pin else rust_digest |
| ./scripts/build_image.py \ | ||
| --stellar-cli-version "${{ steps.pair.outputs.cli }}" \ | ||
| --rust-version "${{ steps.pair.outputs.rust }}" \ | ||
| --rust-image-digest "${{ steps.pair.outputs.digest }}" | ||
| - name: smoke test | ||
| run: | | ||
| ./scripts/smoke_test_image.py \ | ||
| --image "${{ steps.pair.outputs.image }}" \ | ||
| --stellar-cli-version "${{ steps.pair.outputs.cli }}" \ | ||
| --rust-version "${{ steps.pair.outputs.rust }}" \ |
|
|
||
| # Expect the sole digest the fixture declares for this (cli, label), so the | ||
| # assertion can't drift from the digest build_image actually infers. | ||
| expected_digest = minimal_builds["stellar_cli_versions"][0]["rust_versions"][0].split("@", 1)[1] |
| rsver,cliver,count | ||
| 1.96.0,26.1.0,16 | ||
| 1.95.0,26.1.0,15 | ||
| 1.89.0,26.1.0,1 | ||
| 1.95.0,26.0.0,71 | ||
| 1.94.1,26.0.0,29 | ||
| 1.94.0,26.0.0,2 | ||
| 1.93.1,26.0.0,3 | ||
| 1.93.0,26.0.0,64 | ||
| 1.92.0,26.0.0,16 | ||
| 1.90.0,26.0.0,8 | ||
| 1.88.0,26.0.0,9 | ||
| 1.85.0,26.0.0,3 | ||
| 1.96.0-nightly,25.2.0,3 | ||
| 1.95.0,25.2.0,23 | ||
| 1.94.1,25.2.0,45 | ||
| 1.94.0,25.2.0,43 | ||
| 1.93.1,25.2.0,18 | ||
| 1.93.0,25.2.0,18 | ||
| 1.92.0,25.2.0,8 | ||
| 1.91.1,25.2.0,2 | ||
| 1.91.0-nightly,25.2.0,3 | ||
| 1.90.0-nightly,25.2.0,1 | ||
| 1.90.0,25.2.0,9 | ||
| 1.89.0,25.2.0,1 | ||
| 1.86.0,25.2.0,2 | ||
| 1.96.0-nightly,25.1.0,1 | ||
| 1.96.0,25.1.0,5 | ||
| 1.95.0-nightly,25.1.0,2 | ||
| 1.95.0,25.1.0,25 | ||
| 1.94.1,25.1.0,14 | ||
| 1.94.0,25.1.0,15 | ||
| 1.93.1,25.1.0,32 | ||
| 1.93.0,25.1.0,38 | ||
| 1.92.0,25.1.0,36 | ||
| 1.91.1,25.1.0,3 | ||
| 1.90.0,25.1.0,31 | ||
| 1.89.0,25.1.0,11 | ||
| 1.88.0,25.1.0,9 | ||
| 1.87.0,25.1.0,6 | ||
| 1.86.0,25.1.0,1 | ||
| 1.93.1,25.0.0,4 | ||
| 1.93.0,25.0.0,9 | ||
| 1.92.0,25.0.0,24 | ||
| 1.91.0-nightly,25.0.0,10 | ||
| 1.90.0,25.0.0,15 | ||
| 1.87.0,25.0.0,5 | ||
| 1.96.0-nightly,23.4.1,3 | ||
| 1.93.1,23.4.1,1 | ||
| 1.93.0,23.4.1,1 | ||
| 1.92.0,23.4.1,32 | ||
| 1.91.1,23.4.1,5 | ||
| 1.90.0,23.4.1,5 | ||
| 1.89.0,23.4.1,1 | ||
| 1.86.0,23.4.1,2 | ||
| 1.85.0,23.4.1,4 | ||
| 1.95.0,23.4.0,5 | ||
| 1.93.1,23.4.0,2 | ||
| 1.93.0,23.4.0,9 | ||
| 1.92.0,23.4.0,14 | ||
| 1.91.1,23.4.0,12 | ||
| 1.90.0,23.4.0,1 | ||
| 1.89.0,23.4.0,9 | ||
| 1.88.0,23.4.0,2 | ||
| 1.85.0,23.4.0,2 | ||
| 1.93.1,23.3.0,2 | ||
| 1.92.0,23.3.0,15 | ||
| 1.91.1,23.3.0,28 | ||
| 1.90.0,23.3.0,1 | ||
| 1.89.0,23.3.0,2 | ||
| 1.88.0,23.3.0,3 | ||
| 1.85.0,23.3.0,2 | ||
| 1.84.1,23.3.0,1 | ||
| 1.84.0,23.3.0,40 | ||
| 1.81.0,23.3.0,1 | ||
| 1.95.0,23.2.1,1 | ||
| 1.91.1,23.2.1,26 | ||
| 1.90.0,23.2.1,16 | ||
| 1.89.0,23.2.1,1 | ||
| 1.87.0,23.2.1,2 | ||
| 1.86.0,23.2.1,5 | ||
| 1.85.0,23.2.1,1 | ||
| 1.94.0-nightly,23.2.0,9 | ||
| 1.94.0,23.2.0,36 | ||
| 1.92.0,23.2.0,2 | ||
| 1.91.1,23.2.0,9 | ||
| 1.90.0,23.2.0,4 | ||
| 1.88.0,23.2.0,1 | ||
| 1.97.0-nightly,"",1 | ||
| 1.96.0,"",9 | ||
| 1.95.0,"",50 | ||
| 1.94.1,"",40 | ||
| 1.94.0-nightly,"",3 | ||
| 1.94.0,"",55 | ||
| 1.93.1,"",66 | ||
| 1.93.0-nightly,"",23 | ||
| 1.93.0,"",96 | ||
| 1.92.0-nightly,"",23 | ||
| 1.92.0,"",103 | ||
| 1.91.1,"",108 | ||
| 1.91.0-nightly,"",24 | ||
| 1.91.0,"",69 | ||
| 1.90.0-nightly,"",5 | ||
| 1.90.0,"",109 | ||
| 1.89.0,"",153 | ||
| 1.88.0,"",127 | ||
| 1.87.0-nightly,"",10 | ||
| 1.87.0,"",145 | ||
| 1.86.0,"",138 | ||
| 1.85.1,"",33 | ||
| 1.85.0-nightly,"",2 | ||
| 1.85.0,"",81 | ||
| 1.84.1,"",39 | ||
| 1.84.0,"",41 | ||
| 1.83.0,"",40 | ||
| 1.82.0,"",134 | ||
| 1.81.0-nightly,"",1 | ||
| 1.81.0,"",260 | ||
| 1.80.1,"",37 | ||
| 1.80.0,"",60 | ||
| 1.79.0,"",109 | ||
| 1.78.0-nightly,"",2 | ||
| 1.78.0,"",86 | ||
| 1.77.2,"",48 | ||
| 1.77.1,"",9 | ||
| 1.77.0,"",13 | ||
| 1.76.0-nightly,"",30 | ||
| 1.76.0,"",81 | ||
| 1.75.0,"",45 | ||
| 1.74.1,"",52 | ||
| 1.74.0,"",15 | ||
| "","",11 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f0789d237
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| ./scripts/smoke_test_image.py \ | ||
| --image "${{ steps.pair.outputs.image }}" \ | ||
| --stellar-cli-version "${{ steps.pair.outputs.cli }}" \ | ||
| --rust-version "${{ steps.pair.outputs.rust }}" \ |
There was a problem hiding this comment.
Pass the digest to the smoke test
The smoke script still declares --rust-image-digest as a required argument (scripts/smoke_test_image.py), but this workflow now invokes it without that argument, so argparse exits before any smoke checks run. The resolve step already exports steps.pair.outputs.digest; pass it here or make the smoke script infer it, otherwise every CI build workflow run fails at this step.
Useful? React with 👍 / 👎.
| @@ -39,14 +39,12 @@ jobs: | |||
| ./scripts/build_image.py \ | |||
| --stellar-cli-version "${{ steps.pair.outputs.cli }}" \ | |||
| --rust-version "${{ steps.pair.outputs.rust }}" \ | |||
There was a problem hiding this comment.
Keep passing the selected digest to the build
Dropping the explicit digest makes the CI build depend on build_image.py inference, which only works while the selected rust label has exactly one pin. In the documented refresh case where builds.json appends a new digest for the same default label, newest_pair.py will still select the latest pin, but this command calls resolve_rust_digest(..., digest=None) and exits with “declares multiple digests” before building. Keep passing ${{ steps.pair.outputs.digest }} so refreshed base tags remain buildable.
Useful? React with 👍 / 👎.
| "cli_rust_version": "1.90.0-slim-bookworm@sha256:64232e656c058f4468e8d024e990acff04f0fd5a5c0a88a574dc37773d7325c9", | ||
| "ref": "08473ac20016c369067ce0dbca91d9595e72d6d4", | ||
| "rust_versions": [ | ||
| "1.85.0-slim-bookworm@sha256:1829c432be4a592f3021501334d3fcca24f238432b13306a4e62669dec538e52", |
There was a problem hiding this comment.
Add the omitted 23.3.0 Rust rows
This 23.3.0 entry omits stable Rust versions that the new source data says are present on mainnet: tags.csv lists 23.3.0 with Rust 1.84.1, 1.84.0 (40 contracts), and 1.81.0. Since resolve_matrix.py only publishes pairs declared in builds.json, those 42 stable mainnet contracts still won't get matching Docker images even though this change is intended to cover the stable cliver rows.
Useful? React with 👍 / 👎.
Build all versions found on mainnet and publish to my docker registry so I can try build steps.