mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-11 14:56:48 +01:00
Compare commits
3 Commits
stable
...
dev/vanzue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
380669dd81 | ||
|
|
d24569d49c | ||
|
|
94cbea91a0 |
1
.github/actions/spell-check/excludes.txt
vendored
1
.github/actions/spell-check/excludes.txt
vendored
@@ -93,6 +93,7 @@
|
||||
\.xz$
|
||||
\.zip$
|
||||
^\.github/actions/spell-check/
|
||||
^\.github/skills/
|
||||
^\.github/workflows/spelling\d*\.yml$
|
||||
^\.gitmodules$
|
||||
^\Q.pipelines/ESRPSigning_core.json\E$
|
||||
|
||||
152
.github/skills/changelog-generator/SKILL.md
vendored
Normal file
152
.github/skills/changelog-generator/SKILL.md
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
---
|
||||
name: changelog-generator
|
||||
description: Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
|
||||
---
|
||||
|
||||
# Changelog Generator
|
||||
|
||||
This skill transforms technical git commits into polished, user-friendly changelogs that your customers and users will actually understand and appreciate.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Preparing release notes for a new version
|
||||
- Generating changelog between two tags/commits
|
||||
- Creating draft release notes from recent commits
|
||||
|
||||
## Quick Start
|
||||
|
||||
```
|
||||
Create a changelog from commits since v0.96.1
|
||||
```
|
||||
|
||||
```
|
||||
Create release notes for version 0.97.0 starting from tag v0.96.1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ 1. Fetch │───▶│ 2. Filter │───▶│ 3. Categorize│───▶│ 4. Generate │
|
||||
│ Commits │ │ & Dedupe │ │ by Module │ │ Descriptions │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
📄 github-api 📄 commit- 📄 module- 📄 user-facing-
|
||||
reference.md filtering.md mapping.md description.md
|
||||
```
|
||||
|
||||
## Sub-Skills Reference
|
||||
|
||||
This skill is composed of the following sub-skills.
|
||||
|
||||
**⚠️ IMPORTANT: Do NOT read all sub-skills at once!**
|
||||
- Only read a sub-skill when you reach that step in the workflow
|
||||
- This saves context window and improves accuracy
|
||||
- Use `read_file` to load a sub-skill only when needed
|
||||
|
||||
| Step | Sub-Skill | When to Read |
|
||||
|------|-----------|--------------|
|
||||
| Fetch data | [github-api-reference.md](sub-skills/github-api-reference.md) | When fetching commits/PRs |
|
||||
| Filter commits | [commit-filtering.md](sub-skills/commit-filtering.md) | When checking if commit should be skipped |
|
||||
| Categorize | [module-mapping.md](sub-skills/module-mapping.md) | When determining which module a PR belongs to |
|
||||
| Generate text | [user-facing-description.md](sub-skills/user-facing-description.md) | When writing the changelog entry text |
|
||||
| Attribution | [contributor-attribution.md](sub-skills/contributor-attribution.md) | When checking if author needs thanks |
|
||||
| Large releases | [progress-tracking.md](sub-skills/progress-tracking.md) | Only if processing 50+ commits |
|
||||
|
||||
---
|
||||
|
||||
## Step-by-Step Summary
|
||||
|
||||
### Step 1: Get Commit Range
|
||||
```powershell
|
||||
# Count commits between tags
|
||||
gh api repos/microsoft/PowerToys/compare/v0.96.0...v0.96.1 --jq '.commits | length'
|
||||
```
|
||||
👉 Details: [github-api-reference.md](sub-skills/github-api-reference.md)
|
||||
|
||||
### Step 2: Filter Commits
|
||||
- Skip commits already in start tag
|
||||
- Skip cherry-picks and backports
|
||||
- Deduplicate by PR number
|
||||
|
||||
👉 Details: [commit-filtering.md](sub-skills/commit-filtering.md)
|
||||
|
||||
### Step 3: For Each PR, Generate Entry
|
||||
1. Get PR title, body, files, labels
|
||||
2. Determine module from file paths or labels
|
||||
3. Check if user-facing (skip internal changes)
|
||||
4. Transform to user-friendly description
|
||||
5. Add contributor attribution if needed
|
||||
|
||||
👉 Details: [user-facing-description.md](sub-skills/user-facing-description.md), [module-mapping.md](sub-skills/module-mapping.md), [contributor-attribution.md](sub-skills/contributor-attribution.md)
|
||||
|
||||
### Step 4: Checkpoint (if 50+ commits)
|
||||
- Save progress after every 15-20 commits
|
||||
- Track processed PRs for deduplication
|
||||
- Enable resume from interruption
|
||||
|
||||
👉 Details: [progress-tracking.md](sub-skills/progress-tracking.md)
|
||||
|
||||
### Step 5: Format Output
|
||||
```markdown
|
||||
## ✨ What's new
|
||||
**Version X.XX (Month Year)**
|
||||
|
||||
**✨ Highlights**
|
||||
- [Most impactful change 1]
|
||||
- [Most impactful change 2]
|
||||
|
||||
### [Module Name - Alphabetical]
|
||||
- [Description]. Thanks [@contributor](https://github.com/contributor)!
|
||||
|
||||
### Development
|
||||
- [Internal changes]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example Output
|
||||
|
||||
```markdown
|
||||
## ✨ What's new
|
||||
**Version 0.96.1 (December 2025)**
|
||||
|
||||
**✨ Highlights**
|
||||
- Advanced Paste now supports multiple AI providers.
|
||||
- PowerRename can extract photo metadata for renaming.
|
||||
|
||||
### Advanced Paste
|
||||
- Added support for Azure OpenAI, Google Gemini, Mistral, and more.
|
||||
|
||||
### Awake
|
||||
- The countdown timer now stays accurate over long periods. Thanks [@daverayment](https://github.com/daverayment)!
|
||||
|
||||
### Development
|
||||
- Resolved build warnings in Command Palette projects.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tips
|
||||
|
||||
1. **Propose highlights** after all entries are generated
|
||||
2. **Check PR body** when title is unclear
|
||||
3. **Thank external contributors** - see [contributor-attribution.md](sub-skills/contributor-attribution.md)
|
||||
4. **Use progress tracking** for large releases - see [progress-tracking.md](sub-skills/progress-tracking.md)
|
||||
5. **Save output** to `release-change-note-draft.md`
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| Lost progress mid-generation | Read `release-notes-progress.md` to resume |
|
||||
| Duplicate entries | Check processed PR list, dedupe by PR number |
|
||||
| Commit already released | Use `git merge-base --is-ancestor` to verify |
|
||||
| API rate limited | Check `gh api rate_limit`, wait or use token |
|
||||
|
||||
👉 See sub-skills for detailed troubleshooting.
|
||||
107
.github/skills/changelog-generator/sub-skills/commit-filtering.md
vendored
Normal file
107
.github/skills/changelog-generator/sub-skills/commit-filtering.md
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
# Commit Filtering Rules
|
||||
|
||||
This sub-skill defines rules for filtering commits to include in the changelog.
|
||||
|
||||
## Understanding the Branch Model
|
||||
|
||||
PowerToys uses a release branch model where fixes are cherry-picked from main:
|
||||
|
||||
```
|
||||
main: A---B---C---D---E---F---G---H (HEAD)
|
||||
\
|
||||
release: X---Y---Z (v0.96.1 tag)
|
||||
↑
|
||||
(X, Y are cherry-picks of C, E from main)
|
||||
```
|
||||
|
||||
**Key insight:** When comparing `v0.96.1...main`:
|
||||
- The release tag (v0.96.1) is on a **different branch** than main
|
||||
- GitHub compare finds the merge-base and returns commits on main after that point
|
||||
- Commits C and E appear in the results even though they were cherry-picked to release as X and Y
|
||||
- **The SHAs are different**, so SHA-based filtering won't work!
|
||||
|
||||
## ⚠️ CRITICAL: Filter by PR Number, Not SHA
|
||||
|
||||
Since cherry-picks have different SHAs, you **MUST** check by PR number:
|
||||
|
||||
```powershell
|
||||
# Extract PR number from commit message and check if it exists in the release tag
|
||||
$prNumber = "43785"
|
||||
$startTag = "v0.96.1"
|
||||
|
||||
# Search the release branch for this PR number in commit messages
|
||||
$cherryPicked = git log $startTag --oneline --grep="#$prNumber"
|
||||
if ($cherryPicked) {
|
||||
Write-Host "SKIP: PR #$prNumber was cherry-picked to $startTag"
|
||||
} else {
|
||||
Write-Host "INCLUDE: PR #$prNumber is new since $startTag"
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Filtering Workflow
|
||||
|
||||
```powershell
|
||||
$startTag = "v0.96.1" # Release tag (on release branch)
|
||||
$endRef = "main" # Target (main branch)
|
||||
|
||||
# Step 1: Get all commits from main since the merge-base with release tag
|
||||
$commits = gh api "repos/microsoft/PowerToys/compare/$startTag...$endRef" `
|
||||
--jq '.commits[] | {sha: .sha, message: .commit.message}' | ConvertFrom-Json
|
||||
|
||||
# Step 2: Build list of PR numbers already in the release tag
|
||||
$releasePRs = git log $startTag --oneline | Select-String -Pattern '#(\d+)' -AllMatches |
|
||||
ForEach-Object { $_.Matches.Groups[1].Value } | Sort-Object -Unique
|
||||
|
||||
Write-Host "PRs already in $startTag : $($releasePRs.Count)"
|
||||
|
||||
# Step 3: Filter commits - skip if PR was cherry-picked to release
|
||||
$newCommits = @()
|
||||
foreach ($commit in $commits) {
|
||||
if ($commit.message -match '#(\d+)') {
|
||||
$prNumber = $matches[1]
|
||||
if ($releasePRs -contains $prNumber) {
|
||||
Write-Host "SKIP: PR #$prNumber already in $startTag (cherry-picked)"
|
||||
continue
|
||||
}
|
||||
}
|
||||
$newCommits += $commit
|
||||
}
|
||||
|
||||
Write-Host "New commits to process: $($newCommits.Count)"
|
||||
```
|
||||
|
||||
## Why SHA-Based Methods Don't Work Here
|
||||
|
||||
| Method | Works for same branch? | Works for cross-branch (cherry-picks)? |
|
||||
|--------|------------------------|----------------------------------------|
|
||||
| `git merge-base --is-ancestor` | ✅ Yes | ❌ No - different SHAs |
|
||||
| `git tag --contains` | ✅ Yes | ❌ No - tag is on different branch |
|
||||
| GitHub Compare API | ✅ Yes | ❌ No - returns commits by SHA |
|
||||
| **PR number matching** | ✅ Yes | ✅ **Yes** |
|
||||
|
||||
## Skip Rules Summary
|
||||
|
||||
| Priority | Condition | Action |
|
||||
|----------|-----------|--------|
|
||||
| 1 | PR number found in `git log $startTag --grep="#$prNumber"` | **SKIP** - cherry-picked |
|
||||
| 2 | Same PR number already processed in this run | **SKIP** - duplicate |
|
||||
| 3 | Bot author (dependabot, etc.) | **SKIP** - unless user-visible |
|
||||
| 4 | Internal-only change (CI, tests, refactor) | Move to **Development** section |
|
||||
|
||||
## User-Facing vs Non-User-Facing
|
||||
|
||||
**Include in changelog:**
|
||||
- New features and capabilities
|
||||
- Bug fixes that affect users
|
||||
- UI/UX improvements
|
||||
- Performance improvements users would notice
|
||||
- Breaking changes or behavior modifications
|
||||
- Security fixes
|
||||
|
||||
**Exclude from changelog (put in Development section):**
|
||||
- Internal refactoring
|
||||
- CI/CD changes
|
||||
- Code style fixes
|
||||
- Test additions/modifications
|
||||
- Documentation-only changes
|
||||
- Dependency updates (unless user-visible impact)
|
||||
110
.github/skills/changelog-generator/sub-skills/contributor-attribution.md
vendored
Normal file
110
.github/skills/changelog-generator/sub-skills/contributor-attribution.md
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
# Contributor Attribution Rules
|
||||
|
||||
This sub-skill defines when and how to credit contributors in changelog entries.
|
||||
|
||||
## Attribution Rules
|
||||
|
||||
- Check [COMMUNITY.md](../../../COMMUNITY.md) for the "PowerToys core team" section
|
||||
- If author is **NOT** in core team → Add `Thanks [@username](https://github.com/username)!`
|
||||
- If author **IS** in core team → No attribution needed
|
||||
- Microsoft employees working on PowerToys as their job → No attribution needed
|
||||
|
||||
## Core Team Members
|
||||
|
||||
Current core team members (from COMMUNITY.md) - do NOT thank these:
|
||||
|
||||
```
|
||||
@craigloewen-msft, @niels9001, @dhowett, @yeelam-gordon, @jamrobot,
|
||||
@lei9444, @shuaiyuanxx, @moooyo, @haoliuu, @chenmy77, @chemwolf6922,
|
||||
@yaqingmi, @zhaoqpcn, @urnotdfs, @zhaopy536, @wang563681252, @vanzue,
|
||||
@zadjii-msft, @khmyznikov, @chatasweetie, @MichaelJolley, @Jaylyn-Barbee,
|
||||
@zateutsch, @crutkas
|
||||
```
|
||||
|
||||
## Check Author Script
|
||||
|
||||
```powershell
|
||||
$coreTeam = @(
|
||||
'craigloewen-msft', 'niels9001', 'dhowett', 'yeelam-gordon', 'jamrobot',
|
||||
'lei9444', 'shuaiyuanxx', 'moooyo', 'haoliuu', 'chenmy77', 'chemwolf6922',
|
||||
'yaqingmi', 'zhaoqpcn', 'urnotdfs', 'zhaopy536', 'wang563681252', 'vanzue',
|
||||
'zadjii-msft', 'khmyznikov', 'chatasweetie', 'MichaelJolley', 'Jaylyn-Barbee',
|
||||
'zateutsch', 'crutkas'
|
||||
)
|
||||
|
||||
function Get-Attribution {
|
||||
param([string]$author)
|
||||
|
||||
if ($coreTeam -contains $author) {
|
||||
return $null # No attribution needed
|
||||
}
|
||||
return "Thanks [@$author](https://github.com/$author)!"
|
||||
}
|
||||
|
||||
# Usage
|
||||
$author = gh pr view 12345 --repo microsoft/PowerToys --json author --jq '.author.login'
|
||||
$attribution = Get-Attribution $author
|
||||
if ($attribution) {
|
||||
Write-Host "Add: $attribution"
|
||||
} else {
|
||||
Write-Host "No attribution needed (core team member)"
|
||||
}
|
||||
```
|
||||
|
||||
## Attribution Format
|
||||
|
||||
**With attribution:**
|
||||
```markdown
|
||||
- The Awake countdown timer now stays accurate over long periods. Thanks [@daverayment](https://github.com/daverayment)!
|
||||
```
|
||||
|
||||
**Without attribution (core team):**
|
||||
```markdown
|
||||
- Added new feature to Command Palette for opening settings.
|
||||
```
|
||||
|
||||
## Special Cases
|
||||
|
||||
1. **Co-authored commits**: Credit the primary author (first in list)
|
||||
2. **Bot accounts** (dependabot, etc.): No attribution
|
||||
3. **Former core team members**: Check if they were core team at time of PR
|
||||
4. **Multiple PRs by same external contributor**: Thank them on each entry
|
||||
|
||||
## High-Impact Community Members
|
||||
|
||||
These contributors have made significant ongoing contributions and are recognized in COMMUNITY.md.
|
||||
**ALWAYS thank these contributors** - they are NOT core team and deserve recognition:
|
||||
|
||||
```
|
||||
@davidegiacometti, @htcfreek, @daverayment, @jiripolasek
|
||||
```
|
||||
|
||||
Check COMMUNITY.md for the full up-to-date list under "High impact community members" section.
|
||||
|
||||
## Updated Check Author Script
|
||||
|
||||
```powershell
|
||||
$coreTeam = @(
|
||||
'craigloewen-msft', 'niels9001', 'dhowett', 'yeelam-gordon', 'jamrobot',
|
||||
'lei9444', 'shuaiyuanxx', 'moooyo', 'haoliuu', 'chenmy77', 'chemwolf6922',
|
||||
'yaqingmi', 'zhaoqpcn', 'urnotdfs', 'zhaopy536', 'wang563681252', 'vanzue',
|
||||
'zadjii-msft', 'khmyznikov', 'chatasweetie', 'MichaelJolley', 'Jaylyn-Barbee',
|
||||
'zateutsch', 'crutkas'
|
||||
)
|
||||
|
||||
# High-impact community members - ALWAYS thank these!
|
||||
$highImpactCommunity = @(
|
||||
'davidegiacometti', 'htcfreek', 'daverayment', 'jiripolasek'
|
||||
)
|
||||
|
||||
function Get-Attribution {
|
||||
param([string]$author)
|
||||
|
||||
# Core team and bots don't need thanks
|
||||
if ($coreTeam -contains $author -or $author -match '\[bot\]$') {
|
||||
return $null
|
||||
}
|
||||
# Everyone else (including high-impact community) gets thanked
|
||||
return "Thanks [@$author](https://github.com/$author)!"
|
||||
}
|
||||
```
|
||||
101
.github/skills/changelog-generator/sub-skills/github-api-reference.md
vendored
Normal file
101
.github/skills/changelog-generator/sub-skills/github-api-reference.md
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
# GitHub API Reference for Changelog Generation
|
||||
|
||||
This sub-skill provides GitHub API commands and scripts for fetching commit and PR data.
|
||||
|
||||
## Authentication
|
||||
|
||||
```powershell
|
||||
# Ensure gh CLI is authenticated
|
||||
gh auth status
|
||||
|
||||
# Or use personal access token
|
||||
$headers = @{ Authorization = "token $env:GITHUB_TOKEN" }
|
||||
```
|
||||
|
||||
## Useful API Endpoints
|
||||
|
||||
```powershell
|
||||
# Compare two refs (tags, branches, commits)
|
||||
gh api repos/microsoft/PowerToys/compare/v0.96.0...v0.96.1
|
||||
|
||||
# List commits with pagination
|
||||
gh api "repos/microsoft/PowerToys/commits?per_page=100&page=1"
|
||||
|
||||
# Get PR associated with a commit
|
||||
gh api repos/microsoft/PowerToys/commits/{sha}/pulls
|
||||
|
||||
# Get PR details
|
||||
gh api repos/microsoft/PowerToys/pulls/{number}
|
||||
|
||||
# Get files changed in a PR
|
||||
gh api repos/microsoft/PowerToys/pulls/{number}/files
|
||||
|
||||
# Search PRs merged in date range
|
||||
gh api "search/issues?q=repo:microsoft/PowerToys+is:pr+is:merged+merged:2025-01-01..2025-01-31"
|
||||
```
|
||||
|
||||
## Fetch Commits in Range
|
||||
|
||||
```powershell
|
||||
$owner = "microsoft"
|
||||
$repo = "PowerToys"
|
||||
$startTag = "v0.96.0"
|
||||
$endTag = "v0.96.1"
|
||||
|
||||
# Get all commits between two tags
|
||||
gh api repos/$owner/$repo/compare/$startTag...$endTag --jq '.commits[] | {sha: .sha, message: .commit.message, author: .author.login, date: .commit.author.date}'
|
||||
```
|
||||
|
||||
## Get PR Details for a Commit
|
||||
|
||||
```powershell
|
||||
# Get PR associated with a commit SHA
|
||||
gh api "repos/$owner/$repo/commits/{sha}/pulls" --jq '.[0] | {number: .number, title: .title, body: .body, user: .user.login, labels: [.labels[].name]}'
|
||||
|
||||
# Get full PR details
|
||||
gh pr view 1234 --repo microsoft/PowerToys --json title,body,author,files,labels,mergedAt
|
||||
```
|
||||
|
||||
## Batch Processing Script
|
||||
|
||||
```powershell
|
||||
$startTag = "v0.96.0"
|
||||
$endTag = "v0.96.1"
|
||||
|
||||
$commits = gh api repos/microsoft/PowerToys/compare/$startTag...$endTag --jq '.commits[].sha' | ForEach-Object {
|
||||
$sha = $_
|
||||
$prInfo = gh api "repos/microsoft/PowerToys/commits/$sha/pulls" 2>$null | ConvertFrom-Json
|
||||
if ($prInfo) {
|
||||
[PSCustomObject]@{
|
||||
SHA = $sha
|
||||
PRNumber = $prInfo[0].number
|
||||
Title = $prInfo[0].title
|
||||
Author = $prInfo[0].user.login
|
||||
Labels = $prInfo[0].labels.name -join ", "
|
||||
}
|
||||
}
|
||||
}
|
||||
$commits | Format-Table
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
```powershell
|
||||
# Check remaining rate limit
|
||||
gh api rate_limit --jq '.rate'
|
||||
# Authenticated: 5000 requests/hour
|
||||
# Unauthenticated: 60 requests/hour
|
||||
```
|
||||
|
||||
## Pagination for Large Results
|
||||
|
||||
```powershell
|
||||
# GitHub API returns max 100 items per page
|
||||
$page = 1
|
||||
$allCommits = @()
|
||||
do {
|
||||
$commits = gh api "repos/$owner/$repo/commits?per_page=100&page=$page" | ConvertFrom-Json
|
||||
$allCommits += $commits
|
||||
$page++
|
||||
} while ($commits.Count -eq 100)
|
||||
```
|
||||
137
.github/skills/changelog-generator/sub-skills/module-mapping.md
vendored
Normal file
137
.github/skills/changelog-generator/sub-skills/module-mapping.md
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
# PowerToys Module Path Mapping
|
||||
|
||||
This sub-skill maps file paths to PowerToys module names for categorization.
|
||||
|
||||
## Module Path Mapping Table
|
||||
|
||||
| Module | Path Pattern |
|
||||
|--------|--------------|
|
||||
| Advanced Paste | `src/modules/AdvancedPaste/**` |
|
||||
| Always On Top | `src/modules/alwaysontop/**` |
|
||||
| Awake | `src/modules/Awake/**` |
|
||||
| Color Picker | `src/modules/colorPicker/**` |
|
||||
| Command Palette | `src/modules/cmdpal/**` |
|
||||
| Crop And Lock | `src/modules/CropAndLock/**` |
|
||||
| Environment Variables | `src/modules/EnvironmentVariables/**` |
|
||||
| FancyZones | `src/modules/fancyzones/**` |
|
||||
| File Explorer Add-ons | `src/modules/previewpane/**`, `src/modules/FileExplorerPreview/**` |
|
||||
| File Locksmith | `src/modules/FileLocksmith/**` |
|
||||
| Find My Mouse | `src/modules/MouseUtils/FindMyMouse/**` |
|
||||
| Hosts File Editor | `src/modules/Hosts/**` |
|
||||
| Image Resizer | `src/modules/imageresizer/**` |
|
||||
| Keyboard Manager | `src/modules/keyboardmanager/**` |
|
||||
| Light Switch | `src/modules/LightSwitch/**` |
|
||||
| Mouse Highlighter | `src/modules/MouseUtils/MouseHighlighter/**` |
|
||||
| Mouse Jump | `src/modules/MouseUtils/MouseJump/**` |
|
||||
| Mouse Pointer Crosshairs | `src/modules/MouseUtils/MousePointerCrosshairs/**` |
|
||||
| Mouse Without Borders | `src/modules/MouseWithoutBorders/**` |
|
||||
| New+ | `src/modules/NewPlus/**` |
|
||||
| Paste As Plain Text | `src/modules/PastePlain/**` |
|
||||
| Peek | `src/modules/Peek/**` |
|
||||
| PowerRename | `src/modules/powerrename/**` |
|
||||
| PowerToys Run | `src/modules/launcher/**` |
|
||||
| Quick Accent | `src/modules/QuickAccent/**` |
|
||||
| Registry Preview | `src/modules/RegistryPreview/**` |
|
||||
| Screen Ruler | `src/modules/MeasureTool/**` |
|
||||
| Shortcut Guide | `src/modules/ShortcutGuide/**` |
|
||||
| Text Extractor | `src/modules/TextExtractor/**` |
|
||||
| Video Conference Mute | `src/modules/videoconference/**` |
|
||||
| Workspaces | `src/modules/Workspaces/**` |
|
||||
| ZoomIt | `src/modules/ZoomIt/**` |
|
||||
| Settings | `src/settings-ui/**` |
|
||||
| Runner | `src/runner/**` |
|
||||
| Installer | `installer/**` |
|
||||
| General / Infrastructure | `src/common/**`, `.github/**`, `tools/**` |
|
||||
|
||||
## Categorization by PR Labels
|
||||
|
||||
Common PowerToys PR labels for modules:
|
||||
- `Product-FancyZones`
|
||||
- `Product-PowerToys Run`
|
||||
- `Product-Awake`
|
||||
- `Product-ColorPicker`
|
||||
- `Product-Keyboard Manager`
|
||||
- etc.
|
||||
|
||||
## Auto-Categorization Script
|
||||
|
||||
```powershell
|
||||
function Get-ModuleFromPath {
|
||||
param([string]$filePath)
|
||||
|
||||
$moduleMap = @{
|
||||
'src/modules/AdvancedPaste/' = 'Advanced Paste'
|
||||
'src/modules/alwaysontop/' = 'Always On Top'
|
||||
'src/modules/Awake/' = 'Awake'
|
||||
'src/modules/colorPicker/' = 'Color Picker'
|
||||
'src/modules/cmdpal/' = 'Command Palette'
|
||||
'src/modules/CropAndLock/' = 'Crop And Lock'
|
||||
'src/modules/EnvironmentVariables/' = 'Environment Variables'
|
||||
'src/modules/fancyzones/' = 'FancyZones'
|
||||
'src/modules/previewpane/' = 'File Explorer Add-ons'
|
||||
'src/modules/FileExplorerPreview/' = 'File Explorer Add-ons'
|
||||
'src/modules/FileLocksmith/' = 'File Locksmith'
|
||||
'src/modules/MouseUtils/FindMyMouse/' = 'Find My Mouse'
|
||||
'src/modules/Hosts/' = 'Hosts File Editor'
|
||||
'src/modules/imageresizer/' = 'Image Resizer'
|
||||
'src/modules/keyboardmanager/' = 'Keyboard Manager'
|
||||
'src/modules/LightSwitch/' = 'Light Switch'
|
||||
'src/modules/MouseUtils/MouseHighlighter/' = 'Mouse Highlighter'
|
||||
'src/modules/MouseUtils/MouseJump/' = 'Mouse Jump'
|
||||
'src/modules/MouseUtils/MousePointerCrosshairs/' = 'Mouse Pointer Crosshairs'
|
||||
'src/modules/MouseWithoutBorders/' = 'Mouse Without Borders'
|
||||
'src/modules/NewPlus/' = 'New+'
|
||||
'src/modules/PastePlain/' = 'Paste As Plain Text'
|
||||
'src/modules/Peek/' = 'Peek'
|
||||
'src/modules/powerrename/' = 'PowerRename'
|
||||
'src/modules/launcher/' = 'PowerToys Run'
|
||||
'src/modules/QuickAccent/' = 'Quick Accent'
|
||||
'src/modules/RegistryPreview/' = 'Registry Preview'
|
||||
'src/modules/MeasureTool/' = 'Screen Ruler'
|
||||
'src/modules/ShortcutGuide/' = 'Shortcut Guide'
|
||||
'src/modules/TextExtractor/' = 'Text Extractor'
|
||||
'src/modules/videoconference/' = 'Video Conference Mute'
|
||||
'src/modules/Workspaces/' = 'Workspaces'
|
||||
'src/modules/ZoomIt/' = 'ZoomIt'
|
||||
'src/settings-ui/' = 'Settings'
|
||||
'src/runner/' = 'Runner'
|
||||
'installer/' = 'Installer'
|
||||
'src/common/' = 'General'
|
||||
'.github/' = 'Development'
|
||||
'tools/' = 'Development'
|
||||
}
|
||||
|
||||
foreach ($pattern in $moduleMap.Keys) {
|
||||
if ($filePath -like "*$pattern*") {
|
||||
return $moduleMap[$pattern]
|
||||
}
|
||||
}
|
||||
return 'General'
|
||||
}
|
||||
|
||||
# Usage: categorize a PR by its changed files
|
||||
$files = gh pr view 12345 --repo microsoft/PowerToys --json files --jq '.files[].path'
|
||||
$modules = $files | ForEach-Object { Get-ModuleFromPath $_ } | Sort-Object -Unique
|
||||
Write-Host "PR affects modules: $($modules -join ', ')"
|
||||
```
|
||||
|
||||
## Output Organization
|
||||
|
||||
Modules should be listed in **alphabetical order** in the changelog:
|
||||
|
||||
```markdown
|
||||
### Advanced Paste
|
||||
- ...
|
||||
|
||||
### Awake
|
||||
- ...
|
||||
|
||||
### Command Palette
|
||||
- ...
|
||||
|
||||
### General
|
||||
- ...
|
||||
|
||||
### Development
|
||||
- ...
|
||||
```
|
||||
121
.github/skills/changelog-generator/sub-skills/progress-tracking.md
vendored
Normal file
121
.github/skills/changelog-generator/sub-skills/progress-tracking.md
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
# Progress Tracking for Large Changelogs
|
||||
|
||||
This sub-skill provides the checkpoint mechanism for processing many commits without losing progress.
|
||||
|
||||
## When to Use Progress Tracking
|
||||
|
||||
- Processing 50+ commits
|
||||
- Long-running changelog generation
|
||||
- Risk of context overflow in AI conversations
|
||||
|
||||
## Checkpoint Mechanism
|
||||
|
||||
1. **Before starting**: Create a progress tracking file `release-notes-progress.md`
|
||||
2. **After each batch**: Append processed results to `release-change-note-draft.md`
|
||||
3. **Track position**: Record the last processed commit SHA in `release-notes-progress.md`
|
||||
|
||||
## Progress File Template
|
||||
|
||||
Create `release-notes-progress.md`:
|
||||
|
||||
```markdown
|
||||
# Release Notes Generation Progress
|
||||
|
||||
## Configuration
|
||||
- Start Tag: v0.96.0
|
||||
- End Tag: v0.96.1
|
||||
- Total Commits: 127
|
||||
- Batch Size: 20
|
||||
|
||||
## Progress Tracker
|
||||
| Batch | Status | Last SHA | PRs Processed |
|
||||
|-------|--------|----------|---------------|
|
||||
| 1 (1-20) | ✅ Done | abc1234 | #1001, #1002, #1003... |
|
||||
| 2 (21-40) | ✅ Done | def5678 | #1004, #1005... |
|
||||
| 3 (41-60) | 🔄 In Progress | ghi9012 | #1006... |
|
||||
| 4 (61-80) | ⏳ Pending | - | - |
|
||||
| 5 (81-100) | ⏳ Pending | - | - |
|
||||
| 6 (101-120) | ⏳ Pending | - | - |
|
||||
| 7 (121-127) | ⏳ Pending | - | - |
|
||||
|
||||
## Processed PRs (deduplication list)
|
||||
#1001, #1002, #1003, #1004, #1005, #1006
|
||||
|
||||
## Last Checkpoint
|
||||
- Timestamp: 2025-01-07 10:30:00
|
||||
- Last processed commit: ghi9012
|
||||
- Next commit to process: jkl3456
|
||||
```
|
||||
|
||||
## Batch Processing Workflow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 1. Get total commit count and create progress file │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 2. Filter: Skip commits already in start tag │
|
||||
│ - Check if commit is ancestor of start tag │
|
||||
│ - Skip cherry-picks or backports already released │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 3. Process batch of 15-20 commits │
|
||||
│ - Fetch commit details │
|
||||
│ - Get associated PRs │
|
||||
│ - Generate changelog entries │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 4. CHECKPOINT: Save progress │
|
||||
│ - Append entries to release-change-note-draft.md │
|
||||
│ - Update release-notes-progress.md with last SHA │
|
||||
│ - Record processed PR numbers │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 5. Check: More commits remaining? │
|
||||
│ YES → Go to step 3 with next batch │
|
||||
│ NO → Go to step 6 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 6. Final merge and formatting │
|
||||
│ - Combine all batches │
|
||||
│ - Deduplicate by PR number │
|
||||
│ - Sort by module alphabetically │
|
||||
│ - Add highlights section │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Resuming from Checkpoint
|
||||
|
||||
If interrupted, read `release-notes-progress.md` to find:
|
||||
1. Which batch was last completed
|
||||
2. The SHA of the last processed commit
|
||||
3. Which PRs have already been processed (for deduplication)
|
||||
|
||||
Then continue from the next unprocessed commit:
|
||||
|
||||
```powershell
|
||||
# Find where you left off
|
||||
$lastSha = "abc1234" # from progress file
|
||||
$remainingShas = gh api repos/microsoft/PowerToys/compare/$lastSha...main --jq '.commits[].sha'
|
||||
```
|
||||
|
||||
## Batch Size Recommendations
|
||||
|
||||
| Total Commits | Recommended Batch Size |
|
||||
|---------------|------------------------|
|
||||
| < 30 | Process all at once |
|
||||
| 30-100 | 15-20 per batch |
|
||||
| 100-300 | 20 per batch |
|
||||
| 300+ | 25 per batch + parallel processing |
|
||||
|
||||
## Deduplication
|
||||
|
||||
Track processed PR numbers to avoid duplicates:
|
||||
- Same PR can appear multiple times (multiple commits)
|
||||
- Cherry-picks may reference same PR
|
||||
- Always check `Processed PRs` list before generating entry
|
||||
119
.github/skills/changelog-generator/sub-skills/user-facing-description.md
vendored
Normal file
119
.github/skills/changelog-generator/sub-skills/user-facing-description.md
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
# Generating User-Facing Descriptions
|
||||
|
||||
This sub-skill explains how to transform technical PR/commit info into user-friendly changelog entries.
|
||||
|
||||
## Information Sources (Priority Order)
|
||||
|
||||
1. **PR Title** - Often the best summary, already user-facing
|
||||
2. **PR Description/Body** - Look for "What does this PR do?" or summary sections
|
||||
3. **Commit Message** - First line is usually descriptive
|
||||
4. **Changed Files** - Infer the impact from what was modified
|
||||
5. **PR Labels** - Indicate type (bug, feature, enhancement)
|
||||
|
||||
## Data Collection Command
|
||||
|
||||
```powershell
|
||||
# Get all relevant info for a PR
|
||||
$prNumber = 12345
|
||||
$prData = gh pr view $prNumber --repo microsoft/PowerToys --json title,body,author,files,labels,mergedAt
|
||||
|
||||
# Parse the data
|
||||
$pr = $prData | ConvertFrom-Json
|
||||
Write-Host "Title: $($pr.title)"
|
||||
Write-Host "Author: $($pr.author.login)"
|
||||
Write-Host "Labels: $($pr.labels.name -join ', ')"
|
||||
Write-Host "Files changed: $($pr.files.Count)"
|
||||
Write-Host "Body preview: $($pr.body.Substring(0, [Math]::Min(500, $pr.body.Length)))"
|
||||
```
|
||||
|
||||
## Transformation Rules
|
||||
|
||||
| Source Info | Transformation | Example Output |
|
||||
|-------------|----------------|----------------|
|
||||
| PR Title: "Fix null reference in FancyZones editor" | Describe the fix from user perspective | "Fixed a crash that could occur when editing zone layouts." |
|
||||
| PR Title: "Add support for XYZ format" | State the new capability | "Added support for XYZ format in File Explorer preview." |
|
||||
| PR Title: "[FancyZones] Refactor grid logic" | Check if user-visible; if not → Development section | (Development) "Refactored FancyZones grid logic for improved maintainability." |
|
||||
| PR with label "bug" | Frame as a fix | "Fixed an issue where..." |
|
||||
| PR with label "enhancement" | Frame as improvement | "Improved..." or "Enhanced..." |
|
||||
|
||||
## Description Generation Process
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ INPUT: PR #12345 │
|
||||
│ Title: "Fix Awake timer drift after system sleep" │
|
||||
│ Body: "The timer was resetting incorrectly when the system │
|
||||
│ resumed from sleep, causing the countdown to be wrong." │
|
||||
│ Author: @daverayment │
|
||||
│ Labels: [bug, Product-Awake] │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ ANALYSIS: │
|
||||
│ 1. Is it user-facing? YES (timer behavior affects users) │
|
||||
│ 2. Category: Bug fix │
|
||||
│ 3. Module: Awake (from label + file paths) │
|
||||
│ 4. Author in core team? NO → needs attribution │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ OUTPUT: │
|
||||
│ "The Awake countdown timer now stays accurate over long │
|
||||
│ periods. Thanks [@daverayment](https://github.com/daverayment)!" │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Writing Style Guidelines
|
||||
|
||||
**DO:**
|
||||
- Start with what changed or what users can now do
|
||||
- Use active voice: "Added...", "Fixed...", "Improved..."
|
||||
- Be specific about the benefit to users
|
||||
- Keep it concise (1-2 sentences max)
|
||||
- Include link to documentation if it's a new feature
|
||||
|
||||
**DON'T:**
|
||||
- Use technical jargon users won't understand
|
||||
- Reference internal code names, file names, or class names
|
||||
- Say "Fixed bug" without explaining what was wrong
|
||||
- Include PR numbers in the description (they're tracked separately)
|
||||
|
||||
## Example Transformations
|
||||
|
||||
| Technical PR Title | User-Facing Description |
|
||||
|--------------------|------------------------|
|
||||
| "Fix NRE in FZEditor when zones is null" | "Fixed a crash that could occur when opening the FancyZones editor with no saved layouts." |
|
||||
| "Add ExifTool integration for PowerRename" | "PowerRename can now extract and use photo metadata (EXIF, XMP) in renaming patterns like `%Camera`, `%Lens`, and `%ExposureTime`." |
|
||||
| "Perf: Reduce memory allocation in PT Run" | "Improved PowerToys Run startup performance and reduced memory usage." |
|
||||
| "Update Newtonsoft.Json to 13.0.3" | (Development) "Updated Newtonsoft.Json dependency." OR skip if no user impact |
|
||||
| "Add unit tests for color picker" | SKIP - not user-facing |
|
||||
| "Fix typo in settings UI" | "Fixed a typo in the Settings interface." (only if visible to users) |
|
||||
|
||||
## Context-Aware Description
|
||||
|
||||
Sometimes you need to read the PR body or changed files to understand the impact:
|
||||
|
||||
```powershell
|
||||
# If PR title is unclear, check the body for context
|
||||
$prBody = gh pr view 12345 --repo microsoft/PowerToys --json body --jq '.body'
|
||||
|
||||
# Look for common patterns in PR descriptions:
|
||||
# - "## Summary" or "## Description"
|
||||
# - "This PR fixes/adds/improves..."
|
||||
# - "Before/After" comparisons
|
||||
# - Screenshots (indicate UI changes)
|
||||
|
||||
# Check what files changed to understand scope
|
||||
$files = gh pr view 12345 --repo microsoft/PowerToys --json files --jq '.files[].path'
|
||||
# If mostly .xaml files → UI change
|
||||
# If mostly .cs/.cpp in one module → module-specific change
|
||||
# If in src/common/ → potentially affects multiple modules
|
||||
```
|
||||
|
||||
## Handling Ambiguous PRs
|
||||
|
||||
If a PR's impact is unclear:
|
||||
1. **Check the linked issue** - often has user-reported symptoms
|
||||
2. **Look at file changes** - understand what was modified
|
||||
3. **Check PR comments** - may have discussion about user impact
|
||||
4. **When in doubt** - put in Development section or ask for clarification
|
||||
Reference in New Issue
Block a user