name: 'Changed Files Check' description: 'Detect changed files using filters.yaml and check for uncovered files' inputs: gh_token: description: 'GitHub token for PR API calls' required: true outputs: core: description: 'Whether core files changed' value: ${{ steps.filter.outputs.core_any_modified }} operator: description: 'Whether operator files changed' value: ${{ steps.filter.outputs.operator_any_modified }} deploy: description: 'Whether deploy files changed' value: ${{ steps.filter.outputs.deploy_any_modified }} vllm: description: 'Whether vllm files changed' value: ${{ steps.filter.outputs.vllm_any_modified }} sglang: description: 'Whether sglang files changed' value: ${{ steps.filter.outputs.sglang_any_modified }} trtllm: description: 'Whether trtllm files changed' value: ${{ steps.filter.outputs.trtllm_any_modified }} planner: description: 'Whether planner files changed' value: ${{ steps.filter.outputs.planner_any_modified }} frontend: description: 'Whether frontend files changed' value: ${{ steps.filter.outputs.frontend_any_modified }} rust: description: 'Whether rust files changed' value: ${{ steps.filter.outputs.rust_any_modified }} docs: description: 'Whether docs files changed' value: ${{ steps.filter.outputs.docs_any_modified }} runs: using: "composite" steps: # Skipped for pull_request events — tj-actions uses the REST API instead. - name: Get merge base for push events id: merge-base if: github.event_name != 'pull_request' shell: bash env: GH_TOKEN: ${{ inputs.gh_token }} run: | # How changed-file detection works (callers use fetch-depth: 1): # # pull_request events: # tj-actions/changed-files calls the GitHub REST API (GET /pulls/{n}/files) # to list changed files. No git history needed — works with shallow clones. # # push to pull-request/N branches: # The GitHub Compare API returns the true merge-base SHA. We fetch that # single commit so tj-actions can run `git diff merge-base HEAD` locally. # # push to main / release branches: # base_sha is empty, skip_initial_fetch is false — tj-actions falls back # to its default behaviour (deepens history and diffs against the previous # commit). Callers short-circuit outputs to true for main/release anyway. if [[ "${{ github.ref_name }}" =~ ^pull-request/([0-9]+)$ ]]; then BASE=$(gh pr view "${BASH_REMATCH[1]}" --json baseRefName -q '.baseRefName') # Compare API returns the true merge-base (fork point), not the branch tip. BASE_SHA=$(gh api "repos/${{ github.repository }}/compare/${BASE}...${{ github.sha }}" \ --jq '.merge_base_commit.sha') echo "Merge base: $BASE_SHA" # Fetch the merge-base commit so tj-actions can `git diff` against it. git fetch --no-tags --depth=1 origin "$BASE_SHA" echo "base_sha=$BASE_SHA" >> "$GITHUB_OUTPUT" else echo "base_sha=" >> "$GITHUB_OUTPUT" fi - name: Check for changes uses: tj-actions/changed-files@aa08304bd477b800d468db44fe10f6c61f7f7b11 # v42.1.0 id: filter with: files_yaml_from_source_file: .github/filters.yaml token: ${{ inputs.gh_token }} # pull_request: calls GET /pulls/{n}/files — accurate, no git history needed. use_rest_api: ${{ github.event_name == 'pull_request' }} # push to pull-request/N: merge-base SHA from Compare API (set above). # push to main/release: empty — tj-actions uses default (previous commit). base_sha: ${{ steps.merge-base.outputs.base_sha || '' }} # When we provide base_sha we've already fetched everything needed. # When base_sha is empty, let tj-actions fetch history itself. skip_initial_fetch: ${{ steps.merge-base.outputs.base_sha != '' }} - name: Debug changed files shell: bash run: | echo "=== Base SHA Used ===" echo "base_sha: ${{ steps.merge-base.outputs.base_sha || 'default (previous commit)' }}" echo "" echo "=== All Modified Files (${{ steps.filter.outputs.all_all_modified_files_count }} total) ===" echo "${{ steps.filter.outputs.all_all_modified_files }}" echo "" echo "=== Filters That Matched ===" echo "changed_keys: ${{ steps.filter.outputs.changed_keys }}" echo "" echo "=== Filter Results ===" echo "docs: ${{ steps.filter.outputs.docs_any_modified }}" echo "ci: ${{ steps.filter.outputs.ci_any_modified }}" echo "core: ${{ steps.filter.outputs.core_any_modified }}" echo "operator: ${{ steps.filter.outputs.operator_any_modified }}" echo "deploy: ${{ steps.filter.outputs.deploy_any_modified }}" echo "planner: ${{ steps.filter.outputs.planner_any_modified }}" echo "vllm: ${{ steps.filter.outputs.vllm_any_modified }}" echo "sglang: ${{ steps.filter.outputs.sglang_any_modified }}" echo "trtllm: ${{ steps.filter.outputs.trtllm_any_modified }}" echo "frontend: ${{ steps.filter.outputs.frontend_any_modified }}" echo "rust: ${{ steps.filter.outputs.rust_any_modified }}" echo "" echo "=== Files Matching Each Filter ===" echo "docs: ${{ steps.filter.outputs.docs_all_modified_files }}" echo "ci: ${{ steps.filter.outputs.ci_all_modified_files }}" echo "core: ${{ steps.filter.outputs.core_all_modified_files }}" echo "operator: ${{ steps.filter.outputs.operator_all_modified_files }}" echo "deploy: ${{ steps.filter.outputs.deploy_all_modified_files }}" echo "planner: ${{ steps.filter.outputs.planner_all_modified_files }}" echo "vllm: ${{ steps.filter.outputs.vllm_all_modified_files }}" echo "sglang: ${{ steps.filter.outputs.sglang_all_modified_files }}" echo "trtllm: ${{ steps.filter.outputs.trtllm_all_modified_files }}" echo "frontend: ${{ steps.filter.outputs.frontend_all_modified_files }}" echo "rust: ${{ steps.filter.outputs.rust_all_modified_files }}" - name: Check for uncovered files shell: bash run: | # Combine all filter-specific files into one list COVERED_FILES=$(echo "${{ steps.filter.outputs.docs_all_modified_files }} ${{ steps.filter.outputs.examples_all_modified_files }} ${{ steps.filter.outputs.ignore_all_modified_files }} ${{ steps.filter.outputs.ci_all_modified_files }} ${{ steps.filter.outputs.core_all_modified_files }} ${{ steps.filter.outputs.operator_all_modified_files }} ${{ steps.filter.outputs.deploy_all_modified_files }} ${{ steps.filter.outputs.planner_all_modified_files }} ${{ steps.filter.outputs.vllm_all_modified_files }} ${{ steps.filter.outputs.sglang_all_modified_files }} ${{ steps.filter.outputs.trtllm_all_modified_files }} ${{ steps.filter.outputs.frontend_all_modified_files }} ${{ steps.filter.outputs.rust_all_modified_files }}" | tr ' ' '\n' | grep -v '^$' | sort -u) # Get all modified files ALL_FILES=$(echo "${{ steps.filter.outputs.all_all_modified_files }}" | tr ' ' '\n' | grep -v '^$' | sort -u) # Find files in ALL but not in COVERED UNCOVERED=$(comm -23 <(echo "$ALL_FILES") <(echo "$COVERED_FILES")) if [ -n "$UNCOVERED" ]; then echo "::error::The following files are not covered by any CI filter:" echo "$UNCOVERED" echo "" echo "Please add these paths to .github/filters.yaml" echo "See .github/FILTERS.md for documentation" exit 1 fi echo "All modified files are covered by CI filters."