Skip to content

Conversation

@RonTuretzky
Copy link
Contributor

No description provided.

Single workflow that handles:
- CI: build, test, format check
- Upgrade safety validation
- Testnet deploy on PR (optional)
- Mainnet deploy on merge to main (optional)
- 3-tier snapshot rotation after deploy

Configurable via inputs:
- deploy-on-pr: enable testnet deploy on pull requests
- deploy-on-main: enable mainnet deploy on push to main
- run-upgrade-safety: enable/disable upgrade validation
- check-formatting: enable/disable format check
- Add --rpc-url to forge verify-contract (required for --guess-constructor-args)
- Use process substitution instead of pipe to properly propagate exit codes
- Track verification failures and exit 1 if any contract fails after 3 attempts
- Add GitHub Actions ::error:: annotations for visibility
Resolves 'Multiple contracts found with the name' error by finding
the source file path and using format 'src/Contract.sol:Contract'
to disambiguate from lib/ dependencies.
The previous fallback path '$BASELINE/../previous' fails when the
baseline directory doesn't exist because '../' can't resolve through
a non-existent directory. Using '$upgrades-path/previous' directly
avoids this issue.
- Remove validation-script input (no longer needed)
- Use npx @openzeppelin/upgrades-core validate directly
- Loop through all baseline contracts automatically
- Consuming repos don't need ValidateUpgrade.s.sol anymore
- Generate ValidateUpgrades.s.sol dynamically at runtime
- Use forge script with --sig to pass contract names
- Cleanup generated script after validation
- More consistent with Foundry toolchain
flatten-snapshots now runs on push to main when:
- deploy-mainnet succeeds (normal post-deploy flattening)
- deploy-mainnet is skipped (baseline init without deployment)

This enables repos to establish their initial baseline without
requiring mainnet deployment to be enabled.
…t control

New input 'init-baseline-without-deploy' (default: false) controls whether
flatten-snapshots runs when deploy-mainnet is skipped (deploy-on-main: false).

This gives repos explicit control over baseline initialization behavior:
- false (default): baseline only created after successful mainnet deploy
- true: baseline can be initialized on merge even without deployment
Mainnet deployments (on merge to main):
- Creates GitHub Release with tag 'mainnet-{sha}'
- Includes contract addresses, Blockscout links, tx hashes
- Attaches flattened contract sources as assets
- Includes commit details (message, author)

Testnet deployments (on PRs):
- Posts deployment info as PR comment
- Creates GitHub Pre-release with tag 'testnet-{sha}'
- Includes PR reference and commit info

New inputs:
- create-release: boolean (default: true)
- release-prefix: string for custom tag prefixes
Removed testnet pre-release creation on PRs. Releases are now only
created for mainnet deployments (merge to main).

PR deployments still get:
- Deployment summary in workflow
- PR comment with contract addresses and tx links
Replaced network-config-path JSON file requirement with direct inputs:
- testnet-blockscout-url (default: Sepolia)
- testnet-name (default: Sepolia)
- mainnet-blockscout-url (default: Sepolia)
- mainnet-name (default: Sepolia)

This eliminates the need for deploy-networks.json in consuming repos.
Repos can override these inputs if deploying to different networks.
Validates that foundry.toml has required settings for deterministic bytecode:
- bytecode_hash = "none"
- cbor_metadata = false

Fails CI with clear error message if settings are missing.
Creates deployments/{network}/deployment.json with schema:
{
  "contracts": [
    { "sourcePathAndName": "src/Contract.sol:Contract", "address": "0x..." }
  ]
}

- Testnet: deployments/testnet/deployment.json
- Mainnet: deployments/{network-name}/deployment.json

Artifacts uploaded via actions/upload-artifact@v4 for downstream consumption.
Copy link
Contributor

@franrolotti franrolotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RonTuretzky Only three comments - workflow is green on saving-circles PR #72. We haven’t enabled/configured mainnet deploy yet (partly due to the testnet/mainnet secrets noted below).

