Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/scripts/tests/test_release_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,25 @@ def test_reusable_release_executors_have_no_implicit_inputs() -> None:
def test_registry_publish_authenticates_iii_installer() -> None:
body = (WORKFLOWS / "_publish-registry.yml").read_text()
assert "GITHUB_TOKEN: ${{ github.token }}" in body


def test_rust_binary_cache_is_keyed_by_frontend_bundle_digest() -> None:
jobs = workflow(WORKFLOWS / "_rust-binary.yml")["jobs"]
web_build = jobs["web-build"]
assert web_build["outputs"]["frontend_digest"] == "${{ steps.stage.outputs.frontend_digest }}"
assert web_build["outputs"]["frontends"] == "${{ steps.dirs.outputs.frontends }}"

stage = next(step for step in web_build["steps"] if step.get("name") == "Stage frontend bundles")
assert stage["id"] == "stage"
assert "frontend_digest=$digest" in stage["run"]
assert "git hash-object" in stage["run"]

build_steps = jobs["build"]["steps"]
cache = next(step for step in build_steps if step.get("uses") == "Swatinem/rust-cache@v2")
assert "needs.web-build.outputs.frontend_digest" in cache["with"]["key"]

verify = next(step for step in build_steps if step.get("name") == "Verify frontend bundle digest")
assert verify["if"] == "inputs.web_bundle"
assert verify["env"]["EXPECTED_DIGEST"] == "${{ needs.web-build.outputs.frontend_digest }}"
assert "git hash-object" in verify["run"]
assert '[[ "$actual" == "$EXPECTED_DIGEST" ]]' in verify["run"]
44 changes: 43 additions & 1 deletion .github/workflows/_rust-binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ jobs:
needs: [matrix]
if: inputs.web_bundle
runs-on: ubuntu-latest
outputs:
frontend_digest: ${{ steps.stage.outputs.frontend_digest }}
frontends: ${{ steps.dirs.outputs.frontends }}
steps:
- uses: actions/checkout@v5
with:
Expand Down Expand Up @@ -163,6 +166,7 @@ jobs:
done

- name: Stage frontend bundles
id: stage
env:
FRONTENDS: ${{ steps.dirs.outputs.frontends }}
run: |
Expand All @@ -177,6 +181,19 @@ jobs:
mkdir -p "$stage/$bundle"
cp -a "$bundle/dist" "$stage/$bundle/"
done
digest=$(
for bundle in "${bundles[@]}"; do
find "$bundle/dist" -type f -print
done \
| LC_ALL=C sort \
| while IFS= read -r file; do
printf '%s %s\n' "$(git hash-object "$file")" "$file"
done \
| git hash-object --stdin
)
[[ "$digest" =~ ^[0-9a-f]{40}$ ]]
echo "frontend_digest=$digest" >> "$GITHUB_OUTPUT"
echo "::notice::frontend bundle digest: $digest"

- name: Upload frontend bundles
uses: actions/upload-artifact@v6
Expand Down Expand Up @@ -245,7 +262,10 @@ jobs:
- name: Cache cargo registry & build
uses: Swatinem/rust-cache@v2
with:
key: ${{ inputs.bin_name }}-${{ matrix.target }}
# Cargo caches compiled include_str!/rust-embed output. Key UI
# releases by the generated bytes so a new dist/ can never restore
# a worker artifact that still embeds the previous bundle.
key: ${{ inputs.bin_name }}-${{ matrix.target }}${{ inputs.web_bundle && format('-frontend-{0}', needs.web-build.outputs.frontend_digest) || '' }}
# Without this, rust-cache defaults to the repo root, where there is no
# Cargo.toml — its `cargo metadata` exits 101 and the cache is never
# found or saved, so every build of every target ships cold.
Expand Down Expand Up @@ -274,6 +294,28 @@ jobs:
# any path-dependency crates with their own ui/dist).
path: ./

- name: Verify frontend bundle digest
if: inputs.web_bundle
shell: bash
env:
EXPECTED_DIGEST: ${{ needs.web-build.outputs.frontend_digest }}
FRONTENDS: ${{ needs.web-build.outputs.frontends }}
run: |
set -euo pipefail
IFS=, read -ra bundles <<< "$FRONTENDS"
actual=$(
for bundle in "${bundles[@]}"; do
test -d "$bundle/dist"
find "$bundle/dist" -type f -print
done \
| LC_ALL=C sort \
| while IFS= read -r file; do
printf '%s %s\n' "$(git hash-object "$file")" "$file"
done \
| git hash-object --stdin
)
[[ "$actual" == "$EXPECTED_DIGEST" ]]

- name: Build and upload binary
uses: taiki-e/upload-rust-binary-action@v1
env:
Expand Down
Loading