From adba0e31bb5a7299c74186a696be2e5209385a23 Mon Sep 17 00:00:00 2001 From: iam-truongtrungnghia Date: Sat, 5 Sep 2026 18:45:33 +0700 Subject: [PATCH] fix: run the app-ci path filter on pull requests only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dorny/paths-filter uses the GitHub API on a pull_request event, but on a push it has to diff against github.event.before with git. That commit is not in the changes job's default depth-1 checkout, so it fetches it — and the checkout persists no credential (zizmor requires that), so on a private repository the fetch dies with "could not read Username for 'https://github.com'". Every push to main after the first one therefore failed the changes job, which skipped ci and commitlint: the merge gate existed on pull requests only. The first push to a branch survived just because github.event.before is the all-zero sha there. Gate build-filters and the filter on github.event_name == 'pull_request' and fall the job's roots output back to inputs.roots otherwise. The filter is a pull-request time saver — most roots are untouched there — while on the default branch every root should be verified anyway, so the non-pull-request branch wants the full list regardless. Both branches emit a JSON array string, so fromJSON and the ci job's != '[]' guard keep working, no fetch-depth change is needed, and persist-credentials: false stays. Claude-Session: https://claude.ai/code/session_01J4HB8qJjdZwaAv42k6HMpv --- .github/workflows/app-ci.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/app-ci.yml b/.github/workflows/app-ci.yml index aeaee94..11226c4 100644 --- a/.github/workflows/app-ci.yml +++ b/.github/workflows/app-ci.yml @@ -16,12 +16,22 @@ jobs: contents: read pull-requests: read outputs: - roots: ${{ steps.filter.outputs.changes }} + # the filter only runs on a pull request, so on every other event this + # falls back to the full input: a push to the default branch is exactly + # where every root should be verified, not a subset. that also keeps + # paths-filter away from `git`, which it needs on a push (it diffs + # against github.event.before, a commit a depth-1 checkout does not + # have) and cannot use, because the checkout persists no credential + # for it to fetch that commit with on a private repository. + roots: ${{ steps.filter.outputs.changes || inputs.roots }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - id: build-filters + # the filter is a pull-request time saver: most roots are untouched + # there. on any other event the job outputs inputs.roots unchanged. + - if: github.event_name == 'pull_request' + id: build-filters env: ROOTS: ${{ inputs.roots }} # a root is dirty when its own directory, a lockfile, or the root @@ -30,7 +40,8 @@ jobs: echo "$ROOTS" \ | jq -r '.[] | "\(.):\n - \(.)/**\n - mise.toml\n - \"*.lock*\""' \ > "${RUNNER_TEMP}/filters.yml" - - id: filter + - if: github.event_name == 'pull_request' + id: filter uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 with: filters: ${{ runner.temp }}/filters.yml