Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
80 changes: 80 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 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: |
# Note: Using --prepend adds new entries at the top of CHANGELOG.md
# This preserves existing content but may create duplicates if run multiple times for the same version
# See docs/versioning.md for details on changelog management
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 --prepend
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 --prepend flag is used here but not in the changelog-tag task (line 354). This inconsistency means that changelog-tag will overwrite CHANGELOG.md instead of prepending to it. For consistency, either add --prepend to the changelog-tag task or document that it intentionally overwrites the file.

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.

When generating a changelog for a specific tag (line 44), the --prepend flag is used, which will add the generated content to the beginning of the existing CHANGELOG.md file. However, this may result in duplicate content if the tag already exists in the changelog. Consider using --output CHANGELOG.md without --prepend when generating for a specific tag, or add logic to check if the tag already exists in the changelog before prepending.

Suggested change
git-cliff --tag "${{ github.event.inputs.tag }}" --output CHANGELOG.md --prepend
git-cliff --tag "${{ github.event.inputs.tag }}" --output CHANGELOG.md

Copilot uses AI. Check for mistakes.
else
echo "Generating changelog for unreleased changes"
git-cliff --unreleased --prepend --output CHANGELOG.md
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
if [ -n "${{ github.event.inputs.tag }}" ]; then
git commit -m "docs: update CHANGELOG.md for ${{ github.event.inputs.tag }}"
else
Comment on lines +68 to +69
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 message also uses unsanitized user input from github.event.inputs.tag. While less critical than command injection, this could allow malicious commit messages to be created.

Consider validating the tag input or using a sanitized version in the commit message.

Suggested change
git commit -m "docs: update CHANGELOG.md for ${{ github.event.inputs.tag }}"
else
# Sanitize the tag input: allow only alphanumerics, dots, dashes, and underscores
SAFE_TAG=$(echo "${{ github.event.inputs.tag }}" | grep -Eo '^[A-Za-z0-9._-]+$')
if [ -z "$SAFE_TAG" ]; then
echo "Tag input contains invalid characters. Using 'unknown-tag' in commit message."
git commit -m "docs: update CHANGELOG.md for unknown-tag"
else
git commit -m "docs: update CHANGELOG.md for $SAFE_TAG"
fi

Copilot uses AI. Check for mistakes.
git commit -m "docs: update CHANGELOG.md with unreleased changes"
fi
git push
fi

