Initial commit
This commit is contained in:
12
.claude-plugin/plugin.json
Normal file
12
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "docs-and-changelogs",
|
||||
"description": "Generates comprehensive changelogs from Conventional Commits, maintains CHANGELOG.md files, and scaffolds project documentation like PRD.md or ADR.md. This skill should be used when creating changelogs, generating release notes, maintaining version history, documenting architectural decisions, or scaffolding project requirements documentation. Use for changelog generation, release notes, version documentation, ADR, PRD, or technical documentation.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Hope Overture",
|
||||
"email": "support@worldbuilding-app-skills.dev"
|
||||
},
|
||||
"skills": [
|
||||
"./skills"
|
||||
]
|
||||
}
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# docs-and-changelogs
|
||||
|
||||
Generates comprehensive changelogs from Conventional Commits, maintains CHANGELOG.md files, and scaffolds project documentation like PRD.md or ADR.md. This skill should be used when creating changelogs, generating release notes, maintaining version history, documenting architectural decisions, or scaffolding project requirements documentation. Use for changelog generation, release notes, version documentation, ADR, PRD, or technical documentation.
|
||||
57
plugin.lock.json
Normal file
57
plugin.lock.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||
"pluginId": "gh:hopeoverture/worldbuilding-app-skills:plugins/docs-and-changelogs",
|
||||
"normalized": {
|
||||
"repo": null,
|
||||
"ref": "refs/tags/v20251128.0",
|
||||
"commit": "cfb63484fdfc5263340df4c49b4c99ee1df70eaa",
|
||||
"treeHash": "f5a41674605bfcb425fff6e526042b8b766bc84f6c95f272e3d6db0dbb382da7",
|
||||
"generatedAt": "2025-11-28T10:17:34.957922Z",
|
||||
"toolVersion": "publish_plugins.py@0.2.0"
|
||||
},
|
||||
"origin": {
|
||||
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||
"branch": "master",
|
||||
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "docs-and-changelogs",
|
||||
"description": "Generates comprehensive changelogs from Conventional Commits, maintains CHANGELOG.md files, and scaffolds project documentation like PRD.md or ADR.md. This skill should be used when creating changelogs, generating release notes, maintaining version history, documenting architectural decisions, or scaffolding project requirements documentation. Use for changelog generation, release notes, version documentation, ADR, PRD, or technical documentation.",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"content": {
|
||||
"files": [
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "05ec3485cd559235539ce17ff177c84f3bfb6cccde6741a35e08057a36264063"
|
||||
},
|
||||
{
|
||||
"path": ".claude-plugin/plugin.json",
|
||||
"sha256": "dc1e37d07897a72add6305a6876c9accafb4d6217098566d2aad3671ca9161d2"
|
||||
},
|
||||
{
|
||||
"path": "skills/docs-and-changelogs/SKILL.md",
|
||||
"sha256": "d1009762952d079aac28e310e02e9aae4c6d9e223cae011c06f363853ed723a7"
|
||||
},
|
||||
{
|
||||
"path": "skills/docs-and-changelogs/scripts/create_prd.py",
|
||||
"sha256": "7ac9fb4c4e7f0ac50a41083a60c3d362ce947f69fc6b6e577d3522041e9add13"
|
||||
},
|
||||
{
|
||||
"path": "skills/docs-and-changelogs/scripts/generate_changelog.py",
|
||||
"sha256": "331826193a5e77b3f7d34cc5b61f1f766b13547fdd26a30926bc59f77f04667f"
|
||||
},
|
||||
{
|
||||
"path": "skills/docs-and-changelogs/scripts/create_adr.py",
|
||||
"sha256": "b24c6f9bd74883213e2b09c2fded60bb85c7acecf711e651a46ac61ad4cd9399"
|
||||
}
|
||||
],
|
||||
"dirSha256": "f5a41674605bfcb425fff6e526042b8b766bc84f6c95f272e3d6db0dbb382da7"
|
||||
},
|
||||
"security": {
|
||||
"scannedAt": null,
|
||||
"scannerVersion": null,
|
||||
"flags": []
|
||||
}
|
||||
}
|
||||
285
skills/docs-and-changelogs/SKILL.md
Normal file
285
skills/docs-and-changelogs/SKILL.md
Normal file
@@ -0,0 +1,285 @@
|
||||
---
|
||||
name: docs-and-changelogs
|
||||
description: Generates comprehensive changelogs from Conventional Commits, maintains CHANGELOG.md files, and scaffolds project documentation like PRD.md or ADR.md. This skill should be used when creating changelogs, generating release notes, maintaining version history, documenting architectural decisions, or scaffolding project requirements documentation. Use for changelog generation, release notes, version documentation, ADR, PRD, or technical documentation.
|
||||
---
|
||||
|
||||
# Documentation and Changelogs
|
||||
|
||||
Generate and maintain project documentation including changelogs, architectural decision records, and product requirement documents.
|
||||
|
||||
## Overview
|
||||
|
||||
To manage project documentation effectively:
|
||||
|
||||
1. Generate changelogs from git commit history using Conventional Commits
|
||||
2. Maintain CHANGELOG.md with semantic versioning
|
||||
3. Create architectural decision records (ADR) for significant decisions
|
||||
4. Scaffold product requirement documents (PRD) for new features
|
||||
5. Automate documentation updates as part of release process
|
||||
|
||||
## Changelog Generation
|
||||
|
||||
To generate changelogs from Conventional Commits:
|
||||
|
||||
1. Parse git commit history for conventional commit messages
|
||||
2. Categorize commits by type (feat, fix, chore, docs, etc.)
|
||||
3. Group by version/release using git tags
|
||||
4. Format according to Keep a Changelog standards
|
||||
5. Append to existing CHANGELOG.md or create new file
|
||||
|
||||
Use `scripts/generate_changelog.py` to automate changelog generation from commit history.
|
||||
|
||||
### Conventional Commits Format
|
||||
|
||||
Follow this commit message structure:
|
||||
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat`: New feature
|
||||
- `fix`: Bug fix
|
||||
- `docs`: Documentation changes
|
||||
- `style`: Code style changes (formatting, semicolons, etc.)
|
||||
- `refactor`: Code refactoring without feature changes
|
||||
- `perf`: Performance improvements
|
||||
- `test`: Adding or updating tests
|
||||
- `chore`: Maintenance tasks
|
||||
- `ci`: CI/CD changes
|
||||
|
||||
**Breaking Changes:**
|
||||
- Add `BREAKING CHANGE:` in footer or `!` after type
|
||||
- Example: `feat!: redesign entity schema structure`
|
||||
|
||||
## CHANGELOG.md Maintenance
|
||||
|
||||
To maintain changelog file:
|
||||
|
||||
1. Structure with sections: Unreleased, versioned releases
|
||||
2. Use semantic versioning (MAJOR.MINOR.PATCH)
|
||||
3. Group changes by category (Added, Changed, Deprecated, Removed, Fixed, Security)
|
||||
4. Include links to commits and pull requests
|
||||
5. Add release dates in ISO format (YYYY-MM-DD)
|
||||
|
||||
Consult `references/changelog-format.md` for detailed formatting guidelines and examples.
|
||||
|
||||
## Architectural Decision Records (ADR)
|
||||
|
||||
To create architectural decision records:
|
||||
|
||||
1. Use `scripts/create_adr.py` to scaffold new ADR file
|
||||
2. Number ADRs sequentially (0001-title.md, 0002-title.md)
|
||||
3. Include standard sections: Context, Decision, Consequences
|
||||
4. Document alternatives considered
|
||||
5. Reference related ADRs
|
||||
|
||||
Use `assets/adr-template.md` as starting point for new ADRs.
|
||||
|
||||
### ADR Structure
|
||||
|
||||
Standard ADR sections:
|
||||
|
||||
- **Title**: Short, descriptive name
|
||||
- **Status**: Proposed, Accepted, Deprecated, Superseded
|
||||
- **Context**: What problem are we solving?
|
||||
- **Decision**: What did we decide to do?
|
||||
- **Consequences**: What are the tradeoffs and impacts?
|
||||
- **Alternatives Considered**: What other options were evaluated?
|
||||
|
||||
## Product Requirement Documents (PRD)
|
||||
|
||||
To scaffold product requirement documents:
|
||||
|
||||
1. Use `scripts/create_prd.py` to generate PRD template
|
||||
2. Define problem statement and goals
|
||||
3. List functional and non-functional requirements
|
||||
4. Include user stories and acceptance criteria
|
||||
5. Document technical constraints and dependencies
|
||||
|
||||
Reference `assets/prd-template.md` for comprehensive PRD structure.
|
||||
|
||||
### PRD Sections
|
||||
|
||||
Standard PRD components:
|
||||
|
||||
- **Overview**: High-level description
|
||||
- **Problem Statement**: What problem are we solving?
|
||||
- **Goals and Non-Goals**: Scope definition
|
||||
- **User Stories**: Who, what, why format
|
||||
- **Requirements**: Functional and non-functional
|
||||
- **Design Considerations**: UI/UX, architecture
|
||||
- **Success Metrics**: How to measure success
|
||||
- **Timeline**: Development phases
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Generate Changelog from Commits
|
||||
|
||||
To generate changelog:
|
||||
|
||||
1. **Collect Commits**
|
||||
```bash
|
||||
python scripts/generate_changelog.py --since v1.0.0
|
||||
```
|
||||
|
||||
2. **Categorize Changes**
|
||||
- Parse commit messages for conventional commit types
|
||||
- Extract breaking changes
|
||||
- Group by scope if present
|
||||
|
||||
3. **Format Output**
|
||||
- Generate markdown with appropriate headings
|
||||
- Link to commits and PRs
|
||||
- Add version header with date
|
||||
|
||||
4. **Update CHANGELOG.md**
|
||||
- Prepend new version section
|
||||
- Maintain existing content
|
||||
- Update "Unreleased" section
|
||||
|
||||
### Create New ADR
|
||||
|
||||
To document architectural decision:
|
||||
|
||||
1. **Generate ADR File**
|
||||
```bash
|
||||
python scripts/create_adr.py "use postgresql for entity storage"
|
||||
```
|
||||
|
||||
2. **Fill Template**
|
||||
- Document context and constraints
|
||||
- Explain decision rationale
|
||||
- List consequences and tradeoffs
|
||||
|
||||
3. **Review and Commit**
|
||||
- Get team feedback
|
||||
- Update status to "Accepted"
|
||||
- Link from main architecture docs
|
||||
|
||||
### Scaffold New PRD
|
||||
|
||||
To create product requirements:
|
||||
|
||||
1. **Generate PRD Template**
|
||||
```bash
|
||||
python scripts/create_prd.py "timeline visualization feature"
|
||||
```
|
||||
|
||||
2. **Complete Sections**
|
||||
- Define problem and goals
|
||||
- Write user stories
|
||||
- List requirements
|
||||
|
||||
3. **Review with Stakeholders**
|
||||
- Get product team input
|
||||
- Validate technical feasibility
|
||||
- Refine scope and requirements
|
||||
|
||||
## Automation
|
||||
|
||||
To automate documentation updates:
|
||||
|
||||
### Release Workflow Integration
|
||||
|
||||
Add to `.github/workflows/release.yml`:
|
||||
|
||||
```yaml
|
||||
- name: Generate changelog
|
||||
run: python scripts/generate_changelog.py --output CHANGELOG.md
|
||||
|
||||
- name: Commit changelog
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
git add CHANGELOG.md
|
||||
git commit -m "docs: update changelog for ${{ github.ref_name }}"
|
||||
```
|
||||
|
||||
### Pre-commit Hook
|
||||
|
||||
Add to `.git/hooks/commit-msg`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Validate conventional commit format
|
||||
python scripts/validate_commit_msg.py "$1"
|
||||
```
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
Organize project documentation:
|
||||
|
||||
```
|
||||
docs/
|
||||
├── CHANGELOG.md # Version history
|
||||
├── ADR/ # Architectural decisions
|
||||
│ ├── 0001-use-nextjs.md
|
||||
│ └── 0002-database-choice.md
|
||||
├── PRD/ # Product requirements
|
||||
│ ├── timeline-feature.md
|
||||
│ └── entity-relationships.md
|
||||
└── api/ # API documentation
|
||||
└── endpoints.md
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Changelog
|
||||
|
||||
- Write for users, not developers
|
||||
- Use present tense ("Add" not "Added")
|
||||
- Link to relevant issues/PRs
|
||||
- Highlight breaking changes prominently
|
||||
- Keep entries concise and clear
|
||||
|
||||
### ADR
|
||||
|
||||
- Write when decision is made, not after
|
||||
- Document alternatives considered
|
||||
- Be honest about tradeoffs
|
||||
- Update status if decision changes
|
||||
- Link related ADRs
|
||||
|
||||
### PRD
|
||||
|
||||
- Start with user needs, not solutions
|
||||
- Include success metrics
|
||||
- Define scope clearly (goals and non-goals)
|
||||
- Get stakeholder buy-in early
|
||||
- Update as requirements evolve
|
||||
|
||||
## Version Management
|
||||
|
||||
To manage semantic versioning:
|
||||
|
||||
1. **MAJOR**: Breaking changes (incompatible API changes)
|
||||
2. **MINOR**: New features (backward-compatible)
|
||||
3. **PATCH**: Bug fixes (backward-compatible)
|
||||
|
||||
Use `scripts/bump_version.py` to update version across package.json, changelog, and tags.
|
||||
|
||||
## Release Notes
|
||||
|
||||
To generate release notes:
|
||||
|
||||
1. Extract relevant changelog section
|
||||
2. Add highlights and notable changes
|
||||
3. Include upgrade instructions if needed
|
||||
4. Link to full changelog
|
||||
5. Publish to GitHub releases
|
||||
|
||||
Use `scripts/generate_release_notes.py` to create formatted release notes from changelog.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Common issues:
|
||||
|
||||
- **Commits Not Categorized**: Ensure commits follow Conventional Commits format
|
||||
- **Missing Version**: Tag releases in git with semantic version numbers
|
||||
- **Duplicate Entries**: Check for merge conflicts in CHANGELOG.md
|
||||
- **Broken Links**: Verify commit SHAs and PR numbers are correct
|
||||
172
skills/docs-and-changelogs/scripts/create_adr.py
Normal file
172
skills/docs-and-changelogs/scripts/create_adr.py
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create a new Architectural Decision Record (ADR).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def slugify(text):
|
||||
"""Convert text to lowercase slug format."""
|
||||
text = text.lower()
|
||||
text = re.sub(r'[^\w\s-]', '', text)
|
||||
text = re.sub(r'[-\s]+', '-', text)
|
||||
return text.strip('-')
|
||||
|
||||
|
||||
def get_next_adr_number(adr_dir):
|
||||
"""Get the next ADR number in sequence."""
|
||||
if not adr_dir.exists():
|
||||
return 1
|
||||
|
||||
existing = list(adr_dir.glob('*.md'))
|
||||
if not existing:
|
||||
return 1
|
||||
|
||||
numbers = []
|
||||
for path in existing:
|
||||
match = re.match(r'^(\d+)', path.name)
|
||||
if match:
|
||||
numbers.append(int(match.group(1)))
|
||||
|
||||
return max(numbers) + 1 if numbers else 1
|
||||
|
||||
|
||||
def create_adr(title, adr_dir='docs/ADR', status='Proposed'):
|
||||
"""Create a new ADR file."""
|
||||
adr_dir = Path(adr_dir)
|
||||
adr_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
number = get_next_adr_number(adr_dir)
|
||||
slug = slugify(title)
|
||||
filename = f"{number:04d}-{slug}.md"
|
||||
filepath = adr_dir / filename
|
||||
|
||||
date = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
content = f"""# ADR {number:04d}: {title}
|
||||
|
||||
**Status:** {status}
|
||||
|
||||
**Date:** {date}
|
||||
|
||||
**Deciders:** [List key decision makers]
|
||||
|
||||
## Context
|
||||
|
||||
[Describe the context and problem statement. What forces are at play? What are the constraints?]
|
||||
|
||||
### Problem
|
||||
|
||||
[What specific problem are we trying to solve?]
|
||||
|
||||
### Constraints
|
||||
|
||||
- [Constraint 1]
|
||||
- [Constraint 2]
|
||||
|
||||
## Decision
|
||||
|
||||
[Describe the decision we made and why we made it.]
|
||||
|
||||
### Rationale
|
||||
|
||||
[Explain the reasoning behind the decision. What factors influenced this choice?]
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- [Positive consequence 1]
|
||||
- [Positive consequence 2]
|
||||
|
||||
### Negative
|
||||
|
||||
- [Negative consequence 1]
|
||||
- [Negative consequence 2]
|
||||
|
||||
### Neutral
|
||||
|
||||
- [Neutral consequence 1]
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### Alternative 1: [Name]
|
||||
|
||||
**Description:** [Brief description]
|
||||
|
||||
**Pros:**
|
||||
- [Pro 1]
|
||||
|
||||
**Cons:**
|
||||
- [Con 1]
|
||||
|
||||
**Decision:** Rejected because [reason]
|
||||
|
||||
### Alternative 2: [Name]
|
||||
|
||||
**Description:** [Brief description]
|
||||
|
||||
**Pros:**
|
||||
- [Pro 1]
|
||||
|
||||
**Cons:**
|
||||
- [Con 1]
|
||||
|
||||
**Decision:** Rejected because [reason]
|
||||
|
||||
## Implementation
|
||||
|
||||
[How will this decision be implemented? What are the next steps?]
|
||||
|
||||
- [ ] Task 1
|
||||
- [ ] Task 2
|
||||
|
||||
## Related Decisions
|
||||
|
||||
- [Link to related ADR if applicable]
|
||||
|
||||
## References
|
||||
|
||||
- [Link to relevant documentation]
|
||||
- [Link to discussions or RFCs]
|
||||
|
||||
## Notes
|
||||
|
||||
[Any additional notes or context]
|
||||
"""
|
||||
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"Created ADR: {filepath}")
|
||||
print(f"Number: {number:04d}")
|
||||
print(f"Status: {status}")
|
||||
|
||||
return filepath
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Create a new Architectural Decision Record')
|
||||
parser.add_argument('title', help='Title of the ADR')
|
||||
parser.add_argument('--dir', default='docs/ADR', help='ADR directory path')
|
||||
parser.add_argument('--status', default='Proposed',
|
||||
choices=['Proposed', 'Accepted', 'Rejected', 'Deprecated', 'Superseded'],
|
||||
help='Initial status of the ADR')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
filepath = create_adr(args.title, args.dir, args.status)
|
||||
|
||||
print("\nNext steps:")
|
||||
print(f"1. Edit {filepath} to complete all sections")
|
||||
print("2. Review with the team")
|
||||
print("3. Update status to 'Accepted' when finalized")
|
||||
print("4. Link from architecture documentation")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
353
skills/docs-and-changelogs/scripts/create_prd.py
Normal file
353
skills/docs-and-changelogs/scripts/create_prd.py
Normal file
@@ -0,0 +1,353 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create a new Product Requirement Document (PRD).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def slugify(text):
|
||||
"""Convert text to lowercase slug format."""
|
||||
text = text.lower()
|
||||
text = re.sub(r'[^\w\s-]', '', text)
|
||||
text = re.sub(r'[-\s]+', '-', text)
|
||||
return text.strip('-')
|
||||
|
||||
|
||||
def create_prd(title, prd_dir='docs/PRD', author=''):
|
||||
"""Create a new PRD file."""
|
||||
prd_dir = Path(prd_dir)
|
||||
prd_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
slug = slugify(title)
|
||||
filename = f"{slug}.md"
|
||||
filepath = prd_dir / filename
|
||||
|
||||
date = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
content = f"""# Product Requirement Document: {title}
|
||||
|
||||
**Author:** {author or '[Your Name]'}
|
||||
|
||||
**Date:** {date}
|
||||
|
||||
**Status:** Draft
|
||||
|
||||
**Last Updated:** {date}
|
||||
|
||||
## Executive Summary
|
||||
|
||||
[Brief 2-3 sentence overview of what this feature is and why it matters]
|
||||
|
||||
## Problem Statement
|
||||
|
||||
### Current Situation
|
||||
|
||||
[Describe the current state and what pain points exist]
|
||||
|
||||
### User Impact
|
||||
|
||||
[Who is affected by this problem and how?]
|
||||
|
||||
### Business Impact
|
||||
|
||||
[What is the business cost of not solving this problem?]
|
||||
|
||||
## Goals and Objectives
|
||||
|
||||
### Primary Goals
|
||||
|
||||
1. [Goal 1]
|
||||
2. [Goal 2]
|
||||
3. [Goal 3]
|
||||
|
||||
### Success Metrics
|
||||
|
||||
- [Metric 1]: [Target]
|
||||
- [Metric 2]: [Target]
|
||||
- [Metric 3]: [Target]
|
||||
|
||||
### Non-Goals
|
||||
|
||||
[What is explicitly out of scope for this feature?]
|
||||
|
||||
- [Non-goal 1]
|
||||
- [Non-goal 2]
|
||||
|
||||
## User Stories
|
||||
|
||||
### Story 1: [User Type]
|
||||
|
||||
**As a** [user type]
|
||||
**I want to** [action]
|
||||
**So that** [benefit]
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] [Criterion 1]
|
||||
- [ ] [Criterion 2]
|
||||
- [ ] [Criterion 3]
|
||||
|
||||
### Story 2: [User Type]
|
||||
|
||||
**As a** [user type]
|
||||
**I want to** [action]
|
||||
**So that** [benefit]
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] [Criterion 1]
|
||||
- [ ] [Criterion 2]
|
||||
|
||||
## Requirements
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
#### Must Have (P0)
|
||||
|
||||
1. **[Requirement 1]**
|
||||
- Description: [Details]
|
||||
- User Impact: [High/Medium/Low]
|
||||
|
||||
2. **[Requirement 2]**
|
||||
- Description: [Details]
|
||||
- User Impact: [High/Medium/Low]
|
||||
|
||||
#### Should Have (P1)
|
||||
|
||||
1. **[Requirement 3]**
|
||||
- Description: [Details]
|
||||
- User Impact: [High/Medium/Low]
|
||||
|
||||
#### Nice to Have (P2)
|
||||
|
||||
1. **[Requirement 4]**
|
||||
- Description: [Details]
|
||||
- User Impact: [High/Medium/Low]
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
#### Performance
|
||||
|
||||
- [Performance requirement 1]
|
||||
- [Performance requirement 2]
|
||||
|
||||
#### Security
|
||||
|
||||
- [Security requirement 1]
|
||||
- [Security requirement 2]
|
||||
|
||||
#### Accessibility
|
||||
|
||||
- [Accessibility requirement 1]
|
||||
- [Accessibility requirement 2]
|
||||
|
||||
#### Scalability
|
||||
|
||||
- [Scalability requirement 1]
|
||||
- [Scalability requirement 2]
|
||||
|
||||
## Design Considerations
|
||||
|
||||
### User Experience
|
||||
|
||||
[Describe the intended user experience]
|
||||
|
||||
#### User Flow
|
||||
|
||||
1. [Step 1]
|
||||
2. [Step 2]
|
||||
3. [Step 3]
|
||||
|
||||
#### UI Components
|
||||
|
||||
- [Component 1]: [Description]
|
||||
- [Component 2]: [Description]
|
||||
|
||||
### Technical Architecture
|
||||
|
||||
[High-level technical approach]
|
||||
|
||||
#### Components
|
||||
|
||||
- **[Component 1]**: [Purpose and responsibilities]
|
||||
- **[Component 2]**: [Purpose and responsibilities]
|
||||
|
||||
#### Data Model
|
||||
|
||||
[Overview of data structures and relationships]
|
||||
|
||||
#### APIs
|
||||
|
||||
- **[Endpoint 1]**: [Purpose]
|
||||
- **[Endpoint 2]**: [Purpose]
|
||||
|
||||
### Integration Points
|
||||
|
||||
- [System/Service 1]: [How it integrates]
|
||||
- [System/Service 2]: [How it integrates]
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Internal Dependencies
|
||||
|
||||
- [Dependency 1]: [Why needed]
|
||||
- [Dependency 2]: [Why needed]
|
||||
|
||||
### External Dependencies
|
||||
|
||||
- [Third-party service 1]: [Purpose]
|
||||
- [Third-party service 2]: [Purpose]
|
||||
|
||||
### Blocking Issues
|
||||
|
||||
- [Issue 1]: [Resolution plan]
|
||||
- [Issue 2]: [Resolution plan]
|
||||
|
||||
## Risks and Mitigation
|
||||
|
||||
| Risk | Impact | Likelihood | Mitigation Strategy |
|
||||
|------|--------|------------|---------------------|
|
||||
| [Risk 1] | High/Medium/Low | High/Medium/Low | [Strategy] |
|
||||
| [Risk 2] | High/Medium/Low | High/Medium/Low | [Strategy] |
|
||||
|
||||
## Timeline and Milestones
|
||||
|
||||
### Phase 1: [Name] ([Duration])
|
||||
|
||||
- [ ] [Milestone 1]
|
||||
- [ ] [Milestone 2]
|
||||
|
||||
### Phase 2: [Name] ([Duration])
|
||||
|
||||
- [ ] [Milestone 3]
|
||||
- [ ] [Milestone 4]
|
||||
|
||||
### Phase 3: [Name] ([Duration])
|
||||
|
||||
- [ ] [Milestone 5]
|
||||
- [ ] [Milestone 6]
|
||||
|
||||
### Target Launch Date
|
||||
|
||||
[Date or timeframe]
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Testing
|
||||
|
||||
[Approach to unit testing]
|
||||
|
||||
### Integration Testing
|
||||
|
||||
[Approach to integration testing]
|
||||
|
||||
### User Acceptance Testing
|
||||
|
||||
[UAT plan and criteria]
|
||||
|
||||
### Performance Testing
|
||||
|
||||
[Performance testing approach]
|
||||
|
||||
## Launch Plan
|
||||
|
||||
### Pre-Launch Checklist
|
||||
|
||||
- [ ] [Item 1]
|
||||
- [ ] [Item 2]
|
||||
- [ ] [Item 3]
|
||||
|
||||
### Rollout Strategy
|
||||
|
||||
[Describe how the feature will be rolled out]
|
||||
|
||||
- **Audience**: [Who gets access first]
|
||||
- **Timeline**: [Phased rollout schedule]
|
||||
- **Monitoring**: [What metrics to watch]
|
||||
|
||||
### Communication Plan
|
||||
|
||||
- **Internal**: [How to communicate to team]
|
||||
- **External**: [How to communicate to users]
|
||||
|
||||
### Rollback Plan
|
||||
|
||||
[How to rollback if issues arise]
|
||||
|
||||
## Post-Launch
|
||||
|
||||
### Monitoring
|
||||
|
||||
- [Metric to monitor 1]
|
||||
- [Metric to monitor 2]
|
||||
|
||||
### Iteration Plan
|
||||
|
||||
[How we'll iterate based on feedback]
|
||||
|
||||
### Success Evaluation
|
||||
|
||||
[How and when we'll evaluate if we met our goals]
|
||||
|
||||
## Open Questions
|
||||
|
||||
- [ ] [Question 1]
|
||||
- [ ] [Question 2]
|
||||
- [ ] [Question 3]
|
||||
|
||||
## Stakeholders
|
||||
|
||||
| Name | Role | Responsibility |
|
||||
|------|------|----------------|
|
||||
| [Name] | [Role] | [What they're responsible for] |
|
||||
| [Name] | [Role] | [What they're responsible for] |
|
||||
|
||||
## References
|
||||
|
||||
- [Link to related PRDs]
|
||||
- [Link to design mockups]
|
||||
- [Link to technical specs]
|
||||
- [Link to user research]
|
||||
|
||||
## Appendix
|
||||
|
||||
### Terminology
|
||||
|
||||
- **[Term 1]**: [Definition]
|
||||
- **[Term 2]**: [Definition]
|
||||
|
||||
### Additional Resources
|
||||
|
||||
- [Resource 1]
|
||||
- [Resource 2]
|
||||
"""
|
||||
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"Created PRD: {filepath}")
|
||||
|
||||
return filepath
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Create a new Product Requirement Document')
|
||||
parser.add_argument('title', help='Title of the PRD')
|
||||
parser.add_argument('--dir', default='docs/PRD', help='PRD directory path')
|
||||
parser.add_argument('--author', help='Document author name')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
filepath = create_prd(args.title, args.dir, args.author or '')
|
||||
|
||||
print("\nNext steps:")
|
||||
print(f"1. Edit {filepath} to complete all sections")
|
||||
print("2. Share with stakeholders for review")
|
||||
print("3. Refine based on feedback")
|
||||
print("4. Get final approval before implementation")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
243
skills/docs-and-changelogs/scripts/generate_changelog.py
Normal file
243
skills/docs-and-changelogs/scripts/generate_changelog.py
Normal file
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate CHANGELOG.md from Conventional Commits in git history.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
COMMIT_PATTERN = re.compile(
|
||||
r'^(?P<type>\w+)(?:\((?P<scope>[\w-]+)\))?(?P<breaking>!)?: (?P<description>.+)$'
|
||||
)
|
||||
|
||||
TYPE_HEADERS = {
|
||||
'feat': 'Added',
|
||||
'fix': 'Fixed',
|
||||
'docs': 'Documentation',
|
||||
'style': 'Style',
|
||||
'refactor': 'Changed',
|
||||
'perf': 'Performance',
|
||||
'test': 'Tests',
|
||||
'chore': 'Maintenance',
|
||||
'ci': 'CI/CD',
|
||||
'build': 'Build',
|
||||
'revert': 'Reverted',
|
||||
}
|
||||
|
||||
|
||||
def get_commits(since=None, until='HEAD'):
|
||||
"""Get git commits in range."""
|
||||
cmd = ['git', 'log', '--pretty=format:%H|%s|%b|%an|%ae|%ad', '--date=short']
|
||||
|
||||
if since:
|
||||
cmd.append(f'{since}..{until}')
|
||||
else:
|
||||
cmd.append(until)
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
commits = []
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split('|')
|
||||
if len(parts) >= 6:
|
||||
commits.append({
|
||||
'hash': parts[0],
|
||||
'subject': parts[1],
|
||||
'body': parts[2],
|
||||
'author': parts[3],
|
||||
'email': parts[4],
|
||||
'date': parts[5],
|
||||
})
|
||||
|
||||
return commits
|
||||
|
||||
|
||||
def parse_commit(commit):
|
||||
"""Parse conventional commit message."""
|
||||
match = COMMIT_PATTERN.match(commit['subject'])
|
||||
|
||||
if not match:
|
||||
return None
|
||||
|
||||
parsed = {
|
||||
'type': match.group('type'),
|
||||
'scope': match.group('scope'),
|
||||
'breaking': bool(match.group('breaking')),
|
||||
'description': match.group('description'),
|
||||
'hash': commit['hash'][:7],
|
||||
'full_hash': commit['hash'],
|
||||
'body': commit['body'],
|
||||
}
|
||||
|
||||
# Check for BREAKING CHANGE in body
|
||||
if 'BREAKING CHANGE' in commit['body']:
|
||||
parsed['breaking'] = True
|
||||
# Extract breaking change description
|
||||
breaking_match = re.search(r'BREAKING CHANGE:\s*(.+)', commit['body'])
|
||||
if breaking_match:
|
||||
parsed['breaking_description'] = breaking_match.group(1)
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def group_commits(commits):
|
||||
"""Group commits by type and breaking changes."""
|
||||
groups = defaultdict(list)
|
||||
breaking = []
|
||||
|
||||
for commit in commits:
|
||||
parsed = parse_commit(commit)
|
||||
if not parsed:
|
||||
continue
|
||||
|
||||
if parsed['breaking']:
|
||||
breaking.append(parsed)
|
||||
|
||||
commit_type = parsed['type']
|
||||
groups[commit_type].append(parsed)
|
||||
|
||||
return groups, breaking
|
||||
|
||||
|
||||
def format_commit(commit):
|
||||
"""Format a single commit for changelog."""
|
||||
scope = f"**{commit['scope']}**: " if commit['scope'] else ""
|
||||
return f"- {scope}{commit['description']} ([{commit['hash']}](../../commit/{commit['full_hash']}))"
|
||||
|
||||
|
||||
def generate_changelog_section(version, date, groups, breaking):
|
||||
"""Generate a changelog section for a version."""
|
||||
lines = [
|
||||
f"## [{version}] - {date}",
|
||||
""
|
||||
]
|
||||
|
||||
# Breaking changes first
|
||||
if breaking:
|
||||
lines.append("### BREAKING CHANGES")
|
||||
lines.append("")
|
||||
for commit in breaking:
|
||||
if 'breaking_description' in commit:
|
||||
lines.append(f"- {commit['breaking_description']}")
|
||||
else:
|
||||
lines.append(format_commit(commit))
|
||||
lines.append("")
|
||||
|
||||
# Regular changes by type
|
||||
for commit_type, header in TYPE_HEADERS.items():
|
||||
if commit_type in groups and groups[commit_type]:
|
||||
lines.append(f"### {header}")
|
||||
lines.append("")
|
||||
for commit in groups[commit_type]:
|
||||
lines.append(format_commit(commit))
|
||||
lines.append("")
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def get_current_version():
|
||||
"""Get current version from package.json."""
|
||||
try:
|
||||
import json
|
||||
with open('package.json') as f:
|
||||
data = json.load(f)
|
||||
return data.get('version', '0.0.0')
|
||||
except:
|
||||
return '0.0.0'
|
||||
|
||||
|
||||
def get_last_tag():
|
||||
"""Get the most recent git tag."""
|
||||
result = subprocess.run(
|
||||
['git', 'describe', '--tags', '--abbrev=0'],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
return None
|
||||
|
||||
|
||||
def update_changelog(content, output_path):
|
||||
"""Update or create CHANGELOG.md file."""
|
||||
changelog_path = Path(output_path)
|
||||
|
||||
if changelog_path.exists():
|
||||
with open(changelog_path) as f:
|
||||
existing = f.read()
|
||||
|
||||
# Insert new content after header
|
||||
if '## [' in existing:
|
||||
parts = existing.split('## [', 1)
|
||||
updated = parts[0] + content + '\n## [' + parts[1]
|
||||
else:
|
||||
updated = existing + '\n\n' + content
|
||||
else:
|
||||
# Create new changelog with 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).
|
||||
|
||||
"""
|
||||
updated = header + content
|
||||
|
||||
with open(changelog_path, 'w') as f:
|
||||
f.write(updated)
|
||||
|
||||
print(f"Updated: {changelog_path}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Generate changelog from git commits')
|
||||
parser.add_argument('--since', help='Start from this tag/commit')
|
||||
parser.add_argument('--until', default='HEAD', help='End at this tag/commit')
|
||||
parser.add_argument('--version', help='Version number for this release')
|
||||
parser.add_argument('--output', default='CHANGELOG.md', help='Output file path')
|
||||
parser.add_argument('--date', help='Release date (YYYY-MM-DD)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Determine version and since
|
||||
version = args.version or get_current_version()
|
||||
since = args.since or get_last_tag()
|
||||
|
||||
if not since:
|
||||
print("Warning: No previous tag found. Generating changelog for all commits.")
|
||||
|
||||
# Get and parse commits
|
||||
commits = get_commits(since=since, until=args.until)
|
||||
|
||||
if not commits:
|
||||
print("No commits found in range.")
|
||||
return
|
||||
|
||||
groups, breaking = group_commits(commits)
|
||||
|
||||
# Generate changelog section
|
||||
date = args.date or datetime.now().strftime('%Y-%m-%d')
|
||||
changelog_content = generate_changelog_section(version, date, groups, breaking)
|
||||
|
||||
# Update changelog file
|
||||
update_changelog(changelog_content, args.output)
|
||||
|
||||
# Print summary
|
||||
print(f"\nGenerated changelog for version {version}")
|
||||
print(f" Commits processed: {len(commits)}")
|
||||
print(f" Breaking changes: {len(breaking)}")
|
||||
print(f" Features: {len(groups.get('feat', []))}")
|
||||
print(f" Bug fixes: {len(groups.get('fix', []))}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user