[CI] adapt .github/workflows/*.yml for MetaxGPU new #63
Workflow file for this run
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: Preflight Checks | |
| permissions: | |
| contents: read | |
| checks: read | |
| pull-requests: read | |
| on: | |
| push: | |
| branches: [dev, main, testbed] | |
| tags: ["v*"] | |
| pull_request: | |
| branches: [dev, main, testbed] | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| validate-pr-title: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| sparse-checkout: .claude/conventions | |
| sparse-checkout-cone-mode: false | |
| - name: Validate PR title format | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$EVENT_NAME" != "pull_request" ]]; then | |
| echo "Not a pull request event; skipping PR title validation." | |
| exit 0 | |
| fi | |
| source .claude/conventions/types.sh | |
| if [[ ! "$PR_TITLE" =~ $COMMIT_MSG_PATTERN ]]; then | |
| echo "::error::PR title does not follow TileOPs format." | |
| echo "Expected: [Type] description or [Type][Scope] description" | |
| echo "Types: $COMMIT_PR_TYPES" | |
| echo "Got: $PR_TITLE" | |
| exit 1 | |
| fi | |
| echo "PR title is valid: $PR_TITLE" | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| manifest: ${{ steps.filter.outputs.manifest }} | |
| benchmark: ${{ steps.filter.outputs.benchmark }} | |
| steps: | |
| - name: Detect relevant changed paths | |
| id: filter | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_NUMBER: ${{ github.event.pull_request.number || '' }} | |
| REPO: ${{ github.repository }} | |
| WORKFLOW_PATH: .github/workflows/preflight.yml | |
| run: | | |
| set -euo pipefail | |
| # Non-PR events (push to main, tags, manual dispatch) always run | |
| # both gated jobs — no base ref to diff against. | |
| if [[ "$EVENT_NAME" != "pull_request" ]]; then | |
| echo "manifest=true" >> "$GITHUB_OUTPUT" | |
| echo "benchmark=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Fail-open: if the API call errors out or returns nothing, run | |
| # everything. The optimization must never reduce CI reliability. | |
| if ! FILES=$(gh api --paginate "repos/$REPO/pulls/$PR_NUMBER/files" --jq '.[].filename' 2>&1); then | |
| echo "::warning::gh api failed; defaulting to run all gated jobs" | |
| echo "$FILES" | |
| echo "manifest=true" >> "$GITHUB_OUTPUT" | |
| echo "benchmark=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [[ -z "$FILES" ]]; then | |
| echo "::warning::no files returned; defaulting to run all gated jobs" | |
| echo "manifest=true" >> "$GITHUB_OUTPUT" | |
| echo "benchmark=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "Changed files in PR #$PR_NUMBER:" | |
| echo "$FILES" | |
| manifest=false | |
| benchmark=false | |
| while IFS= read -r f; do | |
| [[ -z "$f" ]] && continue | |
| case "$f" in | |
| tileops/manifest/*.yaml|tileops/manifest/__init__.py|scripts/validate_manifest.py|"$WORKFLOW_PATH") | |
| manifest=true | |
| ;; | |
| esac | |
| # `benchmark-contract-tests` runs `pytest benchmarks/tests`, which | |
| # imports `workloads.workload_base`, `tileops.manifest`, and reads | |
| # the per-family files under `tileops/manifest/*.yaml` via | |
| # `load_workloads()` / `workloads_to_params()`. Any of those layers | |
| # can break the contract tests, so include them all. | |
| case "$f" in | |
| benchmarks/*|workloads/*|tileops/manifest/*.yaml|tileops/manifest/__init__.py|"$WORKFLOW_PATH") | |
| benchmark=true | |
| ;; | |
| esac | |
| done <<< "$FILES" | |
| echo "manifest=$manifest" | |
| echo "benchmark=$benchmark" | |
| echo "manifest=$manifest" >> "$GITHUB_OUTPUT" | |
| echo "benchmark=$benchmark" >> "$GITHUB_OUTPUT" | |
| ci-gate: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| skip: ${{ steps.check.outputs.skip }} | |
| steps: | |
| - name: Check existing CI results for this SHA | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| EVENT_ACTION: ${{ github.event.action || '' }} | |
| TARGET_BRANCH: ${{ github.base_ref || '' }} | |
| IS_DRAFT: ${{ github.event.pull_request.draft || false }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$EVENT_NAME" != "pull_request" ]]; then | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [[ "$IS_DRAFT" == "true" ]]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| case "$TARGET_BRANCH" in | |
| dev|main|testbed) ;; | |
| *) echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0 ;; | |
| esac | |
| if [[ "$EVENT_ACTION" != "ready_for_review" ]]; then | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # `benchmark-contract-tests` is intentionally skipped on PRs that | |
| # don't touch its inputs (see detect-changes). Keep that job | |
| # skippable, but still require the core preflight checks to be | |
| # successful so `ready_for_review` re-runs them and unblocks | |
| # gpu-smoke. | |
| CHECKS=$(gh api "repos/${{ github.repository }}/commits/$HEAD_SHA/check-runs" --jq ' | |
| [ | |
| .check_runs | |
| | group_by(.name) | |
| | map(max_by(.id))[] | |
| | select(.name == "pre-commit" or .name == "gitleaks" or .name == "actionlint" or .name == "benchmark-contract-tests") | |
| | {name: .name, conclusion: .conclusion} | |
| ] | |
| ') | |
| ALL_OK=$(echo "$CHECKS" | jq ' | |
| all( | |
| if .name == "benchmark-contract-tests" | |
| then (.conclusion == "success" or .conclusion == "skipped") | |
| else (.conclusion == "success") | |
| end | |
| ) | |
| ') | |
| COUNT=$(echo "$CHECKS" | jq 'length') | |
| if [[ "$ALL_OK" == "true" && "$COUNT" -ge 4 ]]; then | |
| echo "CI already passed for SHA $HEAD_SHA; skipping" | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| pre-commit: | |
| needs: [validate-pr-title, ci-gate] | |
| if: ${{ github.repository == 'MetaX-MACA/TileOPs-Metax' && needs.ci-gate.outputs.skip != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.10" | |
| - name: Run pre-commit | |
| uses: pre-commit/action@v3.0.1 | |
| with: | |
| extra_args: --all-files --show-diff-on-failure | |
| gitleaks: | |
| needs: [validate-pr-title, ci-gate] | |
| if: ${{ github.repository == 'MetaX-MACA/TileOPs-Metax' && needs.ci-gate.outputs.skip != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Install gitleaks | |
| env: | |
| GITLEAKS_VERSION: "8.30.0" | |
| run: | | |
| set -euo pipefail | |
| install_dir="${RUNNER_TEMP}/bin" | |
| archive="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | |
| mkdir -p "$install_dir" | |
| curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${archive}" \ | |
| -o "${RUNNER_TEMP}/${archive}" | |
| tar -xzf "${RUNNER_TEMP}/${archive}" -C "$install_dir" gitleaks | |
| echo "$install_dir" >> "$GITHUB_PATH" | |
| - name: Run gitleaks | |
| run: gitleaks dir . --redact --no-banner | |
| validate-manifest: | |
| needs: [validate-pr-title, ci-gate, detect-changes] | |
| if: ${{ github.repository == 'tile-ai/TileOPs' && needs.ci-gate.outputs.skip != 'true' && needs.detect-changes.outputs.manifest == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.10" | |
| - name: Install TileOPs and validator dependencies | |
| run: pip install -e . | |
| - name: Validate ops manifest | |
| run: python scripts/validate_manifest.py --levels schema,shape,dtype,bench | |
| actionlint: | |
| needs: [validate-pr-title, ci-gate] | |
| if: ${{ github.repository == 'MetaX-MACA/TileOPs-Metax' && needs.ci-gate.outputs.skip != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Install actionlint | |
| env: | |
| ACTIONLINT_VERSION: "1.7.11" | |
| run: | | |
| set -euo pipefail | |
| install_dir="${RUNNER_TEMP}/bin" | |
| mkdir -p "$install_dir" | |
| curl -sSfL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash \ | |
| | bash -s -- "$ACTIONLINT_VERSION" "$install_dir" | |
| echo "$install_dir" >> "$GITHUB_PATH" | |
| - name: Run actionlint | |
| run: actionlint -color | |
| benchmark-contract-tests: | |
| # CPU-only contract tests for benchmark workload protocols. | |
| # Scoped to `benchmarks/tests/` so the GPU-bound `benchmarks/ops/` | |
| # suites (nightly-only) are NOT collected on PR CI. | |
| needs: [validate-pr-title, ci-gate, detect-changes] | |
| if: ${{ github.repository == 'tile-ai/TileOPs' && needs.ci-gate.outputs.skip != 'true' && needs.detect-changes.outputs.benchmark == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.10" | |
| - name: Install TileOPs (with dev extras) | |
| run: pip install -e ".[dev]" | |
| - name: Run benchmark contract tests | |
| run: python -m pytest -q benchmarks/tests |