Skip to content

Commit 2ede1c1

Browse files
feat: add PR comment for scope check failures
Updates the PR scope check CI to post a comment on the pull request when the scope validation fails. The comment details: - If the PR title format is incorrect (missing scope). - Which scopes are missing from the PR title based on changed files. This provides immediate feedback to the PR author, making it easier to correct the PR title. Also ensures README.md is correctly created and updated with this new behavior.
1 parent ebc8284 commit 2ede1c1

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

.github/workflows/check_pr_scope.yml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ on:
77
jobs:
88
check_scope:
99
runs-on: ubuntu-latest
10+
outputs: # Define outputs for the job
11+
outcome: ${{ steps.check_scope_step.outcome }}
1012
steps:
1113
- uses: actions/checkout@v3
1214
with:
@@ -25,6 +27,7 @@ jobs:
2527
echo "EOF" >> $GITHUB_OUTPUT
2628
2729
- name: Check PR scope
30+
id: check_scope_step # Add id to this step
2831
run: |
2932
pr_title="${{ steps.pr_title.outputs.title }}"
3033
changed_files="${{ steps.changed_files.outputs.files }}"
@@ -40,7 +43,10 @@ jobs:
4043
pr_scopes=($(for scope in "${pr_scopes[@]}"; do echo "$scope" | xargs; done))
4144
4245
if [ ${#pr_scopes[@]} -eq 0 ] && [[ "$pr_scopes_str" != "*" ]]; then
43-
echo "::error::PR title does not contain a valid scope."
46+
error_message="PR title does not contain a valid scope. Please use the format 'type(scope): message' or 'type(*): message'."
47+
echo "::error::$error_message"
48+
comment_body="**Scope Check Failed!** 🚨\n\n${error_message}\n\nExample: \`feat(my-scope): add new feature\` or \`fix(*): resolve an issue\`."
49+
echo "comment_body=$comment_body" >> $GITHUB_ENV
4450
exit 1
4551
fi
4652
echo "PR Scopes: ${pr_scopes[@]}"
@@ -107,7 +113,38 @@ jobs:
107113
108114
if [ ${#missing_scopes[@]} -gt 0 ]; then
109115
echo "::error::PR title scopes do not cover all changed files. Missing scopes for: ${missing_scopes[@]}"
116+
# Prepare message for PR comment
117+
comment_body="**Scope Check Failed!** 🚨\n\nPR title scopes do not cover all changed files.\n\n"
118+
comment_body+="Missing required scopes in PR title: \`${missing_scopes[@]}\`\n\n"
119+
comment_body+="Please update your PR title to include these scopes. For example: \`type(${pr_scopes_str:+${pr_scopes_str},}${missing_scopes[@]}): your message\` or \`type(*): your message\` if a wildcard is appropriate.\n\n"
120+
comment_body+="<details><summary>Details</summary>\n"
121+
comment_body+="PR Title Scopes: \`${pr_scopes[@]}\`\n"
122+
comment_body+="Required Scopes from changed files: \`${required_scopes[@]}\`\n"
123+
comment_body+="Changed Files:\n"
124+
comment_body+="\`\`\`\n${changed_files}\n\`\`\`\n"
125+
comment_body+="</details>"
126+
127+
echo "comment_body=$comment_body" >> $GITHUB_ENV
110128
exit 1
111129
else
112130
echo "PR title scopes are valid."
113131
fi
132+
comment_on_pr:
133+
if: failure() && needs.check_scope.outputs.outcome == 'failure'
134+
needs: check_scope
135+
runs-on: ubuntu-latest
136+
permissions:
137+
pull-requests: write
138+
steps:
139+
- name: Comment on PR
140+
uses: actions/github-script@v6
141+
with:
142+
github-token: ${{secrets.GITHUB_TOKEN}}
143+
script: |
144+
const body = `${process.env.comment_body}`;
145+
github.rest.issues.createComment({
146+
issue_number: context.issue.number,
147+
owner: context.repo.owner,
148+
repo: context.repo.repo,
149+
body: body
150+
});

README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# PR Scope Check CI
2+
3+
This repository contains a GitHub Actions workflow that checks if the scope in a Pull Request (PR) title matches the files changed in the PR.
4+
5+
## Purpose
6+
7+
The primary goal of this CI is to enforce conventional commit message guidelines, specifically ensuring that the scope defined in the PR title accurately reflects the parts of the codebase being modified. This helps in:
8+
9+
- Improving the clarity and traceability of changes.
10+
- Automating changelog generation.
11+
- Making it easier to understand the impact of a PR at a glance.
12+
13+
## How it Works
14+
15+
The CI performs the following steps:
16+
17+
1. **Extracts PR Title Scope**: It parses the PR title to find the scope(s) defined within the parentheses, e.g., `type(scope1,scope2): message`.
18+
- Multiple scopes can be comma-separated.
19+
- A wildcard scope `(*)` is also permitted, which will allow changes in any scope.
20+
2. **Determines Required Scopes from Changed Files**: It analyzes the paths of the files modified in the PR.
21+
3. **Matches Scopes against Rules**: It uses a set of rules defined in `scope-rules.json` to map changed file paths to their corresponding scopes.
22+
- `config/{any_dir}/...` maps to the `{any_dir}` as scope.
23+
- `scripts/{any_dir}/...` maps to the `{any_dir}` as scope.
24+
- `data/{any_dir}/...` maps to the `{any_dir}` as scope.
25+
- `.github/...` maps to `github` scope.
26+
- Other files map to `dotfiles` scope.
27+
4. **Validates PR Title Scopes**: It checks if the scopes extracted from the PR title cover all the scopes determined from the changed files.
28+
- If the PR title uses a wildcard `*`, the check automatically passes.
29+
- If there's a mismatch (e.g., a required scope is not listed in the PR title, or the PR title has no scope when one is required), the CI job will fail, and a comment will be posted on the PR detailing the issue.
30+
31+
## Configuration
32+
33+
### Scope Rules (`scope-rules.json`)
34+
35+
The mapping between file paths and their scopes is defined in the `scope-rules.json` file in the root of the repository.
36+
37+
The file contains an array of rule objects, each with a `pattern` (regex) and a `scope` (string). The `scope` can use capture groups from the regex (e.g., `$1`).
38+
39+
**Example `scope-rules.json`:**
40+
41+
```json
42+
{
43+
"rules": [
44+
{
45+
"pattern": "^config/(.+)/.*",
46+
"scope": "$1"
47+
},
48+
{
49+
"pattern": "^scripts/(.+)/.*",
50+
"scope": "$1"
51+
},
52+
{
53+
"pattern": "^data/(.+)/.*",
54+
"scope": "$1"
55+
},
56+
{
57+
"pattern": "^\\.github/.*",
58+
"scope": "github"
59+
},
60+
{
61+
"pattern": ".*",
62+
"scope": "dotfiles"
63+
}
64+
]
65+
}
66+
```
67+
68+
Rules are evaluated in the order they are defined. The first rule that matches a file path determines its scope. The last rule `(.*)` acts as a catch-all for files not matching any preceding rules.
69+
70+
### GitHub Actions Workflow
71+
72+
The CI is implemented as a GitHub Actions workflow defined in `.github/workflows/check_pr_scope.yml`. It triggers on `pull_request` events (`opened`, `synchronize`, `reopened`, `edited`).
73+
74+
No special setup is required beyond having this workflow file and the `scope-rules.json` in the repository.
75+
76+
## Troubleshooting
77+
78+
- **CI Failure with PR Comment**: If the CI fails, it will post a comment on your PR explaining the reason.
79+
- **"PR title does not contain a valid scope."**: Ensure your PR title follows the format `type(scope): message`. If no specific scope applies, but changes are made, consider if `dotfiles` or another general scope is appropriate, or use `type(*): message`. The comment will provide examples.
80+
- **"PR title scopes do not cover all changed files. Missing scopes for: [scope_list]"**: Your PR title is missing one or more scopes that correspond to the files you've changed. Add the missing scopes to your PR title (e.g., `fix(scopeA,scopeB): resolve issues`). The comment will list the missing scopes and suggest how to update the title.
81+
- **"No matching scope rule for file: [filepath]"**: This is a warning output in the CI logs (not a PR comment). While it doesn't fail the CI, it indicates that a changed file didn't match any specific rule in `scope-rules.json` and wasn't assigned a scope. This might mean a new rule needs to be added to `scope-rules.json` or the default "dotfiles" scope (if it's the last rule) is being applied implicitly. If the file should have a specific scope, update the rules.
82+
83+
This provides a good overview for users of the repository.

0 commit comments

Comments
 (0)