Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cd227b6
feat: add automated changelog generation with git-cliff
claude Dec 2, 2025
c2a9438
docs: add git-cliff tasks to mise.toml and update versioning docs
claude Dec 2, 2025
e6dd7d8
Update .github/workflows/changelog.yml
bashandbone Dec 2, 2025
57ed99a
Update CHANGELOG.md
bashandbone Dec 2, 2025
3872bd4
Update .github/workflows/changelog.yml
bashandbone Dec 2, 2025
b886701
Update .github/workflows/release.yml
bashandbone Dec 2, 2025
1e550d6
Update .github/workflows/release.yml
bashandbone Dec 2, 2025
e9cca99
Update cliff.toml
bashandbone Dec 2, 2025
192e814
Update cliff.toml
bashandbone Dec 2, 2025
4cce595
Update CHANGELOG.md
bashandbone Dec 2, 2025
f5c5000
Update mise.toml
bashandbone Dec 2, 2025
dcd9d89
Update mise.toml
bashandbone Dec 2, 2025
336b19b
Update .github/workflows/release.yml
bashandbone Dec 2, 2025
efd500f
Update docs/versioning.md
bashandbone Dec 2, 2025
0297c98
Update docs/versioning.md
bashandbone Dec 2, 2025
685a7db
Update docs/versioning.md
bashandbone Dec 2, 2025
a9d317a
Update .github/workflows/release.yml
bashandbone Dec 2, 2025
4f93f8c
Update .github/workflows/release.yml
bashandbone Dec 2, 2025
6351412
Update .github/workflows/changelog.yml
bashandbone Dec 2, 2025
caf5468
Update docs/versioning.md
bashandbone Dec 2, 2025
ea78b0a
refactor: address PR review feedback for changelog setup
claude Dec 2, 2025
d373b6b
Update cliff.toml
bashandbone Dec 2, 2025
8d48903
Update docs/versioning.md
bashandbone Dec 2, 2025
cea4005
Update cliff.toml
bashandbone Dec 2, 2025
018b354
Update cliff.toml
bashandbone Dec 2, 2025
4ecec83
Update cliff.toml
bashandbone Dec 2, 2025
de2fb71
Update docs/versioning.md
bashandbone Dec 2, 2025
d0856aa
Update cliff.toml
bashandbone Dec 2, 2025
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
73 changes: 73 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# SPDX-FileCopyrightText: 2025 Knitli Inc.
# SPDX-FileContributor: Adam Poulemanos <[email protected]>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

name: Generate Changelog

on:
workflow_dispatch:
inputs:
tag:
description: 'Generate changelog for specific tag (e.g., v0.1.0). Leave empty for unreleased changes.'
required: false
type: string
commit:
description: 'Commit and push the generated CHANGELOG.md'
required: false
type: boolean
default: false

permissions:
contents: write

jobs:
generate-changelog:
name: Generate Changelog
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
fetch-depth: 0 # Fetch all history for changelog generation

- name: Install git-cliff
uses: taiki-e/install-action@331a600f1b10a3fed8dc56f925012bede91ae51f
with:
tool: [email protected]

- name: Generate changelog
id: changelog
run: |
if [ -n "${{ github.event.inputs.tag }}" ]; then
echo "Generating changelog for tag ${{ github.event.inputs.tag }}"
git-cliff --tag "${{ github.event.inputs.tag }}" --output CHANGELOG.md
else
echo "Generating changelog for unreleased changes"
git-cliff --unreleased --output CHANGELOG.md --prepend
fi

- name: Display changelog
run: |
echo "Generated CHANGELOG.md:"
cat CHANGELOG.md

- name: Commit and push
if: github.event.inputs.commit == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add CHANGELOG.md
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "docs: update CHANGELOG.md"
git push
fi

- name: Upload changelog artifact
uses: actions/upload-artifact@4b540d30404c5374296eb0061f5d53f85b8f4cc2
with:
name: changelog
path: CHANGELOG.md
retention-days: 7
75 changes: 74 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,82 @@ jobs:
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"

