Skip to content

Commit 380669d

Browse files
committed
update exlude pattern for commit filter if start and end are from different branch
1 parent d24569d commit 380669d

File tree

2 files changed

+67
-56
lines changed

2 files changed

+67
-56
lines changed

.github/actions/spell-check/excludes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
\.xz$
9494
\.zip$
9595
^\.github/actions/spell-check/
96+
^\.github/skills/
9697
^\.github/workflows/spelling\d*\.yml$
9798
^\.gitmodules$
9899
^\Q.pipelines/ESRPSigning_core.json\E$

.github/skills/changelog-generator/sub-skills/commit-filtering.md

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,81 +2,91 @@
22

33
This sub-skill defines rules for filtering commits to include in the changelog.
44

5-
## Filter Out Commits Already in Start Tag
5+
## Understanding the Branch Model
66

7-
**CRITICAL: Skip commits that are already included in the start tag to avoid duplicates.**
7+
PowerToys uses a release branch model where fixes are cherry-picked from main:
88

9-
This happens when:
10-
- Cherry-picks from main to stable branch
11-
- Backported fixes that were already released
12-
- Commits included in a previous release
13-
14-
### Method 1: Git Merge-Base (Local, Most Reliable)
15-
16-
```powershell
17-
$startTag = "v0.96.0"
18-
$commitSha = "abc1234"
19-
20-
# Check if commit is ancestor of (already included in) start tag
21-
# Returns exit code 0 if true, 1 if false
22-
git merge-base --is-ancestor $commitSha $startTag
23-
if ($LASTEXITCODE -eq 0) {
24-
Write-Host "SKIP: Commit $commitSha already in $startTag"
25-
} else {
26-
Write-Host "PROCESS: Commit $commitSha is new"
27-
}
9+
```
10+
main: A---B---C---D---E---F---G---H (HEAD)
11+
\
12+
release: X---Y---Z (v0.96.1 tag)
13+
14+
(X, Y are cherry-picks of C, E from main)
2815
```
2916

30-
### Method 2: GitHub API Compare (Auto-Filtered)
31-
32-
```powershell
33-
# The compare API already handles this - it returns only commits
34-
# that are in the "head" but NOT in the "base"
35-
$compare = gh api repos/microsoft/PowerToys/compare/v0.96.0...v0.96.1 | ConvertFrom-Json
17+
**Key insight:** When comparing `v0.96.1...main`:
18+
- The release tag (v0.96.1) is on a **different branch** than main
19+
- GitHub compare finds the merge-base and returns commits on main after that point
20+
- Commits C and E appear in the results even though they were cherry-picked to release as X and Y
21+
- **The SHAs are different**, so SHA-based filtering won't work!
3622

