Skip to content
Merged
171 changes: 166 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,100 @@ jobs:
if: github.event_name == 'merge_group'
uses: MetaMask/github-tools/.github/actions/check-skip-merge-queue@v1

detect-changes:
name: Detect changes
runs-on: ubuntu-latest
outputs:
has-code: ${{ steps.changes.outputs.has-code }}
has-ci: ${{ steps.changes.outputs.has-ci }}
has-lint-targets: ${{ steps.changes.outputs.has-lint-targets }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect change categories
id: changes
run: |
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then
# On pushes to main, always run everything
{
echo "has-code=true"
echo "has-ci=true"
echo "has-lint-targets=true"
} >> "$GITHUB_OUTPUT"
exit 0
fi

if [[ "${{ github.event_name }}" == "pull_request" ]]; then
BASE="${{ github.event.pull_request.base.sha }}"
elif [[ "${{ github.event_name }}" == "merge_group" ]]; then
BASE="${{ github.event.merge_group.base_sha }}"
else
echo "::error::Unexpected event type: ${{ github.event_name }}"
exit 1
fi

FILES=$(git diff --name-only "$BASE" HEAD)

HAS_CODE=false
HAS_CI=false
HAS_LINT_TARGETS=false

while IFS= read -r file; do
[[ -z "$file" ]] && continue

case "$file" in
# CI workflow files (also lint-worthy for prettier on .yml)
.github/workflows/*)
HAS_CI=true
HAS_LINT_TARGETS=true
;;
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
# Custom actions are test infrastructure — treat as code
.github/actions/*)
HAS_CI=true
HAS_CODE=true
HAS_LINT_TARGETS=true
;;
# Documentation (lint-worthy for prettier, but not code)
*.md|*.txt|docs/*|LICENSE*)
HAS_LINT_TARGETS=true
;;
# Config/tooling (lint-worthy but not code)
.eslintrc*|.prettierrc*|.editorconfig|.gitignore|.gitattributes|.nvmrc|.yarnrc*)
HAS_LINT_TARGETS=true
;;
# Everything else is code (source, tests, package.json, tsconfig, lockfile, etc.)
*)
HAS_CODE=true
HAS_LINT_TARGETS=true
;;
esac
done <<< "$FILES"

{
echo "has-code=$HAS_CODE"
echo "has-ci=$HAS_CI"
echo "has-lint-targets=$HAS_LINT_TARGETS"
} >> "$GITHUB_OUTPUT"

{
echo "## Change detection results"
echo "- has-code: $HAS_CODE"
echo "- has-ci: $HAS_CI"
echo "- has-lint-targets: $HAS_LINT_TARGETS"
echo "### Changed files"
echo '```'
echo "$FILES"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

check-workflows:
name: Check workflows
runs-on: ubuntu-latest
needs: check-skip-merge-queue
if: github.event_name != 'merge_group' || needs.check-skip-merge-queue.outputs.skip-merge-queue != 'true'
needs: [check-skip-merge-queue, detect-changes]
if: |
(github.event_name != 'merge_group' || needs.check-skip-merge-queue.outputs.skip-merge-queue != 'true')
&& (needs.detect-changes.outputs.has-ci == 'true' || needs.detect-changes.outputs.has-code == 'true')
steps:
- uses: actions/checkout@v6
- name: Download actionlint
Expand All @@ -43,7 +132,12 @@ jobs:

analyse-code:
name: Code scanner
needs: check-workflows
needs: [check-skip-merge-queue, check-workflows, detect-changes]
if: |
always()
&& needs.check-skip-merge-queue.outputs.skip-merge-queue != 'true'
&& needs.detect-changes.outputs.has-code == 'true'
&& needs.check-workflows.result != 'failure'
uses: ./.github/workflows/security-code-scanner.yml
permissions:
actions: read
Expand All @@ -55,9 +149,37 @@ jobs:

lint-build-test:
name: Lint, build, and test
needs: check-workflows
needs: [check-skip-merge-queue, check-workflows, detect-changes]
if: |
always()
&& needs.check-skip-merge-queue.outputs.skip-merge-queue != 'true'
&& needs.detect-changes.outputs.has-code == 'true'
&& needs.check-workflows.result != 'failure'
Comment thread
cursor[bot] marked this conversation as resolved.
uses: ./.github/workflows/lint-build-test.yml

lint-only:
name: Lint (no code changes)
runs-on: ubuntu-latest
needs: [detect-changes]
if: needs.detect-changes.outputs.has-code != 'true' && needs.detect-changes.outputs.has-lint-targets == 'true'
strategy:
matrix:
node-version: [24.x]
steps:
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v3
with:
is-high-risk-environment: false
node-version: ${{ matrix.node-version }}
- run: yarn lint
- name: Require clean working directory
shell: bash
run: |
if ! git diff --exit-code; then
echo "Working tree dirty at end of job"
exit 1
fi

coverage-report:
name: Coverage report
needs: lint-build-test
Expand Down Expand Up @@ -107,15 +229,54 @@ jobs:
all-jobs-complete:
name: All jobs complete
runs-on: ubuntu-latest
if: ${{ always() }}
needs:
- detect-changes
- check-workflows
- analyse-code
- lint-build-test
- lint-only
outputs:
passed: ${{ steps.set-output.outputs.passed }}
steps:
- name: Set passed output
id: set-output
run: echo "passed=true" >> "$GITHUB_OUTPUT"
run: |
# detect-changes must always succeed — without it we can't trust any outputs
if [[ "${{ needs.detect-changes.result }}" != "success" ]]; then
echo "detect-changes did not succeed"
exit 1
fi

HAS_CODE="${{ needs.detect-changes.outputs.has-code }}"
HAS_CI="${{ needs.detect-changes.outputs.has-ci }}"
HAS_LINT="${{ needs.detect-changes.outputs.has-lint-targets }}"

# If code changed, analyse-code and lint-build-test must have succeeded
if [[ "$HAS_CODE" == "true" ]]; then
if [[ "${{ needs.analyse-code.result }}" != "success" || "${{ needs.lint-build-test.result }}" != "success" ]]; then
echo "Code jobs did not succeed"
exit 1
fi
fi

# check-workflows runs for both CI and code changes; require it when either is present
if [[ "$HAS_CI" == "true" || "$HAS_CODE" == "true" ]]; then
if [[ "${{ needs.check-workflows.result }}" != "success" ]]; then
echo "check-workflows did not succeed"
exit 1
fi
fi

# If only lint targets changed (no code), lint-only must have succeeded
if [[ "$HAS_CODE" != "true" && "$HAS_LINT" == "true" ]]; then
if [[ "${{ needs.lint-only.result }}" != "success" ]]; then
echo "Lint-only job did not succeed"
exit 1
fi
fi

echo "passed=true" >> "$GITHUB_OUTPUT"
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.

all-jobs-pass:
name: All jobs pass
Expand Down
Loading