type: string
default: ''

secrets:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deploy-testnet and deploy-mainnet use the same secrets.RPC_URL and secrets.PRIVATE_KEY. This causes trouble to deploy-on-pr (testnet) and deploy-on-main (mainnet) at the same time with different networks

Comment on lines 49 to 56
mainnet-blockscout-url:
description: 'Blockscout URL for mainnet verification and explorer links'
type: string
default: 'https://eth-sepolia.blockscout.com'
mainnet-name:
description: 'Mainnet network name for display'
type: string
default: 'Sepolia'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mainnet-blockscout-url (and mainnet-name) default to Sepolia

name: deployment-testnet
path: deployments/testnet/deployment.json

- name: Verify contracts on Blockscout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some repos may have [etherscan] in foundry.toml that references ${ETHERSCAN_API_KEY} and will fail unless they remove it (like i did with saving-circles). Might be worth documenting this in the consumer instructions. Just pointing it out.

Combines our enhancements with the change detection feature from main:
- Keeps skip-if-no-changes and contract-paths inputs from main
- Keeps detect-changes job from main
- Preserves our direct network config inputs (replaces JSON config)
- Preserves compiler config validation
- Preserves init-baseline-without-deploy flag
- Preserves release options and GitHub release creation
- Preserves dynamic upgrade validation script generation
- Preserves deployment artifact creation
- Preserves improved verification with fully qualified names
Split the monolithic _foundry-cicd.yml into focused, reusable workflows:
- _foundry-detect-changes.yml: Smart contract change detection
- _foundry-ci.yml: Build, test, format check, compiler validation
- _foundry-upgrade-safety.yml: Upgrade safety validation
- _foundry-deploy.yml: Deploy with verification (testnet/mainnet)
- _foundry-post-mainnet.yml: Flatten snapshots and create releases

The main _foundry-cicd.yml now acts as an orchestrator that calls
these sub-workflows, providing the same one-line import experience
for consumers while enabling granular imports for advanced use cases.
- Add foundry-upgradeable-counter-example as submodule at examples/foundry-counter
- Add working-directory input to all sub-workflows for flexible testing
- Create integration-test.yml that validates workflow changes against the example project
- Pass working-directory through orchestrator to all sub-workflows

Integration tests run automatically when workflow files change, validating
changes before they affect external consumers.
- Update README with comprehensive documentation:
  - Quick start for _foundry-cicd.yml orchestrator
  - All workflow inputs and secrets reference
  - Development section explaining integration testing
  - How local ./ refs test current branch before affecting consumers
  - Working with the submodule
  - Architecture decisions

- Update foundry-counter submodule to latest (6c84d40):
  - Clean ERC-7201 namespaced storage pattern
  - Upgrade-safe storage layout
Forge output structure strips src/ and test/upgrades/ prefixes:
- src/Counter.sol -> out/Counter.sol/Counter.json
- test/upgrades/baseline/Counter.sol -> out/baseline/Counter.sol/Counter.json

Updated contract path format to match Forge's output structure:
- Use Counter.sol:Counter instead of src/Counter.sol:Counter
- Use baseline/Counter.sol:Counter instead of test/upgrades/baseline/Counter.sol:Counter

This fixes the "No such file or directory" error when OZ Foundry Upgrades
tries to read contract artifacts.
@franrolotti
Copy link
Contributor

@RonTuretzky can we merge this?

@RonTuretzky
Copy link
Contributor Author

@RonTuretzky can we merge this?

I am unhappy with the state of this repo

RonTuretzky added a commit that referenced this pull request Jan 26, 2026
- Split shared PRIVATE_KEY/RPC_URL into separate TESTNET/MAINNET secrets to allow simultaneous testnet and mainnet deployments
- Add foundry.toml validation to detect and fail early if [etherscan] sections reference undefined ETHERSCAN_API_KEY environment variable
- Update README to document new separate testnet/mainnet secrets
- Network config file already has correct mainnet/testnet values (Ethereum vs Sepolia)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants