Skip to content
Open
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
17 changes: 13 additions & 4 deletions .github/workflows/rainix-copy-artifacts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ jobs:
if: hashFiles('soldeer.lock') != ''
run: nix develop github:rainlanguage/rainix/${{ env.RAINIX_SHA }}#sol-shell -c forge soldeer install
# Currency-check every committed generated artifact by re-running each
# consumer-provided codegen step. The final git diff fails if any
# committed file has drifted from its source. The build-meta.sh hook is
# consumer-provided codegen step. The final currency check fails if any
# committed file has drifted from its source, or if regeneration wrote a
# file the repo does not track. The build-meta.sh hook is
# consumer-supplied because rain meta build's invocation (input/output
# filenames, meta type) varies per repo.
- name: Regenerate meta artifacts
Expand Down Expand Up @@ -55,9 +56,17 @@ jobs:
run: ./script/build.sh
- name: Format (so generated artifacts match committed style)
run: nix develop github:rainlanguage/rainix/${{ env.RAINIX_SHA }}#sol-shell -c forge fmt
# Staging first is what makes this a whole-tree comparison. `git diff`
# alone reads tracked content only, so a regeneration that writes to a
# path nothing has committed yet — a renamed contract, an added artifact —
# is invisible to it, while the artifact it supersedes stays committed and
# frozen at whatever the consumer's `src/**` still imports. `git add --all`
# respects .gitignore, so out/, cache/ and dependencies/ contribute
# nothing, and every addition, deletion and edit reaches the diff.
- name: Assert committed artifacts match freshly built
run: |
if ! git diff --exit-code; then
echo "::error::Committed artifacts are stale. Regenerate (script/build-meta.sh, script/Build.sol, script/CopyArtifacts.sol, script/build.sh, forge fmt) and commit."
git add --all
if ! git diff --cached --exit-code; then
echo "::error::Committed artifacts are stale, or regeneration wrote a file that is not committed. Regenerate (script/build-meta.sh, script/Build.sol, script/CopyArtifacts.sol, script/build.sh, forge fmt) and commit."
exit 1
fi
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@
bats test/bats/devshell/default/prettier-bundle.test.bats
bats test/bats/action/rpc-preflight.test.bats
bats test/bats/action/prompt-cap.test.bats
bats test/bats/workflow/copy-artifacts-currency.test.bats
bats test/bats/task/skip-simulation.test.bats
bats test/bats/task/subgraph-build.test.bats
bats test/bats/task/subgraph-deploy-version.test.bats
Expand Down
76 changes: 76 additions & 0 deletions test/bats/workflow/copy-artifacts-currency.test.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
setup() {
repo_root="$BATS_TEST_DIRNAME/../../.."
workflow="$repo_root/.github/workflows/rainix-copy-artifacts.yaml"
assert_script="$(yq -r '.jobs["copy-artifacts"].steps[] | select(.name == "Assert committed artifacts match freshly built") | .run' "$workflow")"

consumer="$(mktemp -d)"
# A consumer checkout is the only git state the step reads, so the fixture
# owns its whole git environment: no ambient config, no ambient excludes.
export GIT_CONFIG_NOSYSTEM=1
export HOME="$consumer"
cd "$consumer" || return 1
git init -q -b main .
git config user.email rainix@example.com
git config user.name rainix
printf 'out/\ncache/\ndependencies/\n' >.gitignore
mkdir -p src/generated
printf 'library CodeGennable {}\n' >src/generated/CodeGennable.sol
git add --all
git commit -qm 'committed artifacts'
}

teardown() {
cd / || return 0
rm -rf "$consumer"
}

run_assert() {
bash -c "$assert_script"
}

@test "a checkout whose regeneration changed nothing passes" {
run run_assert

[ "$status" -eq 0 ]
}

@test "a committed artifact whose content drifted fails" {
printf 'library CodeGennable { uint256 constant X = 1; }\n' >src/generated/CodeGennable.sol

run run_assert

[ "$status" -eq 1 ]
[[ "$output" == *"CodeGennable.sol"* ]]
[[ "$output" == *"::error::"* ]]
}

@test "an artifact regenerated under a new name, leaving the old one committed, fails" {
printf 'library CodeGennableRenamed {}\n' >src/generated/CodeGennableRenamed.sol

run run_assert

[ "$status" -eq 1 ]
[[ "$output" == *"CodeGennableRenamed.sol"* ]]
[[ "$output" == *"::error::"* ]]
}

@test "a committed artifact that regeneration no longer emits fails" {
rm src/generated/CodeGennable.sol

run run_assert

[ "$status" -eq 1 ]
[[ "$output" == *"CodeGennable.sol"* ]]
[[ "$output" == *"::error::"* ]]
}

@test "build output the consumer gitignores passes" {
mkdir -p out cache dependencies
printf '{}\n' >out/CodeGennable.json
printf '{}\n' >cache/solidity-files-cache.json
printf 'library Dep {}\n' >dependencies/Dep.sol

run run_assert

[ "$status" -eq 0 ]
}
Loading