How to Block PRs Missing Tests or a Changelog
Compare the list of changed files: if source changed but no test or changelog did, fail the job.
Use tj-actions/changed-files to capture which files changed, then a shell step that exits non-zero when source paths changed without a matching test or CHANGELOG.md update.
Steps
- Run
tj-actions/changed-filesto list changed paths. - Bucket the paths into source, tests, and changelog.
- Exit 1 when source changed but tests and changelog did not.
Workflow
.github/workflows/ci.yml
on: [pull_request]
jobs:
guard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: changed
uses: tj-actions/changed-files@v45
- name: Require tests or changelog
env:
FILES: ${{ steps.changed.outputs.all_changed_files }}
run: |
echo "$FILES" | tr ' ' '\n' > files.txt
src=$(grep -E '^src/' files.txt || true)
tests=$(grep -E '(\.test\.|/tests?/)' files.txt || true)
log=$(grep -E '^CHANGELOG\.md$' files.txt || true)
if [ -n "$src" ] && [ -z "$tests" ] && [ -z "$log" ]; then
echo "Source changed without tests or a changelog entry."
exit 1
fiGotchas
- Quote the file list; paths with spaces break the naive split otherwise.
- Allow an override label (for example
no-tests-needed) so genuine exceptions are not blocked.
Related guides
How to Enforce PR Review Rules With Danger JSCodify pull request review rules in a dangerfile.js and run Danger JS in CI to warn or fail when a PR skips a…
How to Require Test Files to Change With SourceEnforce that any pull request touching source also updates tests using dorny/paths-filter to detect changed g…