Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 11 additions & 0 deletions workflows/release-notes-generator/.ambient/ambient.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "Release Notes Generator",
"description": "Generate structured release notes from git commits and tags with automatic categorization into features, bug fixes, breaking changes, and enhancements",
"systemPrompt": "You are a release notes generation specialist helping users create professional, structured release notes from git commit history.\n\n## Your Role\n\nHelp users generate comprehensive release notes by:\n1. Analyzing git commits between version tags\n2. Automatically categorizing changes (features, bug fixes, breaking changes, enhancements)\n3. Extracting PR numbers and commit hashes\n4. Generating markdown-formatted release notes ready for GitHub releases\n\n## Available Commands\n\n- `/generate` - Interactive guided release notes generation\n\n## How to Help Users\n\n**Conversational Approach**: Guide users through providing:\n- Current version tag (required)\n- Previous version tag (optional but recommended)\n- Repository path (optional, defaults to current directory)\n- Repository URL (optional, for generating clickable links)\n\n**Automatic Installation**: The utility-mcp-server package will be installed automatically if needed.\n\n**Output Location**: All generated files go to `artifacts/release-notes/`\n\n## Process Flow\n\n1. **Gather Information**: Get version tags, repo path, and URL from user\n2. **Install Tool**: Ensure utility-mcp-server Python package is available\n3. **Generate Notes**: Call the generation tool with user's parameters\n4. **Save Output**: Save to `artifacts/release-notes/RELEASE_NOTES_<version>.md`\n5. **Present Results**: Show the user the generated notes and statistics\n\n## Tool Details\n\nYou use the `generate_release_notes` function from utility-mcp-server which:\n- Parses git log between tags\n- Recognizes conventional commit formats (feat:, fix:, BREAKING CHANGE:, etc.)\n- Categorizes by component (UI/UX, API, Database, CLI, etc.)\n- Extracts PR numbers from patterns like #123, (#123), PR #123\n- Generates professional markdown with emoji indicators\n\n## Best Practices\n\n- Always ask for both current and previous version tags for meaningful diffs\n- Encourage users to provide repository URL for clickable PR/commit links\n- Explain commit message best practices if notes seem sparse\n- Save both the markdown and statistics for user reference\n\n## Quality Guidelines\n\n- Verify git tags exist before attempting generation\n- Handle errors gracefully with helpful messages\n- If no commits found, explain possible reasons (tags don't exist, no changes between tags)\n- Show statistics to help users understand the scope of changes",
"startupPrompt": "Greet the user briefly as a release notes generation assistant. Explain that you can generate structured release notes from git commits between version tags, automatically categorizing changes into features, bug fixes, breaking changes, and enhancements. Ask what repository and version tags they'd like to generate release notes for. Keep it concise (2-3 sentences).",
"results": {
"Release Notes": "artifacts/release-notes/RELEASE_NOTES_*.md",
"Statistics": "artifacts/release-notes/stats_*.json",
"Generation Scripts": "artifacts/release-notes/generate_*.py"
}
}
142 changes: 142 additions & 0 deletions workflows/release-notes-generator/.claude/commands/generate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# /generate - Generate Release Notes

Generate structured release notes from git commits between two version tags with automatic categorization.

## Usage

```
/generate [current_version] [previous_version] [repo_path] [repo_url]
```

All parameters are optional - if not provided, you'll be prompted conversationally.

## Examples

```
/generate v1.0.0 v0.9.0
/generate v2.0.0 v1.9.0 /path/to/repo
/generate v1.5.0 v1.4.0 /path/to/repo https://github.com/org/repo
```

## Process

### 1. Gather Information

Collect from user (if not in command):
- Current version tag (required)
- Previous version tag (optional)
- Repository path (optional, defaults to current directory)
- Repository URL (optional, for clickable links)

### 2. Validate Environment

```bash
# Verify git repository
git -C <repo_path> status

# List and verify tags
git -C <repo_path> tag -l
git -C <repo_path> tag -l | grep -x <version>
```

### 3. Install Tool

```bash
python3 -c "import utility_mcp_server" 2>/dev/null || pip install utility-mcp-server
```

### 4. Create Generation Script

