Release [amsterdam-full] full chains=all #27
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
| name: Release Workstream | |
| run-name: "Release [${{ inputs.workstream }}] ${{ inputs.parameter_filter != '' && 'partial' || 'full' }} chains=${{ inputs.chains || 'all' }}" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| workstream: | |
| description: "Workstream to release" | |
| required: true | |
| type: choice | |
| options: | |
| - osaka-repricings | |
| - amsterdam-repricings | |
| - osaka-full | |
| - amsterdam-full | |
| chains: | |
| description: "Comma-separated networks to run (leave empty for all workstream defaults)" | |
| required: false | |
| default: "" | |
| nethermind_image: | |
| description: "Nethermind Docker image" | |
| required: true | |
| default: "nethermindeth/nethermind:testing_build_block_with_opcode_tracing" | |
| eest_repo: | |
| description: "execution-specs repository" | |
| required: true | |
| default: "https://github.com/ethereum/execution-specs" | |
| eest_branch: | |
| description: "execution-specs branch" | |
| required: true | |
| default: "forks/amsterdam" | |
| eest_commit: | |
| description: "Pin execution-specs to a specific commit SHA (optional)" | |
| required: false | |
| default: "" | |
| gas_benchmark_values: | |
| description: "Override gas values (leave empty for workstream default)" | |
| required: false | |
| default: "" | |
| parameter_filter: | |
| description: "pytest -k filter expression (if set → partial regeneration)" | |
| required: false | |
| default: "" | |
| nethermind_extra_flags: | |
| description: "Extra Nethermind CLI flags" | |
| required: false | |
| default: "" | |
| push_to_db: | |
| description: "Upload traces metadata to PostgreSQL" | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| setup: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release_tag: ${{ steps.release.outputs.tag }} | |
| base_release_tag: ${{ steps.release.outputs.base_tag }} | |
| matrix: ${{ steps.workstream.outputs.matrix }} | |
| gas_benchmark_values: ${{ steps.workstream.outputs.gas_benchmark_values }} | |
| eest_mode: ${{ steps.workstream.outputs.eest_mode }} | |
| fork: ${{ steps.workstream.outputs.fork }} | |
| chainspec_file: ${{ steps.workstream.outputs.chainspec_file }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Resolve workstream defaults | |
| id: workstream | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # ── Per-workstream defaults ── | |
| case "${{ inputs.workstream }}" in | |
| osaka-repricings) | |
| DEFAULT_GAS="30,60,90,120,150,180,210,240,270,300" | |
| DEFAULT_EEST_MODE="repricing" | |
| DEFAULT_FORK="Osaka" | |
| DEFAULT_CHAINSPEC="" | |
| FULL_MATRIX='[ | |
| {"mode":"compute","chain":"mainnet"}, | |
| {"mode":"compute","chain":"perf-devnet-3"}, | |
| {"mode":"stateful","chain":"mainnet"}, | |
| {"mode":"stateful","chain":"perf-devnet-3"} | |
| ]' | |
| ;; | |
| amsterdam-repricings) | |
| DEFAULT_GAS="30,60,90,120,150,180,210,240,270,300" | |
| DEFAULT_EEST_MODE="repricing" | |
| DEFAULT_FORK="Amsterdam" | |
| DEFAULT_CHAINSPEC="" | |
| FULL_MATRIX='[ | |
| {"mode":"compute","chain":"mainnet","chainspec":"generator-amsterdam-mainnet.json"}, | |
| {"mode":"compute","chain":"perf-devnet-3","chainspec":"generator-amsterdam-perf-devnet-3.json"}, | |
| {"mode":"stateful","chain":"mainnet","chainspec":"generator-amsterdam-mainnet.json"}, | |
| {"mode":"stateful","chain":"perf-devnet-3","chainspec":"generator-amsterdam-perf-devnet-3.json"} | |
| ]' | |
| ;; | |
| osaka-full) | |
| DEFAULT_GAS="90,120" | |
| DEFAULT_EEST_MODE="" | |
| DEFAULT_FORK="Osaka" | |
| DEFAULT_CHAINSPEC="" | |
| FULL_MATRIX='[ | |
| {"mode":"compute","chain":"mainnet"}, | |
| {"mode":"compute","chain":"perf-devnet-3"}, | |
| {"mode":"stateful","chain":"mainnet"}, | |
| {"mode":"stateful","chain":"perf-devnet-3"} | |
| ]' | |
| ;; | |
| amsterdam-full) | |
| DEFAULT_GAS="90,120" | |
| DEFAULT_EEST_MODE="" | |
| DEFAULT_FORK="Amsterdam" | |
| DEFAULT_CHAINSPEC="" | |
| FULL_MATRIX='[ | |
| {"mode":"compute","chain":"mainnet","chainspec":"generator-amsterdam-mainnet.json"}, | |
| {"mode":"compute","chain":"perf-devnet-3","chainspec":"generator-amsterdam-perf-devnet-3.json"}, | |
| {"mode":"stateful","chain":"mainnet","chainspec":"generator-amsterdam-mainnet.json"}, | |
| {"mode":"stateful","chain":"perf-devnet-3","chainspec":"generator-amsterdam-perf-devnet-3.json"} | |
| ]' | |
| ;; | |
| *) | |
| echo "Unknown workstream: ${{ inputs.workstream }}" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| # ── Gas values override (input wins if non-empty) ── | |
| GAS_VALUES="${{ inputs.gas_benchmark_values }}" | |
| GAS_VALUES="${GAS_VALUES:-$DEFAULT_GAS}" | |
| # ── Filter matrix by chains if specified ── | |
| CHAINS_FILTER='${{ inputs.chains }}' | |
| if [[ -n "$CHAINS_FILTER" ]]; then | |
| JQ_FILTER=$(echo "$CHAINS_FILTER" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | jq -R . | jq -sc '.') | |
| MATRIX=$(echo "$FULL_MATRIX" | jq -c --argjson allowed "$JQ_FILTER" '[.[] | select(.chain as $c | $allowed | index($c))]') | |
| else | |
| MATRIX="$FULL_MATRIX" | |
| fi | |
| if [[ "$(echo "$MATRIX" | jq 'length')" -eq 0 ]]; then | |
| echo "Error: chains filter '$CHAINS_FILTER' matched nothing in the workstream matrix" >&2 | |
| exit 1 | |
| fi | |
| echo "matrix=$(echo "$MATRIX" | jq -c '{"include": .}')" >> "$GITHUB_OUTPUT" | |
| echo "gas_benchmark_values=$GAS_VALUES" >> "$GITHUB_OUTPUT" | |
| echo "eest_mode=$DEFAULT_EEST_MODE" >> "$GITHUB_OUTPUT" | |
| echo "fork=$DEFAULT_FORK" >> "$GITHUB_OUTPUT" | |
| echo "chainspec_file=$DEFAULT_CHAINSPEC" >> "$GITHUB_OUTPUT" | |
| echo "Workstream: ${{ inputs.workstream }}" | |
| echo " Fork: $DEFAULT_FORK" | |
| echo " EEST mode: ${DEFAULT_EEST_MODE:-(none)}" | |
| echo " Gas values: $GAS_VALUES" | |
| echo " Chainspec: ${DEFAULT_CHAINSPEC:-(built-in)}" | |
| echo " Matrix: $(echo "$MATRIX" | jq -c '.')" | |
| - name: Resolve version and manage release | |
| id: release | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| WORKSTREAM="${{ inputs.workstream }}" | |
| FILTER="${{ inputs.parameter_filter }}" | |
| if [[ -n "$FILTER" ]]; then | |
| REGEN_TYPE="partial" | |
| else | |
| REGEN_TYPE="full" | |
| fi | |
| TAG_PREFIX="${WORKSTREAM}-v" | |
| # ── Find latest release for this workstream ── | |
| RELEASES=$(gh release list --limit 100 --json tagName,isDraft \ | |
| --jq "[.[] | select(.tagName | startswith(\"${TAG_PREFIX}\"))]") | |
| if [[ "$(echo "$RELEASES" | jq 'length')" -eq 0 ]]; then | |
| MAJOR=0 | |
| MINOR=0 | |
| LATEST_TAG="" | |
| LATEST_IS_DRAFT="false" | |
| else | |
| LATEST=$(echo "$RELEASES" | jq -r --arg pfx "$TAG_PREFIX" ' | |
| sort_by(.tagName | ltrimstr($pfx) | split(".") | map(tonumber)) | last') | |
| LATEST_TAG=$(echo "$LATEST" | jq -r '.tagName') | |
| LATEST_IS_DRAFT=$(echo "$LATEST" | jq -r '.isDraft') | |
| VERSION_STR="${LATEST_TAG#"$TAG_PREFIX"}" | |
| MAJOR=$(echo "$VERSION_STR" | cut -d. -f1) | |
| MINOR=$(echo "$VERSION_STR" | cut -d. -f2) | |
| echo "Latest release: $LATEST_TAG (draft=$LATEST_IS_DRAFT)" | |
| fi | |
| # ── Draft exists → append to it ── | |
| if [[ "$LATEST_IS_DRAFT" == "true" ]]; then | |
| echo "Draft $LATEST_TAG exists — appending to it" | |
| echo "tag=$LATEST_TAG" >> "$GITHUB_OUTPUT" | |
| echo "base_tag=" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # ── No draft → create new version ── | |
| if [[ "$REGEN_TYPE" == "full" ]]; then | |
| NEW_MAJOR=$((MAJOR + 1)) | |
| NEW_TAG="${TAG_PREFIX}${NEW_MAJOR}.0.0" | |
| BASE_TAG="" | |
| else | |
| if [[ -z "$LATEST_TAG" ]]; then | |
| echo "Error: partial regeneration requires an existing release to build on" >&2 | |
| exit 1 | |
| fi | |
| NEW_MINOR=$((MINOR + 1)) | |
| NEW_TAG="${TAG_PREFIX}${MAJOR}.${NEW_MINOR}.0" | |
| BASE_TAG="$LATEST_TAG" | |
| fi | |
| echo "Creating release: $NEW_TAG (base=$BASE_TAG)" | |
| GAS_VALUES="${{ steps.workstream.outputs.gas_benchmark_values }}" | |
| EEST_MODE="${{ steps.workstream.outputs.eest_mode }}" | |
| FORK="${{ steps.workstream.outputs.fork }}" | |
| gh release create "$NEW_TAG" \ | |
| --draft \ | |
| --title "${WORKSTREAM} ${NEW_TAG#"$TAG_PREFIX"} (draft)" \ | |
| --notes "$(cat <<EOF | |
| ## Workstream: \`$WORKSTREAM\` | |
| **Version:** \`${NEW_TAG#"$TAG_PREFIX"}\` | |
| **Type:** ${REGEN_TYPE} regeneration | |
| ${BASE_TAG:+**Base:** \`$BASE_TAG\`} | |
| **Generated:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| **Branch:** ${{ github.ref_name }} | |
| **Triggered by:** ${{ github.actor }} | |
| ### Parameters | |
| | Parameter | Value | | |
| |-----------|-------| | |
| | Fork | \`${FORK}\` | | |
| | EEST mode | \`${EEST_MODE:-all}\` | | |
| | Nethermind image | \`${{ inputs.nethermind_image }}\` | | |
| | EEST branch | \`${{ inputs.eest_branch }}\` | | |
| | Gas benchmark values | \`${GAS_VALUES}\` | | |
| | Warmups | disabled | | |
| | Chains | \`${{ inputs.chains || 'all' }}\` | | |
| ${BASE_TAG:+| Parameter filter | \`${{ inputs.parameter_filter }}\` |} | |
| ### Artifacts | |
| Each mode/chain combination produces: | |
| - \`generated-tests-{mode}-{chain}.tar.gz\` — test fixtures | |
| - \`opcodes_tracing-{mode}-{chain}.json\` — opcode-level tracing data | |
| - \`run_metadata-{mode}-{chain}.json\` — build provenance | |
| EOF | |
| )" | |
| echo "tag=$NEW_TAG" >> "$GITHUB_OUTPUT" | |
| echo "base_tag=$BASE_TAG" >> "$GITHUB_OUTPUT" | |
| - name: Copy base release assets for partial regeneration | |
| if: ${{ inputs.parameter_filter != '' && steps.release.outputs.base_tag != '' }} | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| BASE_TAG="${{ steps.release.outputs.base_tag }}" | |
| NEW_TAG="${{ steps.release.outputs.tag }}" | |
| echo "Copying assets from $BASE_TAG → $NEW_TAG" | |
| rm -rf /tmp/base-assets | |
| mkdir -p /tmp/base-assets | |
| gh release download "$BASE_TAG" -D /tmp/base-assets --clobber | |
| for f in /tmp/base-assets/*; do | |
| echo " Copying $(basename "$f")" | |
| gh release upload "$NEW_TAG" "$f" --clobber | |
| done | |
| rm -rf /tmp/base-assets | |
| generate: | |
| needs: setup | |
| strategy: | |
| max-parallel: 1 | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.setup.outputs.matrix) }} | |
| uses: ./.github/workflows/generate-stateful-tests.yml | |
| with: | |
| mode: ${{ matrix.mode }} | |
| chain: ${{ matrix.chain }} | |
| nethermind_image: ${{ inputs.nethermind_image }} | |
| fork: ${{ needs.setup.outputs.fork }} | |
| chainspec_file: ${{ matrix.chainspec || needs.setup.outputs.chainspec_file }} | |
| eest_repo: ${{ inputs.eest_repo }} | |
| eest_branch: ${{ inputs.eest_branch }} | |
| eest_commit: ${{ inputs.eest_commit }} | |
| gas_benchmark_values: ${{ needs.setup.outputs.gas_benchmark_values }} | |
| gas_bump_count: "-1" | |
| parameter_filter: ${{ inputs.parameter_filter }} | |
| eest_mode: ${{ needs.setup.outputs.eest_mode }} | |
| generation_mode: "stateful_only" | |
| nethermind_extra_flags: ${{ inputs.nethermind_extra_flags }} | |
| warmup_snapshot_backend: "overlay" | |
| commit_results: "false" | |
| skip_artifacts: "false" | |
| push_to_db: ${{ format('{0}', inputs.push_to_db) }} | |
| release_tag: ${{ needs.setup.outputs.release_tag }} | |
| base_release_tag: ${{ needs.setup.outputs.base_release_tag }} | |
| secrets: inherit | |
| summary: | |
| needs: [setup, generate] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Update release notes with job results | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| TAG="${{ needs.setup.outputs.release_tag }}" | |
| if [[ -z "$TAG" ]]; then | |
| echo "No release tag — skipping summary" | |
| exit 0 | |
| fi | |
| RESULT="${{ needs.generate.result }}" | |
| case "$RESULT" in | |
| success) STATUS="All generation jobs completed successfully." ;; | |
| failure) STATUS="One or more generation jobs failed. Check individual run logs." ;; | |
| *) STATUS="Generation finished with status: $RESULT" ;; | |
| esac | |
| REPO="${{ github.repository }}" | |
| EXISTING_NOTES=$(gh release view "$TAG" --repo "$REPO" --json body --jq '.body' 2>/dev/null || echo "") | |
| gh release edit "$TAG" --repo "$REPO" --notes "$(cat <<EOF | |
| ${EXISTING_NOTES} | |
| ### Status | |
| ${STATUS} | |
| **Completed:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| EOF | |
| )" |