From f05dcada782cf364d4fb477c23bff753ba34600c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:04:20 +0000 Subject: [PATCH 1/5] ci: scope generation validation to generation-affecting files only Skip validate + zero-diff jobs for dependency-only PRs (mypy, pylint, etc.) since dev dependency updates cannot affect Speakeasy-generated code. Generation-affecting paths: .speakeasy/**, gen.yaml, overlays/**, scripts/**, poe_tasks.toml, src/**, .genignore, .github/speakeasy/**, and the generation workflow itself. Co-Authored-By: AJ Steers --- .github/workflows/test-full.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index 70ebf42e..60240c72 100644 --- a/.github/workflows/test-full.yml +++ b/.github/workflows/test-full.yml @@ -15,6 +15,10 @@ # workflow that never runs as "expected" (pending), which blocks required checks. # Instead, we filter paths at the job level so skipped jobs report as "skipped" # (equivalent to "passed" for required checks). +# +# The path filter is scoped to generation-affecting files only (Speakeasy config, +# gen.yaml, overlays, scripts, src/, etc.). Dev dependency updates (mypy, pylint, +# etc.) skip the generation validation since they cannot affect generated code. name: Test (Full) @@ -39,9 +43,15 @@ jobs: with: filters: | generation: - - '**' - - '!README.md' - - '!docs/**' + - '.speakeasy/**' + - '.genignore' + - '.github/speakeasy/**' + - '.github/workflows/generate-command.yml' + - 'gen.yaml' + - 'overlays/**' + - 'scripts/**' + - 'poe_tasks.toml' + - 'src/**' outputs: should_run: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.generation == 'true' }} From 963ed3f20e7bab51c2dc6d6413f6748b6fe45a5d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:08:58 +0000 Subject: [PATCH 2/5] ci: add README.md to generation path filter README.md is an input to prepare_readme.py which produces the tracked README-PYPI.md, so changes to it can cause generation drift. Co-Authored-By: AJ Steers --- .github/workflows/test-full.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index 60240c72..477e5cbd 100644 --- a/.github/workflows/test-full.yml +++ b/.github/workflows/test-full.yml @@ -49,6 +49,7 @@ jobs: - '.github/workflows/generate-command.yml' - 'gen.yaml' - 'overlays/**' + - 'README.md' - 'scripts/**' - 'poe_tasks.toml' - 'src/**' From c4a25723669908678804ce7dcb80e74d9c916963 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:09:43 +0000 Subject: [PATCH 3/5] ci: clarify header comment about why dep-only PRs skip generation Co-Authored-By: AJ Steers --- .github/workflows/test-full.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index 477e5cbd..ad47e943 100644 --- a/.github/workflows/test-full.yml +++ b/.github/workflows/test-full.yml @@ -18,7 +18,9 @@ # # The path filter is scoped to generation-affecting files only (Speakeasy config, # gen.yaml, overlays, scripts, src/, etc.). Dev dependency updates (mypy, pylint, -# etc.) skip the generation validation since they cannot affect generated code. +# etc.) skip the generation validation because they don't change generated +# artifacts, and Dependabot PRs lack the SPEAKEASY_API_KEY secret needed to run +# the generation pipeline. name: Test (Full) From b65fefc25995b38de69af233646248045f2a2cda Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:24:50 +0000 Subject: [PATCH 4/5] ci: move skip condition into generate-command.yml so inner job reports as skipped The validate job in test-full.yml now always calls generate-command.yml (no if: condition). The Generate SDK job inside generate-command.yml checks the new should_run input and skips itself internally. This ensures the job name appears in CI as 'skipped' rather than never being created, which satisfies required check merge requirements. Co-Authored-By: AJ Steers --- .github/workflows/generate-command.yml | 5 +++++ .github/workflows/test-full.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/generate-command.yml b/.github/workflows/generate-command.yml index d3df4568..c6d71e16 100644 --- a/.github/workflows/generate-command.yml +++ b/.github/workflows/generate-command.yml @@ -54,6 +54,10 @@ name: Generate SDK description: Validate generation without creating a PR type: boolean default: false + should_run: + description: Whether the generate job should run (false = skip). Used by callers to pass path-filter results so the job skips internally and reports as 'skipped' (satisfying required checks). + type: boolean + default: true outputs: has_changes: description: Whether the generation produced changes vs committed code @@ -69,6 +73,7 @@ concurrency: jobs: generate: name: Generate SDK + if: ${{ inputs.should_run != false }} runs-on: ubuntu-latest timeout-minutes: 30 outputs: diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index ad47e943..58d8382c 100644 --- a/.github/workflows/test-full.yml +++ b/.github/workflows/test-full.yml @@ -61,10 +61,10 @@ jobs: validate: name: Validate Generation (Dry Run) needs: check-paths - if: needs.check-paths.outputs.should_run == 'true' uses: ./.github/workflows/generate-command.yml with: dry_run: true + should_run: ${{ needs.check-paths.outputs.should_run == 'true' }} secrets: inherit zero-diff: From 38c2f1c52d22360358464457774ddd795fdacdac Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:27:53 +0000 Subject: [PATCH 5/5] ci: move path filter entirely into generate-command.yml The generation workflow now owns its path filtering logic: - New check-paths job runs only during dry_run mode - Generate SDK job skips if dry_run and no generation-affecting files changed - test-full.yml simplified to just call generate-command.yml + zero-diff This ensures the Generate SDK job name always appears in CI (as skipped or passed), satisfying required check merge requirements. Co-Authored-By: AJ Steers --- .github/workflows/generate-command.yml | 33 +++++++++++++++--- .github/workflows/test-full.yml | 46 +++----------------------- 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/.github/workflows/generate-command.yml b/.github/workflows/generate-command.yml index c6d71e16..8cb41600 100644 --- a/.github/workflows/generate-command.yml +++ b/.github/workflows/generate-command.yml @@ -54,10 +54,6 @@ name: Generate SDK description: Validate generation without creating a PR type: boolean default: false - should_run: - description: Whether the generate job should run (false = skip). Used by callers to pass path-filter results so the job skips internally and reports as 'skipped' (satisfying required checks). - type: boolean - default: true outputs: has_changes: description: Whether the generation produced changes vs committed code @@ -71,9 +67,36 @@ concurrency: cancel-in-progress: true jobs: + check-paths: + name: Check Generation Paths + if: ${{ inputs.dry_run }} + runs-on: ubuntu-latest + outputs: + should_run: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.generation == 'true' }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Filter changed paths + uses: dorny/paths-filter@v4 + id: filter + with: + filters: | + generation: + - '.speakeasy/**' + - '.genignore' + - '.github/speakeasy/**' + - '.github/workflows/generate-command.yml' + - 'gen.yaml' + - 'overlays/**' + - 'README.md' + - 'scripts/**' + - 'poe_tasks.toml' + - 'src/**' + generate: name: Generate SDK - if: ${{ inputs.should_run != false }} + needs: [check-paths] + if: ${{ always() && (!inputs.dry_run || needs.check-paths.outputs.should_run == 'true') }} runs-on: ubuntu-latest timeout-minutes: 30 outputs: diff --git a/.github/workflows/test-full.yml b/.github/workflows/test-full.yml index 58d8382c..a5867018 100644 --- a/.github/workflows/test-full.yml +++ b/.github/workflows/test-full.yml @@ -4,23 +4,14 @@ # and that the committed generated code matches what the generation pipeline produces. # # Jobs: -# 1. validate: Runs the full generation pipeline in dry-run mode +# 1. validate: Calls generate-command.yml with dry_run=true. The generation +# workflow handles its own path filtering — it skips the Generate SDK job +# when only non-generation files changed (e.g., dev dependency bumps). # 2. zero-diff: Checks for drift using the validate job's outputs (in-place git status). # If drift is detected, the check fails and posts a comment telling the author to run /generate. # # This workflow calls the main generation workflow with dry_run=true to ensure # both workflows use the same generation logic. -# -# Note: paths-ignore is NOT used at the workflow level because GitHub treats a -# workflow that never runs as "expected" (pending), which blocks required checks. -# Instead, we filter paths at the job level so skipped jobs report as "skipped" -# (equivalent to "passed" for required checks). -# -# The path filter is scoped to generation-affecting files only (Speakeasy config, -# gen.yaml, overlays, scripts, src/, etc.). Dev dependency updates (mypy, pylint, -# etc.) skip the generation validation because they don't change generated -# artifacts, and Dependabot PRs lack the SPEAKEASY_API_KEY secret needed to run -# the generation pipeline. name: Test (Full) @@ -33,44 +24,17 @@ permissions: pull-requests: write jobs: - check-paths: - name: Check Changed Paths - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Filter changed paths - uses: dorny/paths-filter@v4 - id: filter - with: - filters: | - generation: - - '.speakeasy/**' - - '.genignore' - - '.github/speakeasy/**' - - '.github/workflows/generate-command.yml' - - 'gen.yaml' - - 'overlays/**' - - 'README.md' - - 'scripts/**' - - 'poe_tasks.toml' - - 'src/**' - outputs: - should_run: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.generation == 'true' }} - validate: name: Validate Generation (Dry Run) - needs: check-paths uses: ./.github/workflows/generate-command.yml with: dry_run: true - should_run: ${{ needs.check-paths.outputs.should_run == 'true' }} secrets: inherit zero-diff: name: Zero-Diff Check (Generated Code) - needs: [check-paths, validate] - if: needs.check-paths.outputs.should_run == 'true' && github.event_name == 'pull_request' + needs: [validate] + if: github.event_name == 'pull_request' runs-on: ubuntu-latest permissions: contents: read