Skip to content

Commit 20cbf1e

Browse files
Add PR summary generation workflow and update pull request template for clarity
1 parent cf94321 commit 20cbf1e

File tree

2 files changed

+159
-9
lines changed

2 files changed

+159
-9
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
# Description
1+
# Pull Request
22

3-
<!-- Provide a brief description of the changes in this PR -->
4-
<!-- tip: use GitHub Copilot to generate description -->
3+
## Summary
4+
5+
<!-- Describe what changed and why -->
56

67
## Type of Change
78

8-
<!-- Select one by placing an 'x' in the brackets -->
9-
- [ ] Bug fix
10-
- [ ] New feature
11-
- [ ] Breaking change
12-
- [ ] Documentation update
13-
- [ ] Code quality improvement (refactoring, tests, performance)
9+
- [ ] feat: New feature or enhancement
10+
- [ ] fix: Bug fix
11+
- [ ] breaking: Breaking change
12+
- [ ] docs: Documentation only
13+
- [ ] chore: Maintenance / tooling
14+
- [ ] refactor: Refactoring without behavior change
15+
16+
## Checklist
17+
18+
- [ ] Tests added or updated
19+
- [ ] `Invoke-Build -Task Test` passes locally
20+
- [ ] Help updated if a public function was added or changed
21+
- [ ] No secrets or environment-specific values introduced

.github/workflows/pr-summary.yml

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: PR Summary
2+
run-name: "${{ github.event.repository.name }} | PR Summary | #${{ github.event.pull_request.number }}"
3+
permissions: read-all
4+
5+
on:
6+
pull_request:
7+
types: [opened]
8+
9+
jobs:
10+
generate:
11+
name: Generate PR Summary
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
pull-requests: write
16+
steps:
17+
- name: Pre-fill PR body
18+
uses: actions/github-script@v7
19+
with:
20+
github-token: ${{ secrets.GITHUB_TOKEN }}
21+
script: |
22+
const pr = context.payload.pull_request;
23+
const branchName = pr.head.ref;
24+
25+
// Detect semantic type from branch prefix
26+
const typeMap = {
27+
'feat': 'feat', 'feature': 'feat', 'add': 'feat',
28+
'fix': 'fix', 'bugfix': 'fix', 'hotfix': 'fix', 'patch': 'fix',
29+
'security': 'fix', 'sec': 'fix',
30+
'breaking': 'breaking', 'major': 'breaking',
31+
'docs': 'docs', 'doc': 'docs',
32+
'chore': 'chore',
33+
'refactor': 'refactor', 'refac': 'refactor', 'cleanup': 'refactor'
34+
};
35+
const prefix = branchName.split('/')[0];
36+
const detectedType = typeMap[prefix] || null;
37+
38+
// Get changed files
39+
const { data: files } = await github.rest.pulls.listFiles({
40+
owner: context.repo.owner,
41+
repo: context.repo.repo,
42+
pull_number: pr.number
43+
});
44+
45+
// Classify each file by area (mirrors visual signal labels)
46+
function classifyFile(filename) {
47+
if (/^src\/.+\.Tests\.ps1$/.test(filename)) return 'tests';
48+
if (/^src\/.+\.(ps1|psd1)$/.test(filename)) return 'cmdlets';
49+
if (/^tests\/Integration\//.test(filename)) return 'tests';
50+
if (/^tests\/PSScriptAnalyzer\//.test(filename)) return 'lint';
51+
if (/^tests\/InjectionHunter\//.test(filename)) return 'security';
52+
if (/^\.github\/workflows\//.test(filename)) return 'ci';
53+
if (/^\.github\/actions\//.test(filename)) return 'ci';
54+
if (/^\.github\/DOCS_TEMPLATE\//.test(filename)) return 'template';
55+
if (/^(AGENTS\.md|\.github\/copilot-instructions\.md)$/.test(filename)) return 'agents';
56+
if (/^(docs\/|README\.md|CONTRIBUTING\.md)/.test(filename)) return 'docs';
57+
if (/\.build\.ps1$|^GitVersion\.yml$/.test(filename)) return 'build';
58+
if (/^\.vscode\//.test(filename)) return 'vscode';
59+
if (/^\.devcontainer\//.test(filename)) return 'devcontainer';
60+
if (/^(requirements\.psd1|\.github\/dependabot\.yml)$/.test(filename)) return 'dependencies';
61+
if (/^\.github\//.test(filename)) return 'github';
62+
return 'other';
63+
}
64+
65+
const areaLabel = {
66+
cmdlets: '📦 Source',
67+
tests: '🧪 Tests',
68+
lint: '🔍 Lint',
69+
security: '🔒 Security',
70+
ci: '⚙️ CI/CD',
71+
build: '🔨 Build',
72+
docs: '📚 Docs',
73+
agents: '🤖 Agents',
74+
template: '📋 Template',
75+
vscode: '💻 VS Code',
76+
devcontainer: '🐳 Dev Container',
77+
github: '🐙 GitHub',
78+
dependencies: '📦 Dependencies',
79+
other: '📄 Other'
80+
};
81+
82+
// Group files by area
83+
const grouped = {};
84+
for (const file of files) {
85+
const area = classifyFile(file.filename);
86+
if (!grouped[area]) grouped[area] = [];
87+
grouped[area].push(file.filename);
88+
}
89+
90+
// Build changed areas table
91+
const rows = Object.entries(grouped)
92+
.map(([area, areaFiles]) => {
93+
const label = areaLabel[area] || area;
94+
const fileList = areaFiles.map(f => `\`${f}\``).join('<br>');
95+
return `| ${label} | ${fileList} |`;
96+
})
97+
.join('\n');
98+
const changesTable = `| Area | Files |\n|------|-------|\n${rows}`;
99+
100+
// Build type of change checklist — auto-check detected type
101+
const types = [
102+
['feat', 'feat: New feature or enhancement'],
103+
['fix', 'fix: Bug fix'],
104+
['breaking', 'breaking: Breaking change'],
105+
['docs', 'docs: Documentation only'],
106+
['chore', 'chore: Maintenance / tooling'],
107+
['refactor', 'refactor: Refactoring without behavior change']
108+
];
109+
const typeChecklist = types
110+
.map(([key, label]) => `- [${detectedType === key ? 'x' : ' '}] ${label}`)
111+
.join('\n');
112+
113+
// Compose final body
114+
const body = [
115+
'## Summary',
116+
'',
117+
'> ✏️ Auto-generated — replace this with a description of what and why.',
118+
'',
119+
`**Branch:** \`${branchName}\``,
120+
'',
121+
'## Changed Areas',
122+
'',
123+
changesTable,
124+
'',
125+
'## Type of Change',
126+
'',
127+
typeChecklist,
128+
'',
129+
'## Checklist',
130+
'',
131+
'- [ ] Tests added or updated',
132+
'- [ ] `Invoke-Build -Task Test` passes locally',
133+
'- [ ] Help updated if a public function was added or changed',
134+
'- [ ] No secrets or environment-specific values introduced'
135+
].join('\n');
136+
137+
await github.rest.pulls.update({
138+
owner: context.repo.owner,
139+
repo: context.repo.repo,
140+
pull_number: pr.number,
141+
body
142+
});

0 commit comments

Comments
 (0)