diff --git a/.github/workflows/hacktoberfest_prep.yml b/.github/workflows/hacktoberfest_prep.yml index c8a7a76a00df..fed359a0d621 100644 --- a/.github/workflows/hacktoberfest_prep.yml +++ b/.github/workflows/hacktoberfest_prep.yml @@ -6,6 +6,14 @@ name: hacktoberfest_prep on: + push: + paths: + - ".github/workflows/hacktoberfest_prep.yml" + - "scripts/hacktoberfest_prep_update.py" + pull_request: + paths: + - ".github/workflows/hacktoberfest_prep.yml" + - "scripts/hacktoberfest_prep_update.py" schedule: - cron: "50 11 * * *" # 11:50 UTC every day workflow_dispatch: # allow a manual run while testing @@ -37,7 +45,20 @@ jobs: set +e python scripts/hacktoberfest_prep_update.py echo "exit_code=$?" >> "$GITHUB_OUTPUT" + # Dry run on push / pull_request: show the diff the script produced but + # do NOT commit or push. This lets a PR prove the tracker still gathers + # its data and rewrites docs/hacktober_2026_prep.md correctly without + # leaving a permanent commit. Only the schedule/manual runs persist. + - name: Show changes (dry run) + if: github.event_name == 'push' || github.event_name == 'pull_request' + run: | + echo "Dry run (${{ github.event_name }}): showing git diff, not committing." + git --no-pager diff -- docs/hacktober_2026_prep.md + if git diff --quiet -- docs/hacktober_2026_prep.md; then + echo "No changes to docs/hacktober_2026_prep.md." + fi - name: Commit any changes + if: github.event_name != 'push' && github.event_name != 'pull_request' run: | git config --global user.name "$GITHUB_ACTOR" git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" diff --git a/scripts/hacktoberfest_prep_update.py b/scripts/hacktoberfest_prep_update.py index 6c6eb1de0fbe..daf32c2f9bd0 100644 --- a/scripts/hacktoberfest_prep_update.py +++ b/scripts/hacktoberfest_prep_update.py @@ -113,11 +113,22 @@ async def _search_count( async def pr_state( client: httpx2.AsyncClient, sem: asyncio.Semaphore, number: int ) -> str | None: - """Return ``"merged"`` / ``"closed"`` for a resolved PR, else ``None``.""" - body, _ = await _request(client, sem, f"{API}/repos/{REPO}/pulls/{number}") + """Return ``"merged"`` / ``"closed"`` for a resolved row, else ``None``. + + Uses the unified ``/issues/{number}`` endpoint, which resolves for both + pull requests *and* issues. The tracker's "Open issues" section lists + issue numbers, and ``/pulls/{issue}`` 404s on those, so querying + ``/issues`` keeps a single issue row from crashing the whole run. A row is + "merged" only when it is a PR whose ``pull_request.merged_at`` is set; any + other closed row is "closed". + """ + body, _ = await _request(client, sem, f"{API}/repos/{REPO}/issues/{number}") if body.get("state") == "open": # type: ignore[union-attr] return None - return "merged" if body.get("merged_at") else "closed" # type: ignore[union-attr] + pr = body.get("pull_request") # type: ignore[union-attr] + if pr and pr.get("merged_at"): + return "merged" + return "closed" async def top_awaiting_directories(