name: Contracts - Build & Compile
on: workflow_call: inputs: runner: description: 'Runner type' required: false type: string default: 'ubuntu-latest' container_image: description: >- Run the job inside this image (e.g. ghcr.io/codehunters-io/ci-base-images:1.0.0-node). Empty = plain runner with actions/setup-node. A container already carrying the toolchain skips the per-run Node download and pins the version to the tag. required: false type: string default: '' node_version: description: 'Node.js version (ignored when container_image is set)' required: false type: string default: '20' package_manager: description: 'Package manager (npm, yarn, or pnpm)' required: false type: string default: 'pnpm' pnpm_version: description: 'pnpm version (used when package_manager: pnpm)' required: false type: string default: '10' run_size_check: description: 'Run hardhat-contract-sizer (strict mode fails if any contract > 24KB)' required: false type: boolean default: true artifact_retention_days: description: 'Days to retain compiled artifacts' required: false type: number default: 1
outputs: artifact_name: description: 'Name of uploaded build artifact' value: ${{ jobs.build.outputs.artifact_name }}
# Least privilege for what this workflow actually does. Without it the# job inherits whatever the calling repository's default happens to be,# which on older repositories is write-all.permissions: contents: read packages: read
jobs: build: name: Build & Compile runs-on: ${{ inputs.runner }} # `container:` takes an object or nothing at all, and there is no way to # write "no container" as a string. fromJSON('null') is how you say it. container: ${{ inputs.container_image != '' && fromJSON(format('{{"image":"{0}"}}', inputs.container_image)) || fromJSON('null') }} timeout-minutes: 15
outputs: artifact_name: contracts-build-${{ github.run_id }}
steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup pnpm if: inputs.package_manager == 'pnpm' && inputs.container_image == '' uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
- name: Setup Node.js ${{ inputs.node_version }} if: inputs.container_image == '' uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ inputs.node_version }} cache: ${{ inputs.package_manager }}
- name: Report toolchain (container) if: inputs.container_image != '' run: | echo "Container: ${{ inputs.container_image }}" node --version npm --version
- name: Install dependencies run: | case "${{ inputs.package_manager }}" in pnpm) pnpm install --frozen-lockfile ;; yarn) yarn install --frozen-lockfile ;; *) npm ci ;; esac
- name: Compile contracts run: | case "${{ inputs.package_manager }}" in pnpm) pnpm hardhat compile ;; yarn) yarn hardhat compile ;; *) npx hardhat compile ;; esac
echo "### Hardhat Compile" >> $GITHUB_STEP_SUMMARY echo "**Status:** Passed" >> $GITHUB_STEP_SUMMARY
- name: Contract size check if: inputs.run_size_check run: | case "${{ inputs.package_manager }}" in pnpm) pnpm hardhat size-contracts ;; yarn) yarn hardhat size-contracts ;; *) npx hardhat size-contracts ;; esac
echo "" >> $GITHUB_STEP_SUMMARY echo "### Contract Sizes" >> $GITHUB_STEP_SUMMARY echo "Strict mode enabled (24KB EIP-170 limit)." >> $GITHUB_STEP_SUMMARY
- name: Upload compiled artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: contracts-build-${{ github.run_id }} path: | artifacts/ cache/ typechain-types/ retention-days: ${{ inputs.artifact_retention_days }} if-no-files-found: warnContracts (Hardhat/Solidity)·Reusable workflow·on: workflow_call
Contracts Build
Contracts - Build & Compile
.github/workflows/contracts-build.yml