Save to `artifacts/release-notes/generate_<version>.py`:

```python
#!/usr/bin/env python3
import asyncio
import json
from pathlib import Path
from utility_mcp_server.src.tools.release_notes_tool import generate_release_notes

async def main():
# Ensure output directory exists
Path("artifacts/release-notes").mkdir(parents=True, exist_ok=True)

# Generate release notes
result = await generate_release_notes(
version="<VERSION>",
previous_version="<PREVIOUS_VERSION>",
repo_path="<REPO_PATH>",
repo_url="<REPO_URL>",
release_date=None # Uses today's date
)

if result.get("status") == "success":
# Save release notes
notes_file = "artifacts/release-notes/RELEASE_NOTES_<VERSION>.md"
with open(notes_file, "w") as f:
f.write(result["release_notes"])
print(f"βœ… Release notes saved to: {notes_file}")

# Save statistics
if "statistics" in result:
stats_file = "artifacts/release-notes/stats_<VERSION>.json"
with open(stats_file, "w") as f:
json.dump(result["statistics"], f, indent=2)
print(f"βœ… Statistics saved to: {stats_file}")

# Display release notes
print("\n" + "="*80)
print(result["release_notes"])
print("="*80 + "\n")

# Display statistics
if "statistics" in result:
print("πŸ“Š Statistics:")
for key, value in result["statistics"].items():
print(f" {key}: {value}")

return result
else:
error_msg = result.get("error", "Unknown error")
print(f"❌ Error: {error_msg}")
return result

if __name__ == "__main__":
asyncio.run(main())
```
Comment on lines +48 to +105
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | πŸ”΅ Trivial

Clarify that placeholders must be replaced.

The script template contains placeholders like <VERSION>, <PREVIOUS_VERSION>, <REPO_PATH>, and <REPO_URL> (lines 65-68, 74, 81), but there's no explicit instruction that these must be replaced with actual values. While this may be obvious in context, adding a brief comment above the script template would improve clarity.

πŸ“ Suggested documentation improvement
 ### 4. Create Generation Script
 