37-
# These commits are guaranteed to be NEW (not in v0.96.0)
38-
$newCommits = $compare.commits
39-
Write-Host "Found $($newCommits.Count) new commits not in start tag"
40-
```
23+
## ⚠️ CRITICAL: Filter by PR Number, Not SHA
4124

42-
### Method 3: Check Tags Containing Commit
25+
Since cherry-picks have different SHAs, you **MUST** check by PR number:
4326

4427
```powershell
45-
$commitSha = "abc1234"
46-
$tagsContaining = git tag --contains $commitSha
47-
if ($tagsContaining -match "v0\.96\.0") {
48-
Write-Host "SKIP: Commit already released in v0.96.0"
28+
# Extract PR number from commit message and check if it exists in the release tag
29+
$prNumber = "43785"
30+
$startTag = "v0.96.1"
31+
32+
# Search the release branch for this PR number in commit messages
33+
$cherryPicked = git log $startTag --oneline --grep="#$prNumber"
34+
if ($cherryPicked) {
35+
Write-Host "SKIP: PR #$prNumber was cherry-picked to $startTag"
36+
} else {
37+
Write-Host "INCLUDE: PR #$prNumber is new since $startTag"
4938
}
5039
```
5140

52-
## Batch Filter Script
41+
## Complete Filtering Workflow
5342

5443
```powershell
55-
$startTag = "v0.96.0"
56-
$endTag = "v0.96.1"
57-
58-
# Get commits from compare (already filtered - only new commits)
59-
$newCommits = gh api repos/microsoft/PowerToys/compare/$startTag...$endTag --jq '.commits[] | {sha: .sha, message: .commit.message}' | ConvertFrom-Json
60-
61-
# Additional validation: filter out any merge commits that reference old PRs
62-
$filteredCommits = $newCommits | Where-Object {
63-
$sha = $_.sha
64-
# Double-check: ensure commit is not ancestor of start tag
65-
git merge-base --is-ancestor $sha $startTag 2>$null
66-
$LASTEXITCODE -ne 0 # Keep only if NOT an ancestor
44+
$startTag = "v0.96.1" # Release tag (on release branch)
45+
$endRef = "main" # Target (main branch)
46+
47+
# Step 1: Get all commits from main since the merge-base with release tag
48+
$commits = gh api "repos/microsoft/PowerToys/compare/$startTag...$endRef" `
49+
--jq '.commits[] | {sha: .sha, message: .commit.message}' | ConvertFrom-Json
50+
51+
# Step 2: Build list of PR numbers already in the release tag
52+
$releasePRs = git log $startTag --oneline | Select-String -Pattern '#(\d+)' -AllMatches |
53+
ForEach-Object { $_.Matches.Groups[1].Value } | Sort-Object -Unique
54+
55+
Write-Host "PRs already in $startTag : $($releasePRs.Count)"
56+
57+
# Step 3: Filter commits - skip if PR was cherry-picked to release
58+
$newCommits = @()
59+
foreach ($commit in $commits) {
60+
if ($commit.message -match '#(\d+)') {
61+
$prNumber = $matches[1]
62+
if ($releasePRs -contains $prNumber) {
63+
Write-Host "SKIP: PR #$prNumber already in $startTag (cherry-picked)"
64+
continue
65+
}
66+
}
67+
$newCommits += $commit
6768
}
6869
69-
Write-Host "After filtering: $($filteredCommits.Count) commits to process"
70+
Write-Host "New commits to process: $($newCommits.Count)"
7071
```
7172

73+
## Why SHA-Based Methods Don't Work Here
74+
75+
| Method | Works for same branch? | Works for cross-branch (cherry-picks)? |
76+
|--------|------------------------|----------------------------------------|
77+
| `git merge-base --is-ancestor` | ✅ Yes | ❌ No - different SHAs |
78+
| `git tag --contains` | ✅ Yes | ❌ No - tag is on different branch |
79+
| GitHub Compare API | ✅ Yes | ❌ No - returns commits by SHA |
80+
| **PR number matching** | ✅ Yes |**Yes** |
81+
7282
## Skip Rules Summary
7383

74-
| Condition | Action |
75-
|-----------|--------|
76-
| `git merge-base --is-ancestor $sha $startTag` returns 0 | SKIP - already in start tag |
77-
| Commit message contains "cherry-pick" + old PR number | SKIP - likely backport |
78-
| PR was merged before start tag date | SKIP - old PR |
79-
| Same PR number already processed | SKIP - duplicate |
84+
| Priority | Condition | Action |
85+
|----------|-----------|--------|
86+
| 1 | PR number found in `git log $startTag --grep="#$prNumber"` | **SKIP** - cherry-picked |
87+
| 2 | Same PR number already processed in this run | **SKIP** - duplicate |
88+
| 3 | Bot author (dependabot, etc.) | **SKIP** - unless user-visible |
89+
| 4 | Internal-only change (CI, tests, refactor) | Move to **Development** section |
8090

8191
## User-Facing vs Non-User-Facing
8292

0 commit comments

Comments
 (0)