- name: Install git-cliff
uses: taiki-e/install-action@331a600f1b10a3fed8dc56f925012bede91ae51f
with:
tool: [email protected]

- name: Generate release notes
id: release_notes
run: "# Get the latest release tag (before current)\nPREVIOUS_TAG=\"$(git tag --sort=-version:refname | grep -E '^v[0-9]+\\.[0-9]+\\.[0-9]+' | head -2 | tail -1 || echo \"\")\"\nCURRENT_TAG=\"${{ steps.version.outputs.tag }}\"\n\necho \"Previous tag: $PREVIOUS_TAG\"\necho \"Current tag: $CURRENT_TAG\"\n\n# Generate changelog\ncat > release_notes.md << 'EOF'\n## What's Changed\n\nEOF\n\nif [ -n \"$PREVIOUS_TAG\" ] && [ \"$PREVIOUS_TAG\" != \"$CURRENT_TAG\" ]; then\n # Get commits since last release\n git log --pretty=format:\"- %s (%h)\" --no-merges \"$PREVIOUS_TAG..$CURRENT_TAG\" >> release_notes.md\nelse\n echo \"- Initial alpha release\" >> release_notes.md\nfi\n\ncat >> release_notes.md << 'EOF'\n\n## Installation\n\nEOF\n\n# Add pre-release specific installation instructions\nVERSION=\"${{ steps.version.outputs.version }}\"\nif [[ \"$VERSION\" == *\"a\"* ]] || [[ \"$VERSION\" == *\"b\"* ]] || [[ \"$VERSION\" == *\"rc\"* ]]; then\n cat >> release_notes.md << 'EOF'\n**This is a pre-release version.** Install with:\n```bash\npip install --pre codeweaver\n# Or specific version:\npip install code-weaver==${{ steps.version.outputs.version }}\n```\nEOF\nelse\n cat >> release_notes.md << 'EOF'\nInstall from PyPI:\n```bash\npip install code-weaver\n```\nEOF\nfi\n\ncat >> release_notes.md << 'EOF'\n\nOr download the wheel/source distribution from the assets below.\n\n## Verification\n\nAll release artifacts are built from source and include:\n- \U0001F4E6 Wheel distribution (.whl)\n- \U0001F4E6 Source distribution (.tar.gz)\n\nEOF\n\nif [ -n \"$PREVIOUS_TAG\" ]; then\n echo \"**Full Changelog**: https://github.com/knitli/codeweaver/compare/$PREVIOUS_TAG...$CURRENT_TAG\" >> release_notes.md\nelse\n echo \"**Full Changelog**: https://github.com/knitli/codeweaver/commits/$CURRENT_TAG\" >> release_notes.md\nfi\n"
run: |
# Get the latest release tag (before current)
PREVIOUS_TAG="$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | head -2 | tail -1 || echo "")"
CURRENT_TAG="${{ steps.version.outputs.tag }}"
VERSION="${{ steps.version.outputs.version }}"

echo "Previous tag: $PREVIOUS_TAG"
echo "Current tag: $CURRENT_TAG"

# Generate changelog using git-cliff
if [ -n "$PREVIOUS_TAG" ] && [ "$PREVIOUS_TAG" != "$CURRENT_TAG" ]; then
# Generate changelog for the range between previous and current tag
git-cliff --strip all --tag "$CURRENT_TAG" "$PREVIOUS_TAG..$CURRENT_TAG" > changelog_section.md
else
# First release - get all commits
git-cliff --strip all --tag "$CURRENT_TAG" > changelog_section.md
fi

# Build complete release notes with installation instructions
cat > release_notes.md << 'EOF'
## What's Changed

EOF

cat changelog_section.md >> release_notes.md

cat >> release_notes.md << 'EOF'

## Installation

EOF