+Replace `<VERSION>`, `<PREVIOUS_VERSION>`, `<REPO_PATH>`, and `<REPO_URL>` with actual values.
+
 Save to `artifacts/release-notes/generate_<version>.py`:
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### 4. Create Generation Script
Save to `artifacts/release-notes/generate_<version>.py`:
```python
#!/usr/bin/env python3
import asyncio
import json
from pathlib import Path
from utility_mcp_server.src.tools.release_notes_tool import generate_release_notes
async def main():
# Ensure output directory exists
Path("artifacts/release-notes").mkdir(parents=True, exist_ok=True)
# Generate release notes
result = await generate_release_notes(
version="<VERSION>",
previous_version="<PREVIOUS_VERSION>",
repo_path="<REPO_PATH>",
repo_url="<REPO_URL>",
release_date=None # Uses today's date
)
if result.get("status") == "success":
# Save release notes
notes_file = "artifacts/release-notes/RELEASE_NOTES_<VERSION>.md"
with open(notes_file, "w") as f:
f.write(result["release_notes"])
print(f"βœ… Release notes saved to: {notes_file}")
# Save statistics
if "statistics" in result:
stats_file = "artifacts/release-notes/stats_<VERSION>.json"
with open(stats_file, "w") as f:
json.dump(result["statistics"], f, indent=2)
print(f"βœ… Statistics saved to: {stats_file}")
# Display release notes
print("\n" + "="*80)
print(result["release_notes"])
print("="*80 + "\n")
# Display statistics
if "statistics" in result:
print("πŸ“Š Statistics:")
for key, value in result["statistics"].items():
print(f" {key}: {value}")
return result
else:
error_msg = result.get("error", "Unknown error")
print(f"❌ Error: {error_msg}")
return result
if __name__ == "__main__":
asyncio.run(main())
```
### 4. Create Generation Script
Replace `<VERSION>`, `<PREVIOUS_VERSION>`, `<REPO_PATH>`, and `<REPO_URL>` with actual values.
Save to `artifacts/release-notes/generate_<version>.py`:
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workflows/release-notes-generator/.claude/commands/generate.md` around lines
48 - 105, Summary: The script template uses placeholders (<VERSION>,
<PREVIOUS_VERSION>, <REPO_PATH>, <REPO_URL>) but doesn't tell users to replace
them. Fix: add a short clarifying comment above the script (or at the top of the
main() block) that explicitly lists the placeholders (<VERSION>,
<PREVIOUS_VERSION>, <REPO_PATH>, <REPO_URL>) and instructs the user to replace
them with real values (or supply them via templating/CLI/env) before running;
reference the generate_release_notes call in main() so readers know which
parameters must be populated.


### 5. Execute

```bash
cd artifacts/release-notes && python3 generate_<version>.py
```
Comment on lines +107 to +111
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | πŸ”΄ Critical

Path inconsistency between script and execution.

The execution step changes directory to artifacts/release-notes/ before running the script, but the script itself (line 61) uses Path("artifacts/release-notes").mkdir(...) which is a relative path. If executed from within artifacts/release-notes/, this would create artifacts/release-notes/artifacts/release-notes/, causing the script to fail or write to the wrong location.

πŸ”§ Proposed fix

Either execute from the repository root:

-### 5. Execute
-
-```bash
-cd artifacts/release-notes && python3 generate_<version>.py
-```
+### 5. Execute
+
+```bash
+python3 artifacts/release-notes/generate_<version>.py
+```

Or update the script to use absolute paths or adjust for the current directory.

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### 5. Execute
```bash
cd artifacts/release-notes && python3 generate_<version>.py
```
### 5. Execute
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workflows/release-notes-generator/.claude/commands/generate.md` around lines
107 - 111, The current execute step changes into artifacts/release-notes before
running generate_<version>.py, but the script itself calls
Path("artifacts/release-notes").mkdir(...) which uses a relative path and will
create nested directories; fix by either updating the execution command to run
from the repo root (use python3 artifacts/release-notes/generate_<version>.py in
the "Execute" section) or modify the script generate_<version>.py to build an
absolute path for the artifacts directory (use
Path(__file__).resolve().parent.joinpath("artifacts/release-notes") or similar
and call mkdir on that Path instead of Path("artifacts/release-notes")).


### 6. Present Results

Show the user:
1. Generated release notes (formatted)
2. Statistics summary
3. File locations
4. Next steps

## Output

Files created in `artifacts/release-notes/`:
- `RELEASE_NOTES_<version>.md` - Main release notes
- `stats_<version>.json` - Statistics
- `generate_<version>.py` - Generation script

## Error Handling

Handle gracefully:
- Tags don't exist β†’ List available tags
- No commits β†’ Explain possible causes
- Not a git repo β†’ Verify path
- Installation fails β†’ Check Python/pip

## Tips

Suggest to users:
- Use conventional commits (`feat:`, `fix:`, etc.)
- Include PR numbers in commits
- Provide repository URL for links
- Tag releases consistently
40 changes: 40 additions & 0 deletions workflows/release-notes-generator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
.venv/
ENV/
*.egg-info/
dist/
build/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Output artifacts (generated at runtime)
artifacts/

# Logs
*.log
.claude/logs/

# Temporary files
*.tmp
.temp/
tmp/

# Environment
.env
.env.local

# Test outputs
test-output/
202 changes: 202 additions & 0 deletions workflows/release-notes-generator/ADD_GENERATE_COMMAND.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# How to Add the /generate Command

The system has security restrictions that prevent automatic creation of files in `.claude/commands/`.

You'll need to add the command file manually. Here's how:

## Quick Method

I've created the command content for you at:
```
/workspace/artifacts/release-notes-workflow/generate_command_temp.md
```

**Simply rename and move it:**

```bash
cd /workspace/artifacts/release-notes-workflow
mv generate_command_temp.md .claude/commands/generate.md
```

## Alternative: Create Directly in Git

If you've already pushed to GitHub and are working in a clone:

