diff --git a/.github/scripts/check-diff-changeset.sh b/.github/scripts/check-diff-changeset.sh index c55b02b62db..10756a6b2fc 100755 --- a/.github/scripts/check-diff-changeset.sh +++ b/.github/scripts/check-diff-changeset.sh @@ -1,7 +1,8 @@ #!/bin/bash # Analyzes a diff between two directories and validates changeset requirements -# Usage: check-diff-changeset.sh +# Usage: check-diff-changeset.sh # analysis-type: bytecode | storage +# base-ref: git ref to compare changesets against (e.g., commit SHA) # # For bytecode: any change requires patch+ # For storage: additions require minor+, removals require major @@ -11,9 +12,10 @@ set -euo pipefail ANALYSIS_TYPE=${1:-} BASE_DIR=${2:-} HEAD_DIR=${3:-} +BASE_REF=${4:-} -if [ -z "$ANALYSIS_TYPE" ] || [ -z "$BASE_DIR" ] || [ -z "$HEAD_DIR" ]; then - echo "Usage: check-diff-changeset.sh " +if [ -z "$ANALYSIS_TYPE" ] || [ -z "$BASE_DIR" ] || [ -z "$HEAD_DIR" ] || [ -z "$BASE_REF" ]; then + echo "Usage: check-diff-changeset.sh " exit 1 fi @@ -91,7 +93,7 @@ echo "$CHANGE_DESC detected." echo "" # Check for adequate changeset -if "$SCRIPT_DIR/check-solidity-changeset.sh" "$REQUIRED_LEVEL"; then +if "$SCRIPT_DIR/check-solidity-changeset.sh" "$REQUIRED_LEVEL" "$BASE_REF"; then echo "" echo "$CHANGE_DESC are permitted with the existing changeset." exit 0 diff --git a/.github/scripts/check-solidity-changeset.sh b/.github/scripts/check-solidity-changeset.sh index 1b3d2da4985..839e300bce2 100755 --- a/.github/scripts/check-solidity-changeset.sh +++ b/.github/scripts/check-solidity-changeset.sh @@ -1,36 +1,59 @@ #!/bin/bash # Checks if @hyperlane-xyz/core has a changeset at or above the required level -# Usage: check-solidity-changeset.sh +# Usage: check-solidity-changeset.sh # Levels: patch < minor < major # Exit 0 if adequate changeset exists, exit 1 otherwise +# +# Note: This parses .changeset/*.md files directly instead of using the changeset CLI +# because the CLI requires git history (merge-base) which fails in shallow clones. +# See: https://github.com/changesets/changesets/issues/700 +# +# Only changesets added since base-ref are checked, ensuring we validate +# changesets introduced by the current PR, not pre-existing ones. set -euo pipefail REQUIRED_LEVEL=${1:-} +BASE_REF=${2:-} PACKAGE="@hyperlane-xyz/core" -if [ -z "$REQUIRED_LEVEL" ]; then - echo "Usage: check-solidity-changeset.sh " +if [ -z "$REQUIRED_LEVEL" ] || [ -z "$BASE_REF" ]; then + echo "Usage: check-solidity-changeset.sh " exit 1 fi -# Get changeset status as JSON -# Note: changeset status --output requires a path relative to repo root -STATUS_FILE=".changeset-status-$$.json" -trap "rm -f $STATUS_FILE" EXIT -# changeset status exits non-zero when there are pending changesets, so ignore exit code -pnpm changeset status --output "$STATUS_FILE" 2>/dev/null || true - -# Extract bump type for the package (only if it has explicit changesets, not transitive) -FOUND_LEVEL=$(jq -r --arg pkg "$PACKAGE" '.releases[] | select(.name == $pkg and (.changesets | length > 0)) | .type' "$STATUS_FILE") - -# Map levels to numbers +# Map levels to numbers for comparison level_to_num() { case "$1" in patch) echo 1 ;; minor) echo 2 ;; major) echo 3 ;; *) echo 0 ;; esac } +# Get only newly added changeset files compared to base, then cat their contents +NEW_CHANGESETS=$(git diff --name-only --diff-filter=A "$BASE_REF" -- '.changeset/*.md' 2>/dev/null || true) +if [ -z "$NEW_CHANGESETS" ]; then + echo "No new changesets found in this PR." + echo "Run 'pnpm changeset' and select '$PACKAGE' with a '$REQUIRED_LEVEL' (or higher) bump." + exit 1 +fi + +# Read content of new changeset files +CHANGESET_CONTENT=$(echo "$NEW_CHANGESETS" | xargs cat 2>/dev/null || true) + +# Search for the package and extract bump level +# Format in changeset files: '@hyperlane-xyz/core': minor +FOUND_LEVEL="" +if echo "$CHANGESET_CONTENT" | grep -q "$PACKAGE"; then + # Found the package, extract the level (major > minor > patch) + if echo "$CHANGESET_CONTENT" | grep "$PACKAGE" | grep -q "major"; then + FOUND_LEVEL="major" + elif echo "$CHANGESET_CONTENT" | grep "$PACKAGE" | grep -q "minor"; then + FOUND_LEVEL="minor" + elif echo "$CHANGESET_CONTENT" | grep "$PACKAGE" | grep -q "patch"; then + FOUND_LEVEL="patch" + fi +fi + REQUIRED_NUM=$(level_to_num "$REQUIRED_LEVEL") FOUND_NUM=$(level_to_num "$FOUND_LEVEL") diff --git a/.github/workflows/bytecode-analysis.yml b/.github/workflows/bytecode-analysis.yml index 18af32ec46e..b2e0dd25494 100644 --- a/.github/workflows/bytecode-analysis.yml +++ b/.github/workflows/bytecode-analysis.yml @@ -66,4 +66,6 @@ jobs: # Compare outputs - name: Compare outputs - run: .github/scripts/check-diff-changeset.sh bytecode solidity/base-bytecode solidity/HEAD-bytecode + env: + BASE_REF: ${{ github.event.inputs.base || github.event.pull_request.base.sha }} + run: .github/scripts/check-diff-changeset.sh bytecode solidity/base-bytecode solidity/HEAD-bytecode "$BASE_REF" diff --git a/.github/workflows/interface-analysis.yml b/.github/workflows/interface-analysis.yml index df370a9002e..7cbcc50e3ae 100644 --- a/.github/workflows/interface-analysis.yml +++ b/.github/workflows/interface-analysis.yml @@ -64,6 +64,8 @@ jobs: # Compare outputs and check for appropriate changeset - name: Compare outputs + env: + BASE_REF: ${{ github.event.inputs.base || github.event.pull_request.base.sha }} run: | set +e pnpm -C solidity interface test-interface base-interface HEAD-interface @@ -76,7 +78,7 @@ jobs: elif [ "$EXIT_CODE" -eq 1 ]; then # Removals detected - require major changeset echo "" - if .github/scripts/check-solidity-changeset.sh major; then + if .github/scripts/check-solidity-changeset.sh major "$BASE_REF"; then echo "" echo "Interface removals are permitted with the existing changeset." exit 0 @@ -88,7 +90,7 @@ jobs: elif [ "$EXIT_CODE" -eq 2 ]; then # Additions only - require minor changeset echo "" - if .github/scripts/check-solidity-changeset.sh minor; then + if .github/scripts/check-solidity-changeset.sh minor "$BASE_REF"; then echo "" echo "Interface additions are permitted with the existing changeset." exit 0 diff --git a/.github/workflows/storage-analysis.yml b/.github/workflows/storage-analysis.yml index 9dc54ff350a..c30177590a0 100644 --- a/.github/workflows/storage-analysis.yml +++ b/.github/workflows/storage-analysis.yml @@ -67,4 +67,6 @@ jobs: # Compare outputs - name: Compare outputs - run: .github/scripts/check-diff-changeset.sh storage solidity/base-storage solidity/HEAD-storage + env: + BASE_REF: ${{ github.event.inputs.base || github.event.pull_request.base.sha }} + run: .github/scripts/check-diff-changeset.sh storage solidity/base-storage solidity/HEAD-storage "$BASE_REF" diff --git a/solidity/foundry.toml b/solidity/foundry.toml index 21e9804eecc..905b6641568 100644 --- a/solidity/foundry.toml +++ b/solidity/foundry.toml @@ -19,6 +19,7 @@ ignored_warnings_from = ['lib', 'test', 'contracts/test'] verbosity = 4 # disable metadata for bytecode comparison cbor_metadata = false +bytecode_hash = "none" [rpc_endpoints] mainnet = "${RPC_URL_MAINNET}"