# Add pre-release specific installation instructions
if [[ "$VERSION" == *"a"* ]] || [[ "$VERSION" == *"b"* ]] || [[ "$VERSION" == *"rc"* ]]; then
cat >> release_notes.md << EOF
**This is a pre-release version.** Install with:
\`\`\`bash
pip install --pre code-weaver
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The installation instruction suggests pip install --pre codeweaver but the package name should be code-weaver (with hyphen) for consistency with line 131. This inconsistency could lead users to install the wrong package.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent package name. The documentation uses codeweaver (no hyphen) in the pip install command, but elsewhere in the file it's been corrected to code-weaver (with hyphen). This line should use code-weaver for consistency.

pip install --pre code-weaver

Copilot uses AI. Check for mistakes.
# Or specific version:
pip install code-weaver==$VERSION
\`\`\`
EOF
else
cat >> release_notes.md << 'EOF'
Install from PyPI:
```bash
pip install code-weaver
```
EOF
fi

cat >> release_notes.md << 'EOF'

Or download the wheel/source distribution from the assets below.

## Verification

All release artifacts are built from source and include:
- 📦 Wheel distribution (.whl)
- 📦 Source distribution (.tar.gz)

EOF

if [ -n "$PREVIOUS_TAG" ]; then
echo "**Full Changelog**: https://github.com/knitli/codeweaver/compare/$PREVIOUS_TAG...$CURRENT_TAG" >> release_notes.md
else
echo "**Full Changelog**: https://github.com/knitli/codeweaver/commits/$CURRENT_TAG" >> release_notes.md
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe
with:
Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Changelog

All notable changes to CodeWeaver 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]

### Bug Fixes
- Verify sparse-only vector search fix (ISSUE-001) ([#176](https://github.com/knitli/codeweaver/pull/176))
- Fix Docker Compose CI test failures - correct Qdrant health endpoint ([#178](https://github.com/knitli/codeweaver/pull/178))
- chore: Add plans for server separation of services refactor to enable… ([#179](https://github.com/knitli/codeweaver/pull/179))
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entry appears to be miscategorized. The description starts with "chore:" which suggests it should be in a "Maintenance" or "Chores" section, not "Bug Fixes". This is likely caused by the branch name containing "issue-" which matches the fix pattern on line 91 of cliff.toml.

The commit parsers should be refined to handle cases where branch names might match fix patterns but the actual change is not a fix (based on conventional commit prefixes like "chore:").

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This changelog entry appears to be miscategorized. The PR description mentions "Add plans for server separation of services refactor" which sounds like planning/documentation rather than a bug fix. Based on the branch naming conventions in the documentation, this should likely be in "Documentation" or "Other Changes" rather than "Bug Fixes".

Copilot uses AI. Check for mistakes.
- Add REUSE.toml for third-party licensing, fix mislabeled vendored files ([#171](https://github.com/knitli/codeweaver/pull/171))
- Fix multiple failing actions due to reusable files recognition ([#167](https://github.com/knitli/codeweaver/pull/167))
- Fix Docker build failures by respecting CODEWEAVER_PROJECT_PATH environment variable ([#165](https://github.com/knitli/codeweaver/pull/165))
- Fix release workflow test exclusions to match CI workflow ([#164](https://github.com/knitli/codeweaver/pull/164))
- fix: Remove corrupted standalone variable names from copilot-setup-steps.yml ([#163](https://github.com/knitli/codeweaver/pull/163))
- Fix: Respect CODEWEAVER_PROJECT_PATH in settings _defaults() ([#162](https://github.com/knitli/codeweaver/pull/162))
- Fix test collection namespace collision and apply consistent pytest marks ([#35](https://github.com/knitli/codeweaver/pull/35))
- Fix undefined names and circular imports in vector stores ([#29](https://github.com/knitli/codeweaver/pull/29))
- Fix CI lint/build job failures: install zsh and correct mise.toml shebangs ([#34](https://github.com/knitli/codeweaver/pull/34))

### Features
- Refactor server architecture to separate concerns and enable stdio transport ([#172](https://github.com/knitli/codeweaver/pull/172))

### Other Changes
- Implement semantic and delimiter chunking systems, add vector store implementations, general code improvements. ([#28](https://github.com/knitli/codeweaver/pull/28))

### Performance
- feat: implement modular workflows with efficiency optimizations ([#166](https://github.com/knitli/codeweaver/pull/166))
<!-- generated by git-cliff -->
126 changes: 126 additions & 0 deletions cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# SPDX-FileCopyrightText: 2025 Knitli Inc.
# SPDX-FileContributor: Adam Poulemanos <[email protected]>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

# git-cliff configuration for automated changelog generation
# See: https://git-cliff.org/docs/configuration

[changelog]
# Template for the changelog header
header = """
# Changelog

All notable changes to CodeWeaver 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
# Available variables:
# - version: Version number
# - message: Commit message
# - date: Commit date
# - commits: List of commits for this version
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.message is starting_with("Merge pull request") -%}
{%- set_global pr_num = commit.message | replace(from="Merge pull request #", to="") | split(pat=" ") | first -%}
{%- if commit.message is containing(" | ") -%}
{%- set_global pr_desc = commit.message | split(pat=" | ") | last -%}
{%- else -%}
{%- set_global pr_desc = "No description" -%}
{%- endif %}
- {{ pr_desc }} ([#{{ pr_num }}](https://github.com/knitli/codeweaver/pull/{{ pr_num }}))
{%- else %}
- {{ commit.message | upper_first }}
{%- endif -%}
{%- if commit.breaking %}
- **BREAKING**: {{ commit.breaking_description }}
{%- endif -%}
{% endfor %}
{% endfor %}
"""
# Template for the changelog footer
footer = """
<!-- generated by git-cliff -->
"""
# Remove the leading and trailing whitespace from the templates
trim = true
# Postprocessors to apply after rendering the changelog
postprocessors = [
# Replace issue/PR numbers with links
{ pattern = '\(#([0-9]+)\)', replace = "([#${1}](https://github.com/knitli/codeweaver/pull/${1}))" },
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The postprocessor pattern on line 61 will create duplicate PR links. The template at line 42 already generates links in the format ([#123](https://github.com/knitli/codeweaver/pull/123)), but this postprocessor will try to replace (#123) with another link, resulting in malformed markdown like ([#123](https://github.com/knitli/codeweaver/pull/123](https://github.com/knitli/codeweaver/pull/123)).

Since PR links are already generated in the template, this postprocessor should be removed.

Suggested change
# Replace issue/PR numbers with links
{ pattern = '\(#([0-9]+)\)', replace = "([#${1}](https://github.com/knitli/codeweaver/pull/${1}))" },
# No postprocessors needed; PR links are already generated in the template

Copilot uses AI. Check for mistakes.
]

[git]
# Parse commits based on https://www.conventionalcommits.org
conventional_commits = false
# Filter out commits that are not conventional
filter_unconventional = false
# Process merge commits - THIS IS KEY for PR-based changelog
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The comment on line 73 states "THIS IS KEY for PR-based changelog" but the actual setting split_commits = false is on line 74. The comment seems to indicate this is an important setting, but the description could be clearer about what split_commits does and why false is the correct value for PR-based changelogs.

Consider expanding the comment to explain: "Set to false to treat merge commits as single entries (important for PR-based changelogs)" for better maintainability.

Suggested change
# Process merge commits - THIS IS KEY for PR-based changelog
# Set to false to treat merge commits (such as PR merges) as single entries in the changelog.
# This is important for PR-based changelogs, as it ensures each PR appears as one changelog entry.

Copilot uses AI. Check for mistakes.
split_commits = false
# Only include merge commits (PR merges)
# Preprocessor to append PR description to the merge commit message for easier extraction
commit_preprocessors = [
# Extract PR description and append to subject for template use
# Input: "Merge pull request #123 from org/branch\n\nPR Description"
# Output: "Merge pull request #123 from org/branch | PR Description"
{ pattern = 'Merge pull request (#[0-9]+) from ([^\n]+)\n+(.+)', replace = "Merge pull request ${1} from ${2} | ${3}" },
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern in the commit preprocessor may not handle PR descriptions correctly if they contain newlines within the description. The pattern \n+(.+) will only capture text up to the first newline within the PR description, truncating multi-paragraph PR descriptions to just the first line.

Consider using (.+) with the DOTALL flag or ([\s\S]+) to capture the full PR description including newlines.

Suggested change
{ pattern = 'Merge pull request (#[0-9]+) from ([^\n]+)\n+(.+)', replace = "Merge pull request ${1} from ${2} | ${3}" },
{ pattern = 'Merge pull request (#[0-9]+) from ([^\n]+)\n+([\s\S]+)', replace = "Merge pull request ${1} from ${2} | ${3}" },

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit preprocessor regex pattern uses \n+(.+) to capture the PR description, but the . metacharacter doesn't match newline characters by default. This means only the first line of multi-line PR descriptions will be captured. Consider using (.+) with a multiline flag or ([\s\S]+) to capture the full PR description including any newlines in the body.

Suggested change
{ pattern = 'Merge pull request (#[0-9]+) from ([^\n]+)\n+(.+)', replace = "Merge pull request ${1} from ${2} | ${3}" },
{ pattern = 'Merge pull request (#[0-9]+) from ([^\n]+)\n+([\s\S]+)', replace = "Merge pull request ${1} from ${2} | ${3}" },

Copilot uses AI. Check for mistakes.
]
# Parse merge commits to extract PR info
# NOTE: Order matters! Commits are matched top-to-bottom, first match wins
commit_parsers = [
# Skip non-PR merge commits (like "Merge branch 'main'")
{ message = "^Merge branch", skip = true },
# Features - check branch name patterns
{ message = "^Merge pull request #[0-9]+ from .*/feat", group = "Features" },
{ message = "^Merge pull request #[0-9]+ from .*/feature", group = "Features" },
# Fixes - multiple patterns for fix-related branches
{ message = "^Merge pull request #[0-9]+ from .*/fix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/bugfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/hotfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/issue-", group = "Bug Fixes" },
# Documentation
{ message = "^Merge pull request #[0-9]+ from .*/docs", group = "Documentation" },
{ message = "^Merge pull request #[0-9]+ from .*/doc", group = "Documentation" },
# Performance
{ message = "^Merge pull request #[0-9]+ from .*/perf", group = "Performance" },
{ message = "^Merge pull request #[0-9]+ from .*/optimize", group = "Performance" },
# Refactoring
{ message = "^Merge pull request #[0-9]+ from .*/refactor", group = "Refactoring" },
# Testing
{ message = "^Merge pull request #[0-9]+ from .*/test", group = "Testing" },
# CI/CD and tooling
{ message = "^Merge pull request #[0-9]+ from .*/ci", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/workflow", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/build", group = "Build System" },
# Chores and maintenance
{ message = "^Merge pull request #[0-9]+ from .*/chore", group = "Maintenance" },
Comment on lines +128 to +150
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The branch pattern matching uses partial matches (e.g., /feat, /feature) which will also match branches like /feature-xyz or /feats. While this might be intentional for flexibility, it could lead to unexpected categorization. Consider using more explicit patterns like /feat/ or /feature/ if branches are expected to follow a strict type/description format, or document that partial matching is intentional.

Suggested change
{ message = "^Merge pull request #[0-9]+ from .*/feat", group = "Features" },
{ message = "^Merge pull request #[0-9]+ from .*/feature", group = "Features" },
# Fixes - multiple patterns for fix-related branches
{ message = "^Merge pull request #[0-9]+ from .*/fix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/bugfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/hotfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/issue-", group = "Bug Fixes" },
# Documentation
{ message = "^Merge pull request #[0-9]+ from .*/docs", group = "Documentation" },
{ message = "^Merge pull request #[0-9]+ from .*/doc", group = "Documentation" },
# Performance
{ message = "^Merge pull request #[0-9]+ from .*/perf", group = "Performance" },
{ message = "^Merge pull request #[0-9]+ from .*/optimize", group = "Performance" },
# Refactoring
{ message = "^Merge pull request #[0-9]+ from .*/refactor", group = "Refactoring" },
# Testing
{ message = "^Merge pull request #[0-9]+ from .*/test", group = "Testing" },
# CI/CD and tooling
{ message = "^Merge pull request #[0-9]+ from .*/ci", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/workflow", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/build", group = "Build System" },
# Chores and maintenance
{ message = "^Merge pull request #[0-9]+ from .*/chore", group = "Maintenance" },
{ message = "^Merge pull request #[0-9]+ from .*/feat/", group = "Features" },
{ message = "^Merge pull request #[0-9]+ from .*/feature/", group = "Features" },
# Fixes - multiple patterns for fix-related branches
{ message = "^Merge pull request #[0-9]+ from .*/fix/", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/bugfix/", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/hotfix/", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/issue-", group = "Bug Fixes" },
# Documentation
{ message = "^Merge pull request #[0-9]+ from .*/docs/", group = "Documentation" },
{ message = "^Merge pull request #[0-9]+ from .*/doc/", group = "Documentation" },
# Performance
{ message = "^Merge pull request #[0-9]+ from .*/perf/", group = "Performance" },
{ message = "^Merge pull request #[0-9]+ from .*/optimize/", group = "Performance" },
# Refactoring
{ message = "^Merge pull request #[0-9]+ from .*/refactor/", group = "Refactoring" },
# Testing
{ message = "^Merge pull request #[0-9]+ from .*/test/", group = "Testing" },
# CI/CD and tooling
{ message = "^Merge pull request #[0-9]+ from .*/ci/", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/workflow/", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/build/", group = "Build System" },
# Chores and maintenance
{ message = "^Merge pull request #[0-9]+ from .*/chore/", group = "Maintenance" },

Copilot uses AI. Check for mistakes.
Comment on lines +128 to +150
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit parser patterns use from .*/feat (and similar) which will only match branch names that have feat at the end of the path. However, according to the documentation (line 221), branches like feat/my-feature should be matched. The current pattern would only match something/feat, not feat/something. The patterns should be from .*feat/ or from .*feat to match branches that start with or contain the prefix followed by a slash.

Suggested change
{ message = "^Merge pull request #[0-9]+ from .*/feat", group = "Features" },
{ message = "^Merge pull request #[0-9]+ from .*/feature", group = "Features" },
# Fixes - multiple patterns for fix-related branches
{ message = "^Merge pull request #[0-9]+ from .*/fix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/bugfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/hotfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/issue-", group = "Bug Fixes" },
# Documentation
{ message = "^Merge pull request #[0-9]+ from .*/docs", group = "Documentation" },
{ message = "^Merge pull request #[0-9]+ from .*/doc", group = "Documentation" },
# Performance
{ message = "^Merge pull request #[0-9]+ from .*/perf", group = "Performance" },
{ message = "^Merge pull request #[0-9]+ from .*/optimize", group = "Performance" },
# Refactoring
{ message = "^Merge pull request #[0-9]+ from .*/refactor", group = "Refactoring" },
# Testing
{ message = "^Merge pull request #[0-9]+ from .*/test", group = "Testing" },
# CI/CD and tooling
{ message = "^Merge pull request #[0-9]+ from .*/ci", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/workflow", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/build", group = "Build System" },
# Chores and maintenance
{ message = "^Merge pull request #[0-9]+ from .*/chore", group = "Maintenance" },
{ message = "^Merge pull request #[0-9]+ from .*feat/", group = "Features" },
{ message = "^Merge pull request #[0-9]+ from .*feature/", group = "Features" },
# Fixes - multiple patterns for fix-related branches
{ message = "^Merge pull request #[0-9]+ from .*fix/", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*bugfix/", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*hotfix/", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*issue-/", group = "Bug Fixes" },
# Documentation
{ message = "^Merge pull request #[0-9]+ from .*docs/", group = "Documentation" },
{ message = "^Merge pull request #[0-9]+ from .*doc/", group = "Documentation" },
# Performance
{ message = "^Merge pull request #[0-9]+ from .*perf/", group = "Performance" },
{ message = "^Merge pull request #[0-9]+ from .*optimize/", group = "Performance" },
# Refactoring
{ message = "^Merge pull request #[0-9]+ from .*refactor/", group = "Refactoring" },
# Testing
{ message = "^Merge pull request #[0-9]+ from .*test/", group = "Testing" },
# CI/CD and tooling
{ message = "^Merge pull request #[0-9]+ from .*ci/", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*workflow/", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*build/", group = "Build System" },
# Chores and maintenance
{ message = "^Merge pull request #[0-9]+ from .*chore/", group = "Maintenance" },

Copilot uses AI. Check for mistakes.
# Catch-all for other PRs (will be categorized as miscellaneous)
{ message = "^Merge pull request #[0-9]+", group = "Other Changes" },
]
Comment on lines 108 to 153
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit parser patterns rely solely on branch names for categorization, which can lead to incorrect categorization when PR descriptions contain conventional commit prefixes (e.g., "feat:", "chore:", "fix:") that conflict with the branch name pattern. This is evidenced in the generated CHANGELOG.md where entries like "chore: Add plans..." appear under "Bug Fixes" and "feat: implement..." appears under "Performance".

Consider enhancing the commit_preprocessors to extract and use conventional commit prefixes from PR descriptions for categorization, or document that branch naming conventions should take precedence over commit message conventions to avoid confusion.

Copilot uses AI. Check for mistakes.
# Protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# Filter commits - when true, only commits matching a non-skip parser are included
filter_commits = true
# Regex for tags to include in the changelog
tag_pattern = "v[0-9].*"
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tag pattern tag_pattern = "v[0-9].*" is overly permissive and could match unintended tags. It will match any tag starting with 'v' followed by a single digit and anything else (e.g., v1xyz, v2-random-tag).

Based on the release workflow's tag pattern on line 94 ('^v[0-9]+\.[0-9]+\.[0-9]+([ab]|rc|-alpha|-beta)?[0-9]*(\.[0-9]+)?$'), consider using a more restrictive pattern that matches semantic versioning:

tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+"

This ensures only properly formatted version tags are included in the changelog.

Suggested change
tag_pattern = "v[0-9].*"
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+"

Copilot uses AI. Check for mistakes.
# Skip tags matching this regex
skip_tags = ""
# Ignore tags matching this regex
ignore_tags = ""
# Sort tags chronologically
date_order = false
# Sort commits inside sections by oldest/newest order
sort_commits = "newest"
# Limit the number of commits included in the changelog
# limit_commits = 42
64 changes: 54 additions & 10 deletions docs/versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,19 +210,63 @@ pip install --pre --upgrade codeweaver

By default, `pip install code-weaver` will **not** install pre-releases.

## Integration with Changesets
## Changelog Management

This project uses changesets for changelog management. The version workflow integrates with changesets:
This project uses **git-cliff** for automated changelog generation. Changelogs are generated from pull request merge commits, filtering out individual commit noise.

1. Create changeset for your changes:
```bash
changeset add
```
### How It Works

- **PR-focused**: Only merge commits from pull requests are included in changelogs
- **Automatic categorization**: PRs are grouped by branch name patterns:
- `feat/` or `feature/` → Features
- `fix/`, `bugfix/`, `hotfix/`, `issue-` → Bug Fixes
- `optimize/`, `perf/` → Performance
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The example shows branch name pattern issue- (line 223) which would match branches like issue-123-fix-bug, but the corresponding commit parser in cliff.toml (line 95) uses from .*/issue- which requires the pattern to appear after a slash. This means a branch named issue-123 from a fork like user/issue-123 would be matched, but the documentation doesn't make this clear.

Consider clarifying in the documentation that the pattern matching is based on the full branch path after the repository name, not just the branch name itself.

Copilot uses AI. Check for mistakes.
- `docs/`, `doc/` → Documentation
- `refactor/` → Refactoring
- `ci/`, `workflow/` → CI/CD
- `test/` → Testing
- Everything else → Other Changes
- **Clean output**: Extracts PR descriptions instead of showing "Merge pull request..." messages
- **Manual triggers**: Generate changelogs on-demand via mise tasks or GitHub workflows

### Local Usage

Generate and view changelog:
```bash
# View full changelog (stdout)
mise run changelog