```bash
cd /path/to/your/workflows-repo/workflows/release-notes-generator

# Create the file directly
cat > .claude/commands/generate.md << 'EOF'
# /generate - Generate Release Notes

Generate structured release notes from git commits between two version tags with automatic categorization.

## Usage

\`\`\`
/generate [current_version] [previous_version] [repo_path] [repo_url]
\`\`\`

All parameters are optional - if not provided, you'll be prompted conversationally.

## Examples

\`\`\`
/generate v1.0.0 v0.9.0
/generate v2.0.0 v1.9.0 /path/to/repo
/generate v1.5.0 v1.4.0 /path/to/repo https://github.com/org/repo
\`\`\`

## Process

### 1. Gather Information

Collect from user (if not in command):
- Current version tag (required)
- Previous version tag (optional)
- Repository path (optional, defaults to current directory)
- Repository URL (optional, for clickable links)

### 2. Validate Environment

\`\`\`bash
# Verify git repository
git -C <repo_path> status

# List and verify tags
git -C <repo_path> tag -l
git -C <repo_path> tag -l | grep -x <version>
\`\`\`

### 3. Install Tool

\`\`\`bash
python3 -c "import utility_mcp_server" 2>/dev/null || pip install utility-mcp-server
\`\`\`

### 4. Create Generation Script

Save to \`artifacts/release-notes/generate_<version>.py\`:

\`\`\`python
#!/usr/bin/env python3
import asyncio
import json
from pathlib import Path
from utility_mcp_server.src.tools.release_notes_tool import generate_release_notes

async def main():
# Ensure output directory exists
Path("artifacts/release-notes").mkdir(parents=True, exist_ok=True)

# Generate release notes
result = await generate_release_notes(
version="<VERSION>",
previous_version="<PREVIOUS_VERSION>",
repo_path="<REPO_PATH>",
repo_url="<REPO_URL>",
release_date=None # Uses today's date
)

if result.get("status") == "success":
# Save release notes
notes_file = "artifacts/release-notes/RELEASE_NOTES_<VERSION>.md"
with open(notes_file, "w") as f:
f.write(result["release_notes"])
print(f"βœ… Release notes saved to: {notes_file}")

# Save statistics
if "statistics" in result:
stats_file = "artifacts/release-notes/stats_<VERSION>.json"
with open(stats_file, "w") as f:
json.dump(result["statistics"], f, indent=2)
print(f"βœ… Statistics saved to: {stats_file}")

# Display release notes
print("\n" + "="*80)
print(result["release_notes"])
print("="*80 + "\n")

# Display statistics
if "statistics" in result:
print("πŸ“Š Statistics:")
for key, value in result["statistics"].items():
print(f" {key}: {value}")

return result
else:
error_msg = result.get("error", "Unknown error")
print(f"❌ Error: {error_msg}")
return result

if __name__ == "__main__":
asyncio.run(main())
\`\`\`

### 5. Execute

\`\`\`bash
cd artifacts/release-notes && python3 generate_<version>.py
\`\`\`

### 6. Present Results

Show the user:
1. Generated release notes (formatted)
2. Statistics summary
3. File locations
4. Next steps

## Output

Files created in \`artifacts/release-notes/\`:
- \`RELEASE_NOTES_<version>.md\` - Main release notes
- \`stats_<version>.json\` - Statistics
- \`generate_<version>.py\` - Generation script

## Error Handling

Handle gracefully:
- Tags don't exist β†’ List available tags
- No commits β†’ Explain possible causes
- Not a git repo β†’ Verify path
- Installation fails β†’ Check Python/pip

## Tips

Suggest to users:
- Use conventional commits (\`feat:\`, \`fix:\`, etc.)
- Include PR numbers in commits
- Provide repository URL for links
- Tag releases consistently
EOF

# Commit it
git add .claude/commands/generate.md
git commit -m "feat: Add /generate command"
```

## Verify

Check that the file was created:

```bash
ls -la .claude/commands/
cat .claude/commands/generate.md
```

## Why is this file important?

The `/generate` command allows users to invoke the release notes generation with a slash command instead of just conversational mode. It's optional but provides a nice shortcut.

**Without it**: Workflow still works conversationally
**With it**: Users can type `/generate v1.0.0 v0.9.0` for quick invocation

## Next Steps

Once you've added the command file:

1. Commit all changes
2. Push to GitHub
3. Test with Custom Workflow in ACP
4. Verify `/generate` command appears and works
Loading