- name: Upload changelog artifact
uses: actions/upload-artifact@4b540d30404c5374296eb0061f5d53f85b8f4cc2
with:
name: changelog
path: CHANGELOG.md
retention-days: 7
77 changes: 76 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,84 @@ 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]+([ab]|rc|-alpha|-beta)?[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.
# Note: We use '--strip header' to intentionally remove the changelog header (as defined in cliff.toml),
# so that only the changes section is extracted for embedding in the release notes.
if [ -n "$PREVIOUS_TAG" ] && [ "$PREVIOUS_TAG" != "$CURRENT_TAG" ]; then
# Generate changelog for the range between previous and current tag
git-cliff --strip header --tag "$CURRENT_TAG" "$PREVIOUS_TAG..$CURRENT_TAG" > changelog_section.md
else
# First release - get all commits
git-cliff --strip header --tag "$CURRENT_TAG" > changelog_section.md
Comment on lines +106 to +109
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 --strip header flag is used on lines 106 and 109, but this flag doesn't exist in git-cliff 2.8.1. The correct flag is --strip all or --body to exclude the header. This will cause the release notes generation to fail.

Suggested change
git-cliff --strip header --tag "$CURRENT_TAG" "$PREVIOUS_TAG..$CURRENT_TAG" > changelog_section.md
else
# First release - get all commits
git-cliff --strip header --tag "$CURRENT_TAG" > changelog_section.md
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

Copilot uses AI. Check for mistakes.
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
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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))
- feat: implement modular workflows with efficiency optimizations ([#166](https://github.com/knitli/codeweaver/pull/166))

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

<!-- generated by git-cliff -->
169 changes: 169 additions & 0 deletions cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# 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("SQUASH | ") -%}
{# Handle squash merge format: "SQUASH | description | #123" #}
{%- set_global parts = commit.message | split(pat=" | ") -%}
{%- set_global pr_desc = parts | nth(n=1) | trim -%}
{%- set_global pr_num = parts | nth(n=2) | replace(from="#", to="") | trim -%}
{%- if pr_num is matching("^[0-9]+$") -%}
- {{ pr_desc }} ([#{{ pr_num }}](https://github.com/knitli/codeweaver/pull/{{ pr_num }}))
{%- else -%}
- {{ pr_desc }}
{%- endif -%}
{%- elif commit.message is starting_with("Merge pull request") -%}
{# Handle regular merge format: "Merge pull request #123 from org/branch | Description" #}
{%- set_global pr_num = commit.message | replace(from="Merge pull request #", to="") | split(pat=" ") | first | trim -%}
{%- if commit.message is containing(" | ") -%}
{%- set_global sep_index = commit.message | find(pat=" | ") -%}
{%- if sep_index is not none and sep_index >= 0 -%}
{%- set_global pr_desc = commit.message | slice(start=(sep_index + 3)) | trim -%}
{%- else -%}
{%- set_global pr_desc = "No description" -%}
{%- endif -%}
{%- endif %}
{%- if pr_num is matching("^[0-9]+$") -%}
- {{ pr_desc }} ([#{{ pr_num }}](https://github.com/knitli/codeweaver/pull/{{ pr_num }}))
{%- else -%}
- {{ pr_desc }}
{%- endif -%}
{%- 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}))" },
# ]

Comment on lines +77 to +81
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 is designed to replace (#123) with a markdown link, but the body template (lines 43) already generates markdown links for PR numbers: ([#{{ pr_num }}](https://github.com/knitli/codeweaver/pull/{{ pr_num }})). This postprocessor would then convert these already-linked references into double-nested links like ([#123](...))([#123](...))(...), resulting in broken markdown. Either remove this postprocessor since links are already generated in the template, or adjust the template to not generate links.

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

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
# Preprocessors for both merge commits and squash merges
commit_preprocessors = [
# 1. Extract PR description from merge commits and append to subject
# 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+([\s\S]+)', replace = "Merge pull request ${1} from ${2} | ${3}" },

# 2. Mark squash merge commits for easier template detection
# Input: "feat: some feature (#123)"
# Output: "SQUASH | feat: some feature | #123"
{ pattern = '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+?\))?: (.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1}${2}: ${3} | #${4}" },
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 for squash merges with conventional commit prefixes is missing the optimize type which is mentioned in the documentation (docs/versioning.md line 223: optimize/, perf/ → Performance). Consider adding |optimize to the pattern to ensure consistency between branch naming conventions and squash merge commit parsing:

{ pattern = '^(feat|fix|docs|style|refactor|perf|optimize|test|build|ci|chore|revert)(\(.+?\))?: (.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1}${2}: ${3} | #${4}" },
Suggested change
{ pattern = '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+?\))?: (.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1}${2}: ${3} | #${4}" },
{ pattern = '^(feat|fix|docs|style|refactor|perf|optimize|test|build|ci|chore|revert)(\(.+?\))?: (.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1}${2}: ${3} | #${4}" },

Copilot uses AI. Check for mistakes.

# 3. Catch squash merges without conventional commit prefix
# Input: "Some change (#123)"
# Output: "SQUASH | Some change | #123"
{ pattern = '^(.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1} | #${2}" },
]
# Parse both merge commits and squash merges 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 },

# === Squash Merge Parsers (conventional commits) ===
# After preprocessing, squash merges are in format: "SQUASH | type: description | #123"
{ message = "^SQUASH \\| feat", group = "Features" },
{ message = "^SQUASH \\| fix", group = "Bug Fixes" },
{ message = "^SQUASH \\| docs", group = "Documentation" },
{ message = "^SQUASH \\| perf", group = "Performance" },
{ message = "^SQUASH \\| refactor", group = "Refactoring" },
{ message = "^SQUASH \\| test", group = "Testing" },
{ message = "^SQUASH \\| build", group = "Build System" },
{ message = "^SQUASH \\| ci", group = "CI/CD" },
Comment on lines +111 to +121
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 squash merge commit parsers are missing handlers for optimize and revert types, which are mentioned in the branch naming documentation and in the preprocessor regex (line 96). Add the following parsers to maintain consistency:

{ message = "^SQUASH \\| optimize", group = "Performance" },
{ message = "^SQUASH \\| revert", group = "Reverts" },

Also note that revert is already handled at line 120, but optimize is missing entirely from the squash parsers.

Copilot uses AI. Check for mistakes.
{ message = "^SQUASH \\| chore", group = "Maintenance" },
{ message = "^SQUASH \\| revert", group = "Reverts" },
{ message = "^SQUASH \\|", group = "Other Changes" },

# === Regular Merge Commit Parsers (branch-based) ===
# 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" },
]
# 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]+\\.[0-9]+\\.[0-9]+.*"
# 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
Loading
Loading