diff --git a/.github/workflows/README.md b/.github/workflows/README.md index c37cf24d..7ef7accc 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -13,34 +13,47 @@ This directory contains CI/CD workflows for the DeepWork project. We use GitHub' ## Merge Queue Strategy +All workflows explicitly target the `main` branch for both `pull_request` and `merge_group` triggers to ensure proper execution in the merge queue. + We use a skip pattern so the same required checks pass in both PR and merge queue contexts: -| Workflow | On PRs | In Merge Queue | -|----------|--------|----------------| -| **Validate** | Runs | Runs | -| **Integration Tests** | Skipped (passes) | Runs | -| **E2E Tests** | Skipped (passes) | Runs | -| **CLA Check** | Runs | Skipped (passes) | +| Workflow | On PRs | In Merge Queue | Manual Trigger | +|----------|--------|----------------|----------------| +| **Validate** | Runs | Runs | Runs | +| **Integration Tests** | Skipped (passes) | Runs | Runs | +| **E2E Tests** | Skipped (passes) | Runs | Runs | +| **CLA Check** | Runs | Skipped (passes) | Skipped (passes) | ### How It Works +All workflows specify explicit branch targeting: + +```yaml +on: + pull_request: + branches: [main] + merge_group: + branches: [main] + workflow_dispatch: # Enables manual triggering for testing +``` + Jobs/steps use `if: github.event_name == 'merge_group'` conditions to control execution: ```yaml -# Job that only runs in merge queue (skipped on PRs) +# Job that only runs in merge queue and manual dispatch (skipped on PRs) jobs: expensive-tests: if: github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' ... -# Step that skips in merge queue (runs on PRs only) -steps: - - name: CLA Check - if: github.event_name != 'merge_group' +# Job that skips in merge queue and manual dispatch (runs on PRs only) +jobs: + cla-check: + if: github.event_name != 'merge_group' && github.event_name != 'workflow_dispatch' ... ``` -When a job/step is skipped due to an `if` condition, GitHub treats it as a successful check. This allows: +When a job is skipped due to an `if` condition, GitHub treats it as a successful check. This allows: - **Fast PR feedback**: Only lint + unit tests run on every push - **Thorough merge validation**: Expensive integration/e2e tests run in merge queue before merging @@ -50,31 +63,38 @@ When a job/step is skipped due to an `if` condition, GitHub treats it as a succe In GitHub branch protection rules, require these checks: - `Validate / tests` -- `Claude Code Integration Test / validate-generation` -- `Claude Code Integration Test / claude-code-e2e` -- `CLA Assistant / cla-check` +- `Claude Code Integration Test / pr-check` (for PRs) +- `Claude Code Integration Test / validate-generation` (for merge queue) +- `Claude Code Integration Test / claude-code-e2e` (for merge queue) +- `CLA Assistant / merge-queue-pass` (for merge queue) +- `CLA Assistant / cla-check` (for PRs) All checks will pass in both PR and merge queue contexts (either by running or by being skipped). +**Note**: The explicit branch targeting in `merge_group` triggers is critical for workflows to run properly in the merge queue. Without this, GitHub may not trigger the workflows and they will remain in "expected" state. + ## Workflow Details ### validate.yml -- **Triggers**: `pull_request`, `merge_group` +- **Triggers**: `pull_request` (main), `merge_group` (main), `workflow_dispatch` - **Jobs**: `tests` - runs ruff format/lint checks and pytest unit tests -- Runs on every PR and in merge queue +- Runs on every PR, in merge queue, and can be manually triggered ### claude-code-test.yml -- **Triggers**: `pull_request`, `merge_group`, `workflow_dispatch` +- **Triggers**: `pull_request` (main), `merge_group` (main), `workflow_dispatch` - **Jobs**: + - `pr-check`: Runs on PRs only, always passes (lightweight check) - `validate-generation`: Tests command generation from fixtures (no API key needed) - `claude-code-e2e`: Full end-to-end test with Claude Code CLI (requires `ANTHROPIC_API_KEY`) -- Both jobs skip on PRs, run in merge queue and manual dispatch +- `validate-generation` and `claude-code-e2e` skip on PRs, run in merge queue and manual dispatch ### cla.yml -- **Triggers**: `pull_request_target`, `issue_comment`, `merge_group` -- **Jobs**: `cla-check` - verifies contributors have signed the CLA -- Runs on PRs, skips in merge queue (CLA already verified) +- **Triggers**: `pull_request_target`, `issue_comment`, `merge_group` (main), `workflow_dispatch` +- **Jobs**: + - `merge-queue-pass`: Runs on merge queue and manual dispatch, always passes + - `cla-check`: Verifies contributors have signed the CLA +- `cla-check` runs on PRs, skips in merge queue and manual dispatch (CLA already verified) ### release.yml -- **Triggers**: Tags matching `v*` +- **Triggers**: `release` (published) - **Jobs**: Builds and publishes to PyPI diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 118f7e8b..b1940f21 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -5,8 +5,11 @@ on: types: [created] pull_request_target: types: [opened, synchronize] + branches: [main] # Run in merge queue but skip the step (shows as passing check) merge_group: + branches: [main] + workflow_dispatch: # Explicitly set permissions for the workflow permissions: @@ -16,11 +19,20 @@ permissions: statuses: write jobs: + # Job for merge queue - always passes since CLA is checked at PR time + merge-queue-pass: + runs-on: ubuntu-latest + if: github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' + steps: + - name: CLA already verified at PR time + run: echo "CLA check is performed on PRs, not in merge queue. Passing." + cla-check: runs-on: ubuntu-latest + if: github.event_name != 'merge_group' && github.event_name != 'workflow_dispatch' steps: - name: "CLA Assistant" - if: github.event_name != 'merge_group' && ((github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target') + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' uses: contributor-assistant/github-action@v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/claude-code-test.yml b/.github/workflows/claude-code-test.yml index 84e888d0..7a113ff6 100644 --- a/.github/workflows/claude-code-test.yml +++ b/.github/workflows/claude-code-test.yml @@ -11,17 +11,31 @@ on: type: boolean # Run on all PRs (shows as check, but steps skip unless in merge queue) pull_request: + branches: [main] # Run in the merge queue to validate before merging merge_group: + branches: [main] # Ensure only one instance runs at a time per PR/branch concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} cancel-in-progress: true +# Minimal permissions for this workflow +permissions: + contents: read + jobs: + # Job for PRs - always passes, actual validation happens in merge queue + pr-check: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - name: PR Check + run: echo "Claude Code integration tests will run in the merge queue" + # Job 1: Validate command generation from fixtures (no API key needed) - # Runs on merge_group and workflow_dispatch, skipped on PRs (shows as passing check) + # Runs on merge_group and workflow_dispatch only validate-generation: runs-on: ubuntu-latest if: github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5b3cfb74..a463b777 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -2,7 +2,14 @@ name: Validate on: pull_request: + branches: [main] merge_group: + branches: [main] + workflow_dispatch: + +# Minimal permissions for this workflow +permissions: + contents: read jobs: tests: