Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions 175 .github/workflows/generate-changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
name: Generate Changelog

on:
workflow_dispatch:
inputs:
since:
description: 'Generate changelog since this tag/commit (optional)'
required: false
type: string
unreleased:
description: 'Include unreleased changes'
required: false
type: boolean
default: true

permissions:
contents: write
pull-requests: write

jobs:
generate-changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Install git-cliff
run: |
curl -LsSf https://github.com/orhun/git-cliff/releases/latest/download/git-cliff-x86_64-unknown-linux-gnu.tar.gz | tar xzf - -C /usr/local/bin

- name: Create git-cliff configuration
run: |
cat > cliff.toml << 'EOF'
[changelog]
# changelog header
header = """
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

"""
# template for the changelog body
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [Unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}**{{commit.scope}}**: {% endif %}\
{{ commit.message | upper_first }}\
{% if commit.links %} ({% for link in commit.links %}[{{link.text}}]({{link.href}}){% if not loop.last %}, {% endif %}{% endfor %}){% endif %}
{% endfor %}
{% endfor %}\

{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
### Contributors

Thanks to all the contributors who made this release possible:

{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
- [@{{ contributor.username }}](https://github.com/{{ contributor.username }}) - *first-time contributor* πŸŽ‰
{% endfor %}
{% for contributor in github.contributors | filter(attribute="is_first_time", value=false) %}
- [@{{ contributor.username }}](https://github.com/{{ contributor.username }})
{% endfor %}
{% endif %}\

"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
---

## Previous Releases

For release history, please refer to the individual server changelogs:
- [Azure MCP Server CHANGELOG](./servers/Azure.Mcp.Server/CHANGELOG.md)
- [Template MCP Server CHANGELOG](./servers/Template.Mcp.Server/CHANGELOG.md)
"""

[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out commits that are not conventional
filter_unconventional = false
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
# Replace issue numbers with links
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/microsoft/mcp/issues/${2}))"},
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "<!-- 0 -->πŸš€ Features"},
{ message = "^fix", group = "<!-- 1 -->πŸ› Bug Fixes"},
{ message = "^doc", group = "<!-- 3 -->πŸ“š Documentation"},
{ message = "^perf", group = "<!-- 4 -->⚑ Performance"},
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor"},
{ message = "^style", group = "<!-- 5 -->🎨 Styling"},
{ message = "^test", group = "<!-- 6 -->πŸ§ͺ Testing"},
{ message = "^chore\\(release\\): prepare for", skip = true},
{ message = "^chore\\(deps.*\\)", skip = true},
{ message = "^chore\\(pr\\)", skip = true},
{ message = "^chore\\(pull\\)", skip = true},
{ message = "^chore|^ci", group = "<!-- 7 -->βš™οΈ Miscellaneous Tasks"},
{ body = ".*security", group = "<!-- 8 -->πŸ›‘οΈ Security"},
{ message = "^revert", group = "<!-- 9 -->◀️ Revert"},
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out commits that are not matched by commit parsers
filter_commits = false
# regex for matching git tags
tag_pattern = "v[0-9].*"
# regex for skipping tags
skip_tags = "v0.1.0-beta.1"
# regex for ignoring tags
ignore_tags = ""
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
# limit the number of commits included in the changelog.
# limit_commits = 42

[remote.github]
owner = "microsoft"
repo = "mcp"
token = "${{ secrets.GITHUB_TOKEN }}"
EOF

- name: Generate changelog
run: |
# Generate changelog based on inputs
if [ "${{ github.event.inputs.since }}" != "" ]; then
since_arg="--include-path '*' --since ${{ github.event.inputs.since }}"
else
since_arg=""
fi

if [ "${{ github.event.inputs.unreleased }}" = "true" ]; then
unreleased_arg="--unreleased"
else
unreleased_arg=""
fi

git-cliff --config cliff.toml $since_arg $unreleased_arg --output CHANGELOG.md

- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "docs: update CHANGELOG.md with generated entries"
title: "πŸ“ Update CHANGELOG.md with generated entries"
body: |
This PR updates the CHANGELOG.md file with automatically generated entries based on commit messages.

The changelog is generated using git-cliff and follows conventional commit patterns.

Generated with inputs:
- Since: ${{ github.event.inputs.since || 'beginning' }}
- Include unreleased: ${{ github.event.inputs.unreleased }}
branch: update-changelog-automated
base: main
156 changes: 156 additions & 0 deletions 156 .github/workflows/update-changelog-contributors.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
name: Update CHANGELOG with Contributors

on:
release:
types: [published]
repository_dispatch:
types: [update-changelog]
workflow_dispatch:
inputs:
tag_name:
description: 'Tag name for the release'
required: true
type: string

permissions:
contents: write
pull-requests: write

jobs:
update-changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history for contributor analysis
token: ${{ secrets.GITHUB_TOKEN }}

- name: Get release information
id: release
run: |
if [ "${{ github.event_name }}" = "release" ]; then
echo "tag_name=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
echo "release_name=${{ github.event.release.name }}" >> $GITHUB_OUTPUT
echo "release_body<<EOF" >> $GITHUB_OUTPUT
echo "${{ github.event.release.body }}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
elif [ "${{ github.event_name }}" = "repository_dispatch" ]; then
echo "tag_name=${{ github.event.client_payload.tag_name }}" >> $GITHUB_OUTPUT
echo "release_name=${{ github.event.client_payload.release_name }}" >> $GITHUB_OUTPUT
echo "release_body=${{ github.event.client_payload.release_body }}" >> $GITHUB_OUTPUT
else
echo "tag_name=${{ github.event.inputs.tag_name }}" >> $GITHUB_OUTPUT
echo "release_name=${{ github.event.inputs.tag_name }}" >> $GITHUB_OUTPUT
echo "release_body=" >> $GITHUB_OUTPUT
fi

- name: Get previous release tag
id: previous_release
run: |
# Get the previous release tag for comparison
previous_tag=$(git tag --sort=-version:refname | grep -v "${{ steps.release.outputs.tag_name }}" | head -n 1)
if [ -z "$previous_tag" ]; then
# If no previous tag, use first commit
previous_tag=$(git rev-list --max-parents=0 HEAD)
fi
echo "previous_tag=$previous_tag" >> $GITHUB_OUTPUT

- name: Get contributors since last release
id: contributors
run: |
tag_name="${{ steps.release.outputs.tag_name }}"
previous_tag="${{ steps.previous_release.outputs.previous_tag }}"

echo "Getting contributors between $previous_tag and $tag_name"

# Get all contributors (commit authors and co-authors) since last release
contributors=$(git log --format='%aN <%aE>' $previous_tag..$tag_name 2>/dev/null || git log --format='%aN <%aE>' $previous_tag..HEAD)

# Also get co-authors from commit messages
co_authors=$(git log --format='%b' $previous_tag..$tag_name 2>/dev/null || git log --format='%b' $previous_tag..HEAD | grep -i "co-authored-by:" | sed 's/^[[:space:]]*[Cc]o-[Aa]uthored-[Bb]y:[[:space:]]*//')

# Combine and deduplicate contributors
all_contributors=$(echo -e "$contributors\n$co_authors" | sort -u | grep -v "^$" | grep -v "azure-sdk" | grep -v "noreply@github.com")

# Format contributors for markdown
formatted_contributors=""
while IFS= read -r contributor; do
if [ ! -z "$contributor" ]; then
# Extract name and email
name=$(echo "$contributor" | sed 's/ <.*>//')
email=$(echo "$contributor" | sed 's/.*<\(.*\)>.*/\1/')

# Get GitHub username if possible
username=$(curl -s "https://api.github.com/search/users?q=$email" | jq -r '.items[0].login // empty' 2>/dev/null || echo "")

if [ ! -z "$username" ] && [ "$username" != "null" ]; then
formatted_contributors="${formatted_contributors}- [@$username](https://github.com/$username) ($name)\n"
else
formatted_contributors="${formatted_contributors}- $name\n"
fi
fi
done <<< "$all_contributors"

echo "contributors<<EOF" >> $GITHUB_OUTPUT
echo -e "$formatted_contributors" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Update CHANGELOG
run: |
tag_name="${{ steps.release.outputs.tag_name }}"
release_name="${{ steps.release.outputs.release_name }}"
contributors="${{ steps.contributors.outputs.contributors }}"

# Get current date
release_date=$(date +%Y-%m-%d)

# Prepare the new release section
release_section="## [$tag_name] - $release_date\n\n"

# Add release body if available
if [ ! -z "${{ steps.release.outputs.release_body }}" ]; then
release_section="${release_section}${{ steps.release.outputs.release_body }}\n\n"
fi

# Add contributors section
if [ ! -z "$contributors" ]; then
release_section="${release_section}### Contributors\n\n"
release_section="${release_section}Thanks to all the contributors who made this release possible:\n\n"
release_section="${release_section}$contributors\n"
fi

# Create a temporary file
temp_file=$(mktemp)

# Insert the new release section after the ## [Unreleased] section
awk -v release="$release_section" '
/^## \[Unreleased\]/ {
print
# Print everything until the next ## heading or ---
while ((getline) > 0 && !/^##/ && !/^---/) {
print
}
# Print the new release section
printf "%s\n", release
# Print the line that ended the loop (if it was a heading)
if (/^##/ || /^---/) print
}
!/^## \[Unreleased\]/ { print }
' CHANGELOG.md > "$temp_file"

# Replace the original file
mv "$temp_file" CHANGELOG.md

- name: Commit and push changes
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"

if git diff --quiet CHANGELOG.md; then
echo "No changes to CHANGELOG.md"
else
git add CHANGELOG.md
git commit -m "Update CHANGELOG.md for release ${{ steps.release.outputs.tag_name }}"
git push
fi
3 changes: 3 additions & 0 deletions 3 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ node_modules/

generated/
/docs/commandline

# Test scripts for contributor functionality
test-contributors.sh
33 changes: 33 additions & 0 deletions 33 CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Automatic contributor recognition in release notes

### Changed

### Fixed

### Removed

---

## Previous Releases

For release history, please refer to the individual server changelogs:
- [Azure MCP Server CHANGELOG](./servers/Azure.Mcp.Server/CHANGELOG.md)
- [Template MCP Server CHANGELOG](./servers/Template.Mcp.Server/CHANGELOG.md)

---

## Contributors πŸ‘₯

We appreciate all the contributors who have helped improve this project! Contributors are automatically recognized in each release.

<!-- Contributors will be automatically updated by GitHub Actions -->
11 changes: 11 additions & 0 deletions 11 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ Check out the [Azure Developer CLI (azd) templates](https://azure.github.io/awes
- [MCP SDKs and Building Blocks](https://modelcontextprotocol.io/sdk)
- [MCP Specification](https://spec.modelcontextprotocol.io/specification/)

## πŸ‘₯ Contributor Recognition

We automatically recognize and thank all contributors in our [CHANGELOG.md](./CHANGELOG.md) for each release! The system:

- ✨ **Automatically extracts contributors** from commits and co-author tags
- πŸš€ **Updates CHANGELOG.md** with contributor recognition for each release
- 🎯 **Supports conventional commits** for organized change categorization
- πŸ“ **Provides manual changelog generation** using git-cliff

Learn more about how contributor recognition works in our [Contributor Recognition Guide](./docs/CONTRIBUTOR_RECOGNITION.md).

## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Expand Down
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.