| name | generate-release-notes |
| description | Auto-generate release notes from a list of PRs for Azure Functions Python Worker components (worker, runtime v1, or runtime v2). Analyzes PR file changes to determine component relevance, groups by category/prefix, and outputs organized release notes. Use when the user asks to "generate release notes", "create release notes from PRs", "format these PRs for release", or provides a list of PRs to organize.
|
| tags | ["release-notes","changelog","pull-request","github"] |
| category | Development |
Generate Release Notes
Auto-generate organized release notes from a list of PRs for Azure Functions Python Worker components.
Workflow
1. Parse Input
Accept:
- List of PRs: Each PR should include:
- PR title (with prefix like
fix:, feat:, build:, etc.)
- PR link (full GitHub URL or
#number)
- PR author (GitHub username)
- Component: One of:
worker - Python Worker component
runtime v1 - Runtime V1 component
runtime v2 - Runtime V2 component
Example input format:
## What's Changed
* fix: fix protobuf import for V2 by @hallvictoria in https://github.com/Azure/azure-functions-python-worker/pull/1736
* feat: allow event loop to be uvloop by @EvanR-Dev in https://github.com/Azure/azure-functions-python-worker/pull/1697
...
2. Extract PR Information
For each PR in the list, extract:
- PR number (from URL or
#number)
- PR title
- PR author
- PR link
Store this information for later use.
3. Analyze PR File Changes
For each PR, determine which files were changed:
Using GitHub CLI:
gh pr view <number> --json files | ConvertFrom-Json
This returns the list of changed files in the PR.
4. Determine Component Relevance
For each PR, analyze the changed files and classify based on paths:
| Path Pattern | Component | Rule |
|---|
runtimes/v1/** | runtime v1 | Any file inside runtimes/v1/ directory |
runtimes/v2/** | runtime v2 | Any file inside runtimes/v2/ directory |
workers/** | worker | Any file inside workers/ directory |
| Other paths | all | Changes outside these directories affect all components |
Component matching logic:
- If only
runtimes/v1/ files changed → runtime v1 only
- If only
runtimes/v2/ files changed → runtime v2 only
- If only
workers/ files changed → worker only
- If files from multiple directories changed → all relevant components
- If files outside these three directories changed → all components (worker, runtime v1, runtime v2)
Worker-specific exclusions:
Some PRs should ONLY appear in worker releases, even if they change root-level files:
-
Azure Functions SDK version updates - PRs that update the azure-functions package version in workers/pyproject.toml
- Example title patterns: "Update Python SDK Version to X.Y.Z"
- File changed:
workers/pyproject.toml (dependency update)
- Rule: Include ONLY in worker releases
-
Worker version updates - PRs that update the worker version in workers/*/version.py
- Example title patterns: "Update version to X.Y.Z"
- Files changed:
workers/azure_functions_worker/version.py or similar
- Rule: Include ONLY in worker releases
Detection logic for worker-specific PRs:
If PR title matches "Update Python SDK Version" OR "Update version to":
Check if files changed include:
- workers/pyproject.toml (for SDK updates)
- workers/*/version.py (for worker version updates)
If yes:
- Include in worker release ONLY
- Exclude from runtime v1 and runtime v2 releases
Filter PRs based on the user-specified component:
- Keep PRs that affect the specified component
- Exclude PRs that don't touch any files in that component's scope
- For runtime v1/v2 releases: Also exclude worker-specific version update PRs
5. Extract PR Category from Title
Parse the PR title prefix to determine the category:
| Prefix | Category | Description |
|---|
feat: | Features | New features or capabilities |
fix: | Bug Fixes | Bug fixes and corrections |
build: | Build & Dependencies | Version updates, dependency changes, build configuration |
refactor: | Refactoring | Code restructuring without behavior changes |
test: | Tests | Test additions or modifications |
chore: | Chores | Maintenance tasks, cleanup |
docs: | Documentation | Documentation updates |
perf: | Performance | Performance improvements |
ci: | CI/CD | Continuous integration/deployment changes |
style: | Style | Code style, formatting |
revert: | Reverts | Reverting previous changes |
If no recognized prefix is found, use the first word or classify as "Other".
6. Extract Runtime and SDK Versions (Worker Releases Only)
For worker component releases only, read the current versions from workers/pyproject.toml:
Extract the versions of these packages:
azure-functions-runtime
azure-functions-runtime-v1
azure-functions (with Python version conditions)
Important: The azure-functions SDK has different versions for different Python version ranges. Extract all variants.
Using PowerShell:
$pyprojectContent = Get-Content workers/pyproject.toml -Raw
# Extract runtime versions (single version each)
$runtimeMatch = [regex]::Match($pyprojectContent, 'azure-functions-runtime==([^;"\s]+)')
$runtimeV1Match = [regex]::Match($pyprojectContent, 'azure-functions-runtime-v1==([^;"\s]+)')
# Extract all azure-functions SDK versions with their Python version conditions
$sdkMatches = [regex]::Matches($pyprojectContent, '"azure-functions==([^;"]+);\s*([^"]+)"')
$sdkVersions = @()
foreach ($match in $sdkMatches) {
$version = $match.Groups[1].Value
$condition = $match.Groups[2].Value
$sdkVersions += @{Version=$version; Condition=$condition}
}
Using Python:
import re
with open('workers/pyproject.toml', 'r') as f:
content = f.read()
runtime = re.search(r'azure-functions-runtime==([^;"\s]+)', content)
runtime_v1 = re.search(r'azure-functions-runtime-v1==([^;"\s]+)', content)
sdk_pattern = r'"azure-functions==([^;"]+);\s*([^"]+)"'
sdk_matches = re.findall(sdk_pattern, content)
Format for output:
- Runtime versions: single line each
- SDK versions: one line per Python version range with the condition in a human-readable format
Store these versions for inclusion in the output.
Note: Skip this step for runtime v1 and runtime v2 releases.
7. Classify PRs by Python Version (Worker Releases Only)
For worker component releases only, classify each PR by which Python versions it affects:
Python version classification rules:
-
Special case - Worker version updates:
- PRs with title "Update version to 4.X.X" (worker component version)
- These go in a separate "Worker Version" section
- Example: "Update version to 4.43.0"
-
Check if PR touches worker code:
- If PR does NOT change any files under
workers/ directory → General/Build section
- These are repo-wide changes that don't affect worker code directly
- Examples: root-level config changes, CI/CD changes, documentation
-
Check file paths for worker code changes:
- Python <= 3.12 only: PR changes ONLY files under
workers/azure_functions_worker/
- Python 3.13+ only: PR changes ONLY files under
workers/proxy_worker/
- Both: PR changes files in both directories, OR changes files under
workers/ that affect both (e.g., workers/pyproject.toml, workers/README.md)
-
Special handling for SDK version updates:
- PRs with title "Update Python SDK Version to X.Y.Z" need additional classification
- Read
workers/pyproject.toml to determine which Python version range uses this version
- Example: If updating to 2.0.0 and pyproject shows
azure-functions==2.0.0; python_version >= '3.13', then this PR is Python 3.13+ only
- Example: If updating to 1.25.0b4 and pyproject shows
azure-functions==1.25.0b4; python_version >= '3.10' and python_version < '3.13', then this PR is Python <= 3.12 only
Classification logic:
for pr in filtered_prs:
files = get_pr_files(pr.number)
if re.match(r'[Uu]pdate\s+version\s+to\s+4\.\d+\.\d+', pr.title):
pr.section = 'worker_version'
continue
touches_workers = any(f.startswith('workers/') for f in files)
if not touches_workers:
pr.section = 'general'
continue
if 'Update Python SDK Version' in pr.title:
version = extract_version_from_title(pr.title)
pyproject = read_pyproject()
python_range = find_python_range_for_sdk_version(pyproject, version)
if '3.13' in python_range and '3.10' not in python_range:
pr.python_versions = ['3.13+']
elif '3.10' in python_range or '3.12' in python_range:
pr.python_versions = ['<=3.12']
else:
pr.python_versions = ['<=3.12', '3.13+']
else:
affects_legacy = (f.startswith() f files)
affects_proxy = (f.startswith() f files)
affects_workers_general = (
f.startswith()
f.startswith()
f.startswith()
f files
)
affects_legacy affects_proxy affects_workers_general:
pr.python_versions = []
affects_proxy affects_legacy affects_workers_general:
pr.python_versions = []
:
pr.python_versions = [, ]
Notes:
- PRs affecting both worker directories appear in both Python version sections
- PRs affecting
workers/ general files (e.g., workers/pyproject.toml) appear in both Python sections
- PRs NOT touching
workers/ at all go in the "General" section
- Worker version update PRs go in the "Worker Version" section
- SDK version updates are classified based on the Python version range in pyproject.toml
- This classification is ONLY for worker releases, not runtime releases
8. Group PRs by Category
Organize filtered PRs into categories based on their prefix.
Recommended category order for output:
- Features
- Bug Fixes
- Build & Dependencies
- Refactoring
- Tests
- Chores
- Other categories (alphabetically)
9. Deduplicate Version Update PRs
For Build & Dependencies category only, deduplicate PRs that update the same package multiple times:
Package patterns to check:
Update Python SDK Version to X.Y.Z → package: azure-functions
Update Python Runtime Version to X.Y.Z → package: azure-functions-runtime
Update version to X.Y.Z (runtime v1) → package: azure-functions-runtime-v1
Update azurefunctions-extensions-<name> version to X.Y.Z → package: azurefunctions-extensions-<name>
Update <package-name> version to X.Y.Z → package: <package-name>
Deduplication logic:
- Parse each PR title in the Build & Dependencies category
- Extract the package name using these patterns:
- Title contains "Python SDK Version" →
azure-functions
- Title contains "Python Runtime Version" and not "v1" →
azure-functions-runtime
- Title contains "Python Runtime Version" and "v1" →
azure-functions-runtime-v1
- Title matches "Update azurefunctions-extensions- version" → extract
azurefunctions-extensions-<name>
- Title matches "Update version" → extract package name
- Group PRs by package name
- For each package with multiple updates, keep only the PR with the highest PR number (most recent)
- Discard older version updates for the same package
Example:
Input PRs (Build & Dependencies):
- Update Python SDK Version to 1.24.0b4 (#1755)
- Update Python SDK Version to 1.25.0b2 (#1798)
- Update Python SDK Version to 1.25.0b3 (#1822)
- Update azurefunctions-extensions-blob version to 1.1.1 (#1762)
- Update azurefunctions-extensions-blob version to 1.1.2 (#1821)
After deduplication:
- Update Python SDK Version to 1.25.0b3 (#1822) ✓ (highest PR for azure-functions)
- Update azurefunctions-extensions-blob version to 1.1.2 (#1821) ✓ (highest PR for extensions-blob)
Removed:
- #1755, #1798 (older azure-functions updates)
- #1762 (older extensions-blob update)
Implementation approach:
package_updates = {}
for pr in build_dependency_prs:
package_name = extract_package_name(pr.title)
if package_name:
if package_name not in package_updates or pr.number > package_updates[package_name].number:
package_updates[package_name] = pr
deduplicated_prs = list(package_updates.values())
Note: Only apply deduplication to PRs that match version update patterns. Keep other build/dependency PRs as-is.
10. Format Output
Generate clean, human-readable release notes in Markdown format.
For worker releases:
# Release Notes
## General
### Features
* <title without prefix> ([#<number>](<link>)) - @<author>
* ...
### Bug Fixes
* <title without prefix> ([#<number>](<link>)) - @<author>
* ...
### Build & Dependencies
* <title without prefix> ([#<number>](<link>)) - @<author>
* ...
[... other categories ...]
## Worker Version
* <title without prefix> ([#<number>](<link>)) - @<author>
## Python <= 3.12
### Features
* <title without prefix> ([#<number>](<link>)) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
([]()) - @
...
azure-functions-runtime==
azure-functions-runtime-v1==
azure-functions== (Python < 3.10)
azure-functions== (Python 3.10-3.12)
azure-functions== (Python 3.13+)
For runtime v1/v2 releases:
# Release Notes
## Features
* <title without prefix> ([#<number>](<link>)) - @<author>
* ...
## Bug Fixes
* <title without prefix> ([#<number>](<link>)) - @<author>
* ...
[... other categories ...]
Formatting rules:
- Worker releases only:
- Section order:
- General: PRs not touching
workers/ directory (optional - only if PRs exist)
- Worker Version: Worker version update PRs (e.g., "Update version to 4.43.0")
- Python <= 3.12: PRs affecting
azure_functions_worker/
- Python 3.13+: PRs affecting
proxy_worker/
- Runtime and SDK Versions: At the END
- Within each section (except Worker Version and Runtime sections), organize by category (Features, Bug Fixes, etc.)
- PRs affecting both Python worker directories appear in both Python sections
- Only include sections and categories that have PRs
- Remove the prefix from the title (e.g.,
fix: → ``)
- Capitalize the first letter of the title
- Include PR link in standard format
[#number](full-url)
- Include author attribution with
@username
- Sort PRs within each category by PR number (ascending)
11. Save to Temporary File
Save the formatted release notes to a temporary markdown file for easy copying:
File location:
- Windows:
$env:TEMP\release-notes-<component>.md
- Linux/Mac:
/tmp/release-notes-<component>.md
Example:
- Worker release:
release-notes-worker.md
- Runtime v1 release:
release-notes-runtime-v1.md
- Runtime v2 release:
release-notes-runtime-v2.md
Using PowerShell:
$component = "worker" # or "runtime-v1" or "runtime-v2"
$outputPath = Join-Path $env:TEMP "release-notes-$component.md"
$releaseNotes | Out-File -FilePath $outputPath -Encoding utf8
Write-Host "Release notes saved to: $outputPath"
Using Python:
import tempfile
import os
component = "worker"
temp_dir = tempfile.gettempdir()
output_path = os.path.join(temp_dir, f"release-notes-{component}.md")
with open(output_path, 'w', encoding='utf-8') as f:
f.write(release_notes)
print(f"Release notes saved to: {output_path}")
After saving:
- Display the file path to the user
- Optionally open the file in the default editor or VS Code
- User can easily copy the contents from the file
12. Handle Edge Cases
PR without recognizable prefix:
- Place in "Other" category
- Keep original title
PR affects multiple components:
- Include in all relevant component release notes
- Note in output if the same PR appears in multiple components
Large PR lists (>30 PRs):
- Process in batches to avoid rate limits
- Show progress updates to user
Authentication errors:
- Check
gh auth status
- Prompt user to authenticate if needed
PR not found:
- Note the PR number that couldn't be fetched
- Continue with remaining PRs
- Report missing PRs at the end
Example Workflow
Example 1: Worker Release
User provides:
Component: worker
PRs:
* fix: fix protobuf import by @user1 in https://github.com/org/repo/pull/100
* feat: add new feature for proxy worker by @user2 in https://github.com/org/repo/pull/101
* fix: legacy worker bug fix by @user3 in https://github.com/org/repo/pull/105
* build: update version to 4.40.0 by @user4 in https://github.com/org/repo/pull/102
* build: update Python SDK Version to 1.24.0b4 by @user5 in https://github.com/org/repo/pull/103
* build: update Python SDK Version to 1.25.0b2 by @user6 in https://github.com/org/repo/pull/150
* build: update Python SDK Version to 1.25.0b3 by @user7 in https://github.com/org/repo/pull/160
* build: update pyproject for azure-functions 2.x structure by @user8 in https://github.com/org/repo/pull/200
Agent:
- Extracts PR numbers: 100, 101, 102, 103, 105, 150, 160, 200
- Fetches file changes for each PR
- PR #100: Changed
setup.cfg (root level, not in workers/) → General section
- PR #101: Changed
workers/proxy_worker/handler.py → Python 3.13+ only
- PR #102: Changed
workers/azure_functions_worker/version.py + title matches "Update version to 4.X.X" → Worker Version section
- PR #103, #150, #160: Changed
workers/pyproject.toml (SDK updates) → Check version in pyproject
- PR #105: Changed
workers/azure_functions_worker/dispatcher.py → Python <= 3.12 only
- PR #200: Changed
.github/workflows/ci.yml (not in workers/) → General section
- Classifies PRs by section:\n - PR #100: Root-level file, not in workers/ → General section\n - PR #101: Only
proxy_worker/ → Python 3.13+ only\n - PR #102: Title "Update version to 4.40.0" → Worker Version section\n - PR #103, #150, #160: SDK updates - check pyproject.toml:\n - If version 1.25.0b3 is for Python 3.10-3.12 → Python <= 3.12 only\n - PR #105: Only azure_functions_worker/ → Python <= 3.12 only\n - PR #200: CI file, not in workers/ → General section\n10. Deduplicates version updates:\n - Package azure-functions: PRs #103, #150, #160\n - Keeps only #160 (highest PR number)\n - Removes #103 and #150\n11. Reads workers/pyproject.toml to extract versions:\n - azure-functions-runtime==1.1.0\n - azure-functions-runtime-v1==1.1.0\n - azure-functions==1.24.0 (Python < 3.10)\n - azure-functions==1.25.0b4 (Python 3.10-3.12)\n - azure-functions==2.0.0 (Python 3.13+)\n12. Groups by section and category, then outputs:\n\nmarkdown\n# Release Notes\n\n## General\n\n### Bug Fixes\n* Fix protobuf import ([#100](link)) - @user1\n\n### Build & Dependencies\n* Update pyproject for azure-functions 2.x structure ([#200](link)) - @user8\n\n## Worker Version\n* Update version to 4.40.0 ([#102](link)) - @user4\n\n## Python <= 3.12\n\n### Bug Fixes\n* Legacy worker bug fix ([#105](link)) - @user3\n\n### Build & Dependencies\n* Update Python SDK Version to 1.25.0b3 ([#160](link)) - @user7\n\n## Python 3.13+\n\n### Features\n* Add new feature for proxy worker ([#101](link)) - @user2\n\n## Runtime and SDK Versions\nazure-functions-runtime==1.1.0\nazure-functions-runtime-v1==1.1.0\nazure-functions==1.24.0 (Python < 3.10)\nazure-functions==1.25.0b4 (Python 3.10-3.12)\nazure-functions==2.0.0 (Python 3.13+)\n\n\n \n- PR #100 and #200 in General section (don't touch workers/ directory)\n- PR #102 in Worker Version section (matches "Update version to 4.X.X")\n- PR #105 only in Python <= 3.12 (only affects )\n- PR #101 only in Python 3.13+ (only affects )\n- PR #160 only in Python <= 3.12 (SDK version 1.25.0b3 is for Python 3.10-3.12)\n- PRs #103 and #150 were excluded due to deduplication\n- Runtime and SDK Versions section is at the END
Example 2: Runtime V2 Release with Deduplication
User provides:
Component: runtime v2
PRs:
* fix: fix protobuf import by @user1 in https://github.com/org/repo/pull/100
* feat: add new feature by @user2 in https://github.com/org/repo/pull/101
* build: update version to 1.0.0b1 by @user3 in https://github.com/org/repo/pull/110
* build: update version to 1.0.0b2 by @user4 in https://github.com/org/repo/pull/120
* build: update version to 1.1.0b1 by @user5 in https://github.com/org/repo/pull/130
* build: update azurefunctions-extensions-blob version to 1.1.1 by @user6 in https://github.com/org/repo/pull/140
* build: update azurefunctions-extensions-blob version to 1.1.2 by @user7 in https://github.com/org/repo/pull/145
* build: update Python SDK Version to 1.24.0 by @user8 in https://github.com/org/repo/pull/150
Agent:
- Extracts PR numbers: 100, 101, 110, 120, 130, 140, 145, 150
- Fetches file changes for each PR
- PR #100: Changed
setup.cfg (root level) → all components ✓
- PR #101: Changed
runtimes/v2/handler.py → runtime v2 ✓
- PR #110, #120, #130: Changed
runtimes/v2/version.py → runtime v2 ✓
- PR #140, #145: Changed
runtimes/v2/pyproject.toml (extensions-blob) → runtime v2 ✓
- PR #150: Changed
workers/pyproject.toml (azure-functions) → worker-specific only ✗ (exclude)
- Deduplicates version updates:
- Package
azure-functions-runtime-v2: PRs #110, #120, #130 → Keeps only #130
- Package
azurefunctions-extensions-blob: PRs #140, #145 → Keeps only #145
- Groups by category and outputs:
# Release Notes
## Features
* Add new feature ([#101](link)) - @user2
## Bug Fixes
* Fix protobuf import ([#100](link)) - @user1
## Build & Dependencies
* Update version to 1.1.0b1 ([#130](link)) - @user5
* Update azurefunctions-extensions-blob version to 1.1.2 ([#145](link)) - @user7
Notes:
- PRs #110 and #120 were excluded (older
azure-functions-runtime-v2 updates)
- PR #140 was excluded (older
azurefunctions-extensions-blob update)
- PR #150 was excluded (worker-specific
azure-functions SDK update)
Tips for Best Results
- Ensure PRs follow conventional commit format with prefixes
- Have GitHub CLI installed and authenticated (
gh auth login)
- Provide clear component name (exact match:
worker, runtime v1, or runtime v2)
- For PRs from different repos, include full URLs
- If the repo is not the current workspace, the agent will need to clone or access it
- The release notes will be saved to a temporary file for easy copying:
$env:TEMP\release-notes-<component>.md (Windows) or /tmp/release-notes-<component>.md (Linux/Mac)
Notes
- This skill is specific to the Azure Functions Python Worker repository structure
- Assumes repository access permissions for fetching PR data
- Can be adapted for other repositories by modifying the component path patterns in Step 4