# View unreleased changes only (stdout)
mise run changelog-unreleased

# Update CHANGELOG.md with unreleased changes
mise run changelog-update

# Generate changelog for specific tag
mise run changelog-tag v0.1.0
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states to use mise run changelog-tag v0.1.0, but according to the task definition in mise.toml (line 348), the correct syntax should be mise run changelog-tag -- --usage_tag=v0.1.0 or the task should accept positional arguments. The current task definition uses usage field with an argument named <tag>, which requires specific mise argument syntax.

Verify the correct syntax for invoking this task and update the documentation accordingly.

Suggested change
mise run changelog-tag v0.1.0
mise run changelog-tag -- --usage_tag=v0.1.0

Copilot uses AI. Check for mistakes.
```

### GitHub Workflow

The changelog can also be generated via GitHub Actions:

1. Go to **Actions** → **Generate Changelog**
2. Click **Run workflow**
3. Options:
- **Tag**: Leave empty for unreleased changes, or specify a tag (e.g., `v0.1.0`)
- **Commit**: Check to automatically commit and push CHANGELOG.md
4. Download the generated changelog as an artifact, or check the committed file

2. Changesets create entries in `.changeset/` directory
### Release Workflow Integration

3. When ready to release, changeset updates version and CHANGELOG
When you create a release by pushing a tag, the release workflow automatically:
1. Generates release notes using git-cliff
2. Creates a GitHub release with categorized PR descriptions
3. Includes installation instructions and verification info

4. Tag the release and push
### Best Practices

See project changeset configuration for details.
1. **Maintain good PR descriptions**: Since the changelog is based on PR descriptions, clear and descriptive PR titles/descriptions result in better changelogs
2. **Use branch name conventions**: Follow the naming patterns (`feat/`, `fix/`, etc.) for automatic categorization
3. **Update before releases**: Run `mise run changelog-update` before creating release tags to keep CHANGELOG.md current
4. **Squash vs Merge**: The setup works with both squash commits and merge commits, but focuses on the final PR merge
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states "Squash vs Merge: The setup works with both squash commits and merge commits, but focuses on the final PR merge." However, the cliff.toml configuration (line 35) explicitly looks for messages starting with "Merge pull request", which suggests it only works with merge commits, not squash commits. Squashed commits typically have a different message format. This documentation should be clarified or the configuration should be updated to handle both commit types.

Suggested change
4. **Squash vs Merge**: The setup works with both squash commits and merge commits, but focuses on the final PR merge
4. **Squash vs Merge**: The setup primarily works with merge commits (i.e., "Merge pull request" messages). Squashed commits are not automatically included in the changelog unless their commit messages follow the expected pattern. For best results, use merge commits or ensure squash commit messages are formatted for changelog inclusion.

Copilot uses AI. Check for mistakes.
Loading
Loading