-
Notifications
You must be signed in to change notification settings - Fork 0
feat(script): BuildScript base — regenerate and cut are separate entrypoints #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
d75fcc1
feat(script): BuildScript base — regenerate and cut are separate entr…
thedavidmeister 53edcd3
fix(script): build through the base, and freeze nothing into nothing
thedavidmeister 7316b38
fix(script): scope the slither unimplemented-functions finding to the…
thedavidmeister 4880714
fix(test): one contract per file
thedavidmeister File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // SPDX-License-Identifier: LicenseRef-DCL-1.0 | ||
| // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd | ||
| pragma solidity ^0.8.25; | ||
|
|
||
| import {Script} from "forge-std-1.16.1/src/Script.sol"; | ||
| import {LibSnapshot} from "../lib/LibSnapshot.sol"; | ||
|
|
||
| /// @title BuildScript | ||
| /// @notice Base for a repo's codegen script. Splits "regenerate the committed | ||
| /// generated files" from "cut this release's immutable record" into two | ||
| /// entrypoints, and owns both so a consumer cannot merge them back together. | ||
| /// | ||
| /// The split is the whole point. The snapshot tag derives from | ||
| /// `[package].version`, which release automation bumps on every publish. A | ||
| /// script that cut a snapshot as part of its ordinary build therefore opens a | ||
| /// `<tag>/` dir for a release nobody deployed, every time the version moves, | ||
| /// and the next regenerate-and-diff finds the tree dirty. `run()` and `cut()` | ||
| /// are concrete here precisely so a consumer implements the hooks and has | ||
| /// nowhere to cut from the path CI runs. | ||
| /// | ||
| /// Cutting stays independent of deploying. The frozen record carries the | ||
| /// creation code, and a Zoltu address is a pure function of it, so a deploy | ||
| /// reads the record rather than needing this script to broadcast — the deploy | ||
| /// then puts on-chain exactly the bytes that were frozen, instead of | ||
| /// re-deriving them. | ||
| abstract contract BuildScript is Script { | ||
| /// @notice Write this repo's generated files, e.g. via | ||
| /// `LibFs.buildFileForContract`. Runs on both entrypoints: cutting a record | ||
| /// of stale output would freeze a lie. | ||
| function build() internal virtual; | ||
|
|
||
| /// @notice The contracts whose generated files form this release's frozen | ||
| /// record. Empty for a repo that generates files but freezes none. | ||
| /// @return names The contract names. | ||
| function snapshotContractNames() internal view virtual returns (string[] memory names); | ||
|
|
||
| /// @notice Freeze this release's record. Virtual only so tests can observe | ||
| /// the dispatch; consumers are not expected to override it. | ||
| function freeze() internal virtual { | ||
| LibSnapshot.freezeSnapshot(vm, snapshotContractNames()); | ||
| } | ||
|
|
||
| /// @notice Regenerate the committed generated files, cutting nothing. This | ||
| /// is what CI's regenerate-and-diff runs, so it is inert with respect to | ||
| /// the frozen `<tag>/` dirs. | ||
| function run() external { | ||
| build(); | ||
| } | ||
|
|
||
| /// @notice Regenerate, then cut this release's record into | ||
| /// `src/generated/<tag>/`. A deliberate act, so it has its own entrypoint: | ||
| /// `forge script <path> --sig 'cut()'`. | ||
| function cut() external { | ||
| build(); | ||
| freeze(); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| // SPDX-License-Identifier: LicenseRef-DCL-1.0 | ||
| // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd | ||
| pragma solidity =0.8.25; | ||
|
|
||
| import {Test} from "forge-std-1.16.1/src/Test.sol"; | ||
| import {BuildScript} from "src/abstract/BuildScript.sol"; | ||
|
|
||
| /// @notice Counts the hooks instead of running them, so the entrypoints are | ||
| /// asserted on dispatch alone. The real `freeze` writes the tag dir named by | ||
| /// `[package].version` — shared state that `LibSnapshot.t.sol` also drives, and | ||
| /// forge runs test contracts concurrently, so touching it here would race | ||
| /// rather than test. | ||
| contract SpyBuildScript is BuildScript { | ||
| uint256 public builds; | ||
| uint256 public freezes; | ||
|
|
||
| function build() internal override { | ||
| builds++; | ||
| } | ||
|
|
||
| function snapshotContractNames() internal pure override returns (string[] memory names) { | ||
| names = new string[](0); | ||
| } | ||
|
|
||
| function freeze() internal override { | ||
| freezes++; | ||
| } | ||
| } | ||
|
|
||
| /// @title BuildScriptTest | ||
| contract BuildScriptTest is Test { | ||
| /// THE property the base exists to enforce. `run()` is the path CI takes on | ||
| /// every build; the tag follows `[package].version`, which release | ||
| /// automation bumps on every publish, so a `run()` that cut would open a | ||
| /// `<tag>/` dir for a release nobody deployed and dirty the tree. | ||
| function testRunBuildsAndCutsNothing() external { | ||
| SpyBuildScript s = new SpyBuildScript(); | ||
| s.run(); | ||
| assertEq(s.builds(), 1, "run did not build"); | ||
| assertEq(s.freezes(), 0, "the CI path cut a snapshot"); | ||
| } | ||
|
|
||
| /// Cutting regenerates first: freezing stale output would record a lie. | ||
| function testCutBuildsThenFreezes() external { | ||
| SpyBuildScript s = new SpyBuildScript(); | ||
| s.cut(); | ||
| assertEq(s.builds(), 1, "cut did not build"); | ||
| assertEq(s.freezes(), 1, "cut did not freeze"); | ||
| } | ||
|
|
||
| /// Each entrypoint is one pass, so a repeated dispatch is the caller's | ||
| /// choice rather than a hidden loop. | ||
| function testEntrypointsDoNotCompound() external { | ||
| SpyBuildScript s = new SpyBuildScript(); | ||
| s.run(); | ||
| s.run(); | ||
| s.cut(); | ||
| assertEq(s.builds(), 3, "builds per dispatch drifted"); | ||
| assertEq(s.freezes(), 1, "run freezes"); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.