fix: make workflow_dispatch actually run code jobs #3

Merged
john merged 1 commit from fix/detect-changes-workflow-dispatch into main 2026-07-26 16:09:41 +00:00
Owner

Problem

The event dispatch in detect-changes.yml has two branches, not three — anything that isn't a push falls into the pull_request branch:

if [ "$event_name" = "push" ]; then  CHANGED=$(git diff --name-only HEAD~1 HEAD)
else                                 CHANGED=$(git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD)
fi

On workflow_dispatch there is no github.event.pull_request.base.sha, so it expands to:

git diff --name-only  HEAD      # empty diff

has_code is therefore always 'false', and every code job skips. Manual re-trigger has been silently inert in all 10 consuming reposworkflow_dispatch is declared in their CI as an escape hatch and has never been able to run anything.

How it surfaced

On jaberson-planner, runs #396 and #397 were fired via workflow_dispatch to clear a red CI status. Both skipped every job:

Skipping job 'Docker Build (Backend)' due to 'needs.detect-changes.outputs.has_code == '''true''''
Skipping job 'Frontend'               due to 'needs.detect-changes.outputs.has_code == '''true''''

Two manual attempts that could never have worked.

Fix

Split the else into an explicit pull_request branch plus a catch-all that sets CHANGED="force-run". That string fails the doc-only exclusion grep, so has_code=true — the same escape hatch the existing || echo "force-run" fallbacks already rely on.

Verification

Ran the filter expression against 10 event shapes:

Input has_code
force-run (workflow_dispatch, new) true ← the fix
empty diff (old workflow_dispatch) false ← the bug
docs/foo.md false unchanged
README.md false unchanged
CLAUDE.md false unchanged
.workstream/state.json false unchanged
app/main.py true unchanged
docs + code mixed true unchanged
.forgejo/workflows/ci.yml true unchanged
Dockerfile true unchanged

Only the workflow_dispatch case changes. push and pull_request paths are untouched.

Blast radius

Consumed at @main by 10 repos, so this takes effect immediately on merge: haskydocs-v2, haskytech-modules-py, markspace-website, heyco, keizen-wa, keizen-full, rainbowcentre, jaberson-planner, jaberson-timecard.

The change can only cause more jobs to run, never fewer — a manual dispatch that previously did nothing will now execute the full pipeline. Revert is a one-line rollback.

Note

Repos with an inline detect-changes job rather than this reusable workflow (smeos, tachikoma) carry the same two-branch bug independently and are not fixed here.

## Problem The event dispatch in `detect-changes.yml` has **two branches, not three** — anything that isn't a `push` falls into the `pull_request` branch: ```bash if [ "$event_name" = "push" ]; then CHANGED=$(git diff --name-only HEAD~1 HEAD) else CHANGED=$(git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD) fi ``` On `workflow_dispatch` there is no `github.event.pull_request.base.sha`, so it expands to: ``` git diff --name-only HEAD # empty diff ``` `has_code` is therefore always `'false'`, and **every code job skips**. Manual re-trigger has been silently inert in all **10 consuming repos** — `workflow_dispatch` is declared in their CI as an escape hatch and has never been able to run anything. ## How it surfaced On `jaberson-planner`, runs **#396** and **#397** were fired via `workflow_dispatch` to clear a red CI status. Both skipped every job: ``` Skipping job 'Docker Build (Backend)' due to 'needs.detect-changes.outputs.has_code == '''true'''' Skipping job 'Frontend' due to 'needs.detect-changes.outputs.has_code == '''true'''' ``` Two manual attempts that could never have worked. ## Fix Split the `else` into an explicit `pull_request` branch plus a catch-all that sets `CHANGED="force-run"`. That string fails the doc-only exclusion grep, so `has_code=true` — the same escape hatch the existing `|| echo "force-run"` fallbacks already rely on. ## Verification Ran the filter expression against 10 event shapes: | Input | has_code | | |---|---|---| | `force-run` (workflow_dispatch, **new**) | `true` | ← the fix | | empty diff (old workflow_dispatch) | `false` | ← the bug | | `docs/foo.md` | `false` | unchanged | | `README.md` | `false` | unchanged | | `CLAUDE.md` | `false` | unchanged | | `.workstream/state.json` | `false` | unchanged | | `app/main.py` | `true` | unchanged | | docs + code mixed | `true` | unchanged | | `.forgejo/workflows/ci.yml` | `true` | unchanged | | `Dockerfile` | `true` | unchanged | Only the `workflow_dispatch` case changes. `push` and `pull_request` paths are untouched. ## Blast radius Consumed at `@main` by 10 repos, so this takes effect immediately on merge: haskydocs-v2, haskytech-modules-py, markspace-website, heyco, keizen-wa, keizen-full, rainbowcentre, jaberson-planner, jaberson-timecard. The change can only cause **more** jobs to run, never fewer — a manual dispatch that previously did nothing will now execute the full pipeline. Revert is a one-line rollback. ## Note Repos with an **inline** `detect-changes` job rather than this reusable workflow (smeos, tachikoma) carry the same two-branch bug independently and are not fixed here.
The event dispatch had two branches, not three: anything that was not a
push fell into the pull_request branch. On workflow_dispatch there is no
github.event.pull_request.base.sha, so the command expanded to

    git diff --name-only  HEAD

— an empty diff. has_code was therefore always 'false' and every code job
was skipped. Manual re-trigger has been silently inert in all 10 consuming
repos.

Found on jaberson-planner, where two workflow_dispatch runs (#396, #397)
were fired to clear a red CI status. Both skipped every job and could
never have worked.

Non-push, non-PR events (workflow_dispatch, schedule) now set CHANGED to
'force-run', which fails the doc-only exclusion grep and yields
has_code=true — the same escape hatch the existing '|| echo force-run'
fallbacks already use.

Verified the filter against 10 event shapes: workflow_dispatch flips
false -> true; docs-only, md-only, CLAUDE.md-only, workstream-only stay
false; code, mixed, workflow-file and Dockerfile changes stay true.
john merged commit 1bb3adba81 into main 2026-07-26 16:09:41 +00:00
john deleted branch fix/detect-changes-workflow-dispatch 2026-07-26 16:09:41 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
haskytech/forgejo-ci!3
No description provided.