From c4c4fd90158f2ebe9f5e3146fdc2b339f23620a9 Mon Sep 17 00:00:00 2001 From: lukemun Date: Fri, 15 Aug 2025 16:25:15 -0400 Subject: [PATCH 1/5] docs: remove legacy migration files and streamline README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit β€’ Remove outdated EXTRACTION_SUMMARY.md documentation β€’ Delete MIGRATION_GUIDE.md that was specific to early versions β€’ Clean up README.md by removing duplicate setup examples β€’ Remove migration-example.yml that's no longer relevant πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- EXTRACTION_SUMMARY.md | 334 --------------------------------- MIGRATION_GUIDE.md | 304 ------------------------------ README.md | 231 ++++++----------------- examples/migration-example.yml | 155 --------------- 4 files changed, 54 insertions(+), 970 deletions(-) delete mode 100644 EXTRACTION_SUMMARY.md delete mode 100644 MIGRATION_GUIDE.md delete mode 100644 examples/migration-example.yml diff --git a/EXTRACTION_SUMMARY.md b/EXTRACTION_SUMMARY.md deleted file mode 100644 index 6ae4655..0000000 --- a/EXTRACTION_SUMMARY.md +++ /dev/null @@ -1,334 +0,0 @@ -# GitHub Action Extraction Summary - -## 🎯 What Was Extracted - -This standalone GitHub Action was extracted from the TripSnag monorepo's complex changelog automation workflow. Here's what was transformed: - -### Original Workflow Complexity - -- **File**: `.github/workflows/update-changelog.yml` -- **Size**: 854 lines of complex YAML and embedded JavaScript -- **Functionality**: AI-powered changelog generation with Claude API -- **Scope**: Single repository, tightly coupled to TripSnag structure - -### Extracted Action Benefits - -- **Reusable**: Can be used in any repository -- **Maintainable**: Clear separation of concerns -- **Testable**: Dedicated CI/CD pipeline -- **Documented**: Comprehensive usage guides -- **Configurable**: Flexible input parameters - -## πŸ“ Project Structure - -``` -context-ledger/ -β”œβ”€β”€ action.yml # GitHub Action definition -β”œβ”€β”€ lib/ -β”‚ └── generate-changelog.js # Core changelog generation logic -β”œβ”€β”€ package.json # Node.js dependencies -β”œβ”€β”€ README.md # Main documentation -β”œβ”€β”€ USAGE.md # Detailed usage examples -β”œβ”€β”€ MIGRATION_GUIDE.md # Migration instructions -β”œβ”€β”€ CHANGELOG.md # Project changelog -β”œβ”€β”€ LICENSE # MIT License -β”œβ”€β”€ .gitignore # Git ignore rules -β”œβ”€β”€ .github/ -β”‚ β”œβ”€β”€ workflows/ -β”‚ β”‚ └── test.yml # CI/CD pipeline -β”‚ β”œβ”€β”€ ISSUE_TEMPLATE/ -β”‚ β”‚ β”œβ”€β”€ bug_report.md # Bug report template -β”‚ β”‚ └── feature_request.md # Feature request template -β”‚ β”œβ”€β”€ pull_request_template.md # PR template -β”‚ └── dependabot.yml # Dependency updates -└── examples/ - └── migration-example.yml # Migration example -``` - -## πŸ”§ Core Components Extracted - -### 1. Action Definition (`action.yml`) - -- **Inputs**: 11 configurable parameters -- **Outputs**: 5 result variables -- **Runs**: Composite action using bash and Node.js -- **Features**: Loop prevention, AI generation, GitHub integration - -### 2. Core Logic (`lib/generate-changelog.js`) - -- **Functions**: 8 modular functions for different aspects -- **Features**: - - Commit parsing and categorization - - Semantic versioning logic - - Claude AI integration - - Git operations - - Error handling - -### 3. CI/CD Pipeline (`.github/workflows/test.yml`) - -- **Jobs**: 3 different test scenarios -- **Tests**: Syntax validation, integration testing, linting -- **Triggers**: Push, PR, and manual dispatch - -## πŸš€ Key Features - -### Smart Loop Prevention - -```yaml -- name: Check for suggestion commits - # Prevents infinite loops from GitHub suggestions - # Detects changelog-only commits - # Skips when appropriate -``` - -### AI-Powered Analysis - -```javascript -// Categorizes commits using conventional commit patterns -// Determines semantic version increments -// Generates meaningful changelog entries -// Uses Claude API for natural language processing -``` - -### GitHub Integration - -```yaml -- name: Create GitHub PR suggestions - # Creates one-click apply suggestions - # Handles diff positioning - # Works with new and modified files -``` - -### Semantic Versioning - -```javascript -// Automatically determines version increments: -// Breaking changes β†’ major (1.0.0 β†’ 2.0.0) -// New features β†’ minor (1.0.0 β†’ 1.1.0) -// Bug fixes β†’ patch (1.0.0 β†’ 1.0.1) -``` - -## πŸ“Š Migration Benefits - -| Aspect | Before | After | -| ------------------- | ----------- | --------------- | -| **Workflow Size** | 854 lines | ~100 lines | -| **Maintainability** | Single repo | Reusable action | -| **Testing** | Manual | Automated CI/CD | -| **Documentation** | Minimal | Comprehensive | -| **Error Handling** | Basic | Robust | -| **Customization** | Hard-coded | Configurable | -| **Updates** | Manual | Dependabot | - -## πŸ› οΈ Usage Examples - -### Basic Usage - -```yaml -- name: Generate Changelog - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} -``` - -### Advanced Configuration - -```yaml -- name: Generate Changelog - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: "docs/CHANGES.md" - target_name: "api-service" - version_increment: "minor" - auto_commit: true -``` - -### Monorepo Usage - -```yaml -strategy: - matrix: - project: - - { name: "frontend", path: "packages/frontend/CHANGELOG.md" } - - { name: "backend", path: "packages/backend/CHANGELOG.md" } - -steps: - - name: Generate Changelog for ${{ matrix.project.name }} - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: ${{ matrix.project.path }} - target_name: ${{ matrix.project.name }} -``` - -## πŸ”’ Security Features - -### API Key Protection - -- Stored in GitHub Secrets -- Never logged or exposed -- Supports organization-level secrets - -### Minimal Permissions - -```yaml -permissions: - contents: write # Read/write changelog files - pull-requests: write # Create suggestions -``` - -### Input Validation - -- Validates all input parameters -- Sanitizes file paths -- Prevents injection attacks - -## πŸ“ˆ Publishing Options - -### GitHub Marketplace - -1. Create public repository -2. Add proper `action.yml` metadata -3. Create release with tag -4. Submit to marketplace - -### Private Distribution - -1. Create private repository -2. Use in workflows via: - ```yaml - uses: organization/context-ledger@v1 - ``` - -### Fork and Customize - -1. Fork this repository -2. Customize for your needs -3. Use your fork in workflows - -## πŸ”§ Customization Points - -### Prompt Engineering - -Modify `lib/generate-changelog.js` to adjust: - -- AI prompt structure -- Domain-specific terminology -- Output formatting -- Analysis depth - -### Commit Categorization - -Customize commit analysis: - -- Conventional commit patterns -- Category mappings -- Version increment rules -- Breaking change detection - -### GitHub Integration - -Adjust suggestion behavior: - -- Diff positioning logic -- Comment formatting -- Review creation -- Error handling - -## πŸ§ͺ Testing Strategy - -### Local Development - -```bash -# Install dependencies -npm install - -# Test syntax -node -c lib/generate-changelog.js - -# Local testing with act -act pull_request -s ANTHROPIC_API_KEY=test_key -``` - -### Integration Testing - -1. Create test repository -2. Configure action workflow -3. Create test PRs -4. Verify changelog generation - -### CI/CD Pipeline - -- Automatic testing on push/PR -- Syntax validation -- Integration tests -- Dependency security checks - -## πŸ“š Documentation Structure - -### User-Facing - -- **README.md**: Overview and quick start -- **USAGE.md**: Detailed examples and configuration -- **examples/**: Real-world workflow examples - -### Developer-Facing - -- **MIGRATION_GUIDE.md**: How to extract and customize -- **EXTRACTION_SUMMARY.md**: This document -- **CHANGELOG.md**: Version history - -### Community - -- **Issue templates**: Bug reports and feature requests -- **PR template**: Contribution guidelines -- **LICENSE**: MIT license for open source use - -## 🎯 Next Steps - -### For Original Repository (TripSnag) - -1. Replace existing workflow with action usage -2. Test with a sample PR -3. Monitor for any regressions -4. Enjoy simplified maintenance - -### For Action Repository - -1. Publish to GitHub (public or private) -2. Set up Dependabot for security updates -3. Add integration tests -4. Consider contributing back improvements - -### For Other Users - -1. Fork or use the published action -2. Customize for your domain -3. Create your own workflows -4. Share improvements with community - -## πŸ’‘ Innovation Opportunities - -### Enhanced AI Features - -- Multi-model support (GPT, Gemini) -- Custom training data -- Domain-specific prompts -- Automated testing suggestions - -### Advanced Integrations - -- Jira ticket linking -- Slack notifications -- Release automation -- Documentation updates - -### Community Features - -- Shared prompt library -- Best practices database -- Template marketplace -- Plugin ecosystem - -This extraction transforms a complex, single-use workflow into a powerful, reusable tool that can benefit developers across the entire GitHub ecosystem! diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md deleted file mode 100644 index 0dbf81f..0000000 --- a/MIGRATION_GUIDE.md +++ /dev/null @@ -1,304 +0,0 @@ -# Migration Guide: From Inline Workflow to Standalone Action - -This guide helps you extract your existing GitHub Actions workflow into this standalone, reusable action. - -## πŸ“Š Before vs After Comparison - -| Aspect | Before (Inline Workflow) | After (Standalone Action) | -| ------------------- | ------------------------ | ------------------------- | -| **Lines of Code** | ~850 lines | ~100 lines | -| **Maintainability** | Complex, single-repo | Simple, reusable | -| **Testing** | Manual, in-production | Automated CI/CD | -| **Updates** | Manual copy-paste | Automated via Dependabot | -| **Error Handling** | Basic | Comprehensive | -| **Documentation** | Minimal | Extensive | -| **Reusability** | Single repository | Multiple repositories | - -## πŸš€ Migration Process - -### Step 1: Extract Your Current Workflow - -Your existing workflow likely contains several key components: - -1. **Loop Prevention Logic** - Detecting suggestion commits -2. **Change Analysis** - Extracting PR commits and file changes -3. **Claude AI Integration** - API calls and prompt engineering -4. **GitHub Suggestions** - Creating PR review suggestions -5. **Version Management** - Semantic versioning logic - -### Step 2: Create the Standalone Action Repository - -1. **Create a new repository** for your action: - - ```bash - git clone https://github.com/lukemun/context-ledger.git - cd context-ledger - ``` - -2. **Copy the extracted structure** from this directory to your new repo: - ``` - context-ledger/ - β”œβ”€β”€ action.yml # Action definition - β”œβ”€β”€ lib/generate-changelog.js # Core logic - β”œβ”€β”€ package.json # Dependencies - β”œβ”€β”€ README.md # Documentation - β”œβ”€β”€ USAGE.md # Usage examples - β”œβ”€β”€ LICENSE # MIT License - β”œβ”€β”€ .github/workflows/test.yml # CI/CD - └── examples/ # Example workflows - ``` - -### Step 3: Customize for Your Needs - -1. **Update action.yml**: - - - Change author information - - Adjust input defaults - - Modify branding - -2. **Customize generate-changelog.js**: - - - Adjust prompt engineering for your domain - - Modify commit categorization logic - - Update version increment rules - -3. **Update documentation**: - - Replace placeholder URLs with your repository - - Add specific examples for your use case - - Document any custom configurations - -### Step 4: Publish Your Action - -1. **Tag and release**: - - ```bash - git tag v1.0.0 - git push origin v1.0.0 - ``` - -2. **Publish to GitHub Marketplace** (optional): - - Go to your repository on GitHub - - Click "Releases" β†’ "Create a new release" - - Fill in release details - - Check "Publish this Action to the GitHub Marketplace" - -### Step 5: Update Your Original Repository - -Replace your existing workflow with a simplified version: - -```yaml -name: Update Changelog - -on: - pull_request: - branches: [main] - types: [opened, synchronize, reopened, ready_for_review] - paths-ignore: - - "**/CHANGELOG.md" - -permissions: - contents: write - pull-requests: write - -jobs: - update-changelog: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - fetch-depth: 0 - - - name: Generate Changelog - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: "CHANGELOG.md" - target_name: "project" -``` - -## πŸ”§ Customization Examples - -### For Monorepos - -Create a matrix strategy to handle multiple changelogs: - -```yaml -strategy: - matrix: - project: - - { name: "frontend", path: "packages/frontend/CHANGELOG.md" } - - { name: "backend", path: "packages/backend/CHANGELOG.md" } - -steps: - - name: Generate Changelog for ${{ matrix.project.name }} - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: ${{ matrix.project.path }} - target_name: ${{ matrix.project.name }} -``` - -### For Different Environments - -Handle different changelog files based on target branch: - -```yaml -- name: Determine changelog path - id: changelog-path - run: | - if [ "${{ github.base_ref }}" = "main" ]; then - echo "path=CHANGELOG.md" >> $GITHUB_OUTPUT - echo "target=production" >> $GITHUB_OUTPUT - else - echo "path=CHANGELOG-DEV.md" >> $GITHUB_OUTPUT - echo "target=development" >> $GITHUB_OUTPUT - fi - -- name: Generate Changelog - uses: yourusername/claude-changelog-action@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: ${{ steps.changelog-path.outputs.path }} - target_name: ${{ steps.changelog-path.outputs.target }} -``` - -## πŸ§ͺ Testing Your Action - -### Local Testing with Act - -```bash -# Install act -brew install act - -# Test pull request trigger -act pull_request \ - -s ANTHROPIC_API_KEY=your_test_key \ - -e test-event.json - -# Test with custom payload -echo '{"pull_request":{"head":{"ref":"feature-branch"},"base":{"ref":"main"}}}' > test-event.json -act pull_request -e test-event.json -``` - -### Integration Testing - -1. Create a test repository -2. Add your action as a workflow -3. Create a test PR with meaningful commits -4. Verify the changelog generation works correctly - -### Unit Testing (Future Enhancement) - -Consider adding Jest or similar for testing individual functions: - -```bash -npm install --save-dev jest -# Add tests for commit categorization, version logic, etc. -``` - -## πŸ”’ Security Considerations - -### API Key Management - -1. **Repository Secrets**: Store in GitHub repository secrets -2. **Organization Secrets**: Share across multiple repos -3. **Key Rotation**: Regularly rotate your Anthropic API keys -4. **Least Privilege**: Use minimal required permissions - -### Permissions - -The action requires these permissions: - -```yaml -permissions: - contents: write # To read/write changelog files - pull-requests: write # To create suggestions -``` - -### Dependencies - -Keep dependencies up to date: - -```yaml -# .github/dependabot.yml -version: 2 -updates: - - package-ecosystem: "npm" - directory: "/" - schedule: - interval: "weekly" -``` - -## πŸ“ˆ Maintenance and Updates - -### Versioning Strategy - -Use semantic versioning for your action: - -- **v1.0.0**: Initial release -- **v1.1.0**: New features (backward compatible) -- **v1.0.1**: Bug fixes -- **v2.0.0**: Breaking changes - -### Update Process - -1. **Make changes** in a feature branch -2. **Test thoroughly** with integration tests -3. **Update documentation** and examples -4. **Create release** with appropriate version tag -5. **Notify users** of breaking changes - -### Support Multiple Versions - -Maintain multiple major versions: - -``` -v1.2.3 -> v1 (auto-updates to latest v1.x) -v2.1.0 -> v2 (auto-updates to latest v2.x) -``` - -## 🎯 Best Practices - -### Action Design - -1. **Single Responsibility**: Focus on changelog generation only -2. **Configurable**: Make behavior configurable via inputs -3. **Defensive**: Handle errors gracefully -4. **Documented**: Provide comprehensive documentation - -### Workflow Design - -1. **Minimal Permissions**: Only request what you need -2. **Error Handling**: Use `continue-on-error` where appropriate -3. **Conditional Logic**: Skip unnecessary runs -4. **Clear Outputs**: Provide useful outputs for chaining - -### Community - -1. **Open Source**: Consider making your action open source -2. **Examples**: Provide real-world usage examples -3. **Support**: Respond to issues and feature requests -4. **Documentation**: Keep documentation up to date - -## πŸ”— Resources - -- [GitHub Actions Documentation](https://docs.github.com/en/actions) -- [Creating Actions](https://docs.github.com/en/actions/creating-actions) -- [Action Marketplace](https://github.com/marketplace?type=actions) -- [Anthropic API Documentation](https://docs.anthropic.com/) -- [Semantic Versioning](https://semver.org/) - -## 🀝 Contributing Back - -If you create improvements to this action: - -1. **Fork** the original repository -2. **Create** a feature branch -3. **Test** your changes thoroughly -4. **Submit** a pull request with clear description -5. **Maintain** backward compatibility when possible - -This migration transforms a complex, single-use workflow into a maintainable, reusable GitHub Action that can benefit the entire community! diff --git a/README.md b/README.md index d9373a4..5051cbd 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,58 @@ A GitHub Action that maintains a source of truth for LLM context across your cod > **Installation**: Use `lukemun/context-ledger@v1` in your workflows. For the latest features, use `@main`. +## πŸ› οΈ Quick Setup + +- **Add secret**: In GitHub β†’ Settings β†’ Secrets and variables β†’ Actions β†’ New repository secret + + - Name: `ANTHROPIC_API_KEY` + - Value: your Anthropic API key + +- **Add workflow**: Create `.github/workflows/changelog.yml` + +```yaml +name: Update Changelog + +on: + pull_request: + branches: [main] + types: [opened, synchronize, reopened, ready_for_review] + paths-ignore: + - "**/CHANGELOG.md" + - "CHANGELOG.md" + +permissions: + contents: write + pull-requests: write + +jobs: + update-changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Generate Changelog + uses: lukemun/context-ledger@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + # Optional: changelog_path, target_name, commit_range, version_increment, create_pr_suggestions, auto_commit +``` + +- **Create changelog**: Add `CHANGELOG.md` to your repo root + +```markdown +# Changelog + +## [Unreleased] + + +``` + +- **Open a PR**: The action analyzes your changes and suggests entries for `CHANGELOG.md`. + ## ✨ Features - πŸ€– **AI-Powered Analysis**: Uses Claude AI to understand commit patterns and generate meaningful changelog entries @@ -27,7 +79,7 @@ A GitHub Action that maintains a source of truth for LLM context across your cod - **Faster onboarding for new engineers and contractors (founder benefit)**: Give an LLM the precise, up‑to‑date context to answer β€œhow does this work?” based on real, recent changes. Reduce ramp‑up time without long knowledge dumps. - **Sales enablement with up‑to‑date product information**: Keep customer‑facing docs, release summaries, and collateral aligned with what actually shipped so sales can speak confidently and accurately. -## πŸš€ Quick Start +## 🧩 In-Depth Setup ### Simple Setup (single project) @@ -196,42 +248,6 @@ Create a new pull request and watch Context Ledger analyze your changes and sugg - **Permissions**: Make sure your repository allows Actions to write to PRs (enabled by default) - **Customize target options**: Update the `target_changelog` options in `workflow_dispatch` to match your project structure (e.g., service names in a monorepo) -### Basic Usage (Alternative) - -```yaml -name: Update Changelog - -on: - pull_request: - branches: [main] - types: [opened, synchronize, reopened, ready_for_review] - paths-ignore: - - "**/CHANGELOG.md" - - "CHANGELOG.md" - -jobs: - update-changelog: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Generate Changelog - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: "CHANGELOG.md" - target_name: "project" -``` - ### Required Setup 1. **Get an Anthropic API Key**: @@ -241,6 +257,7 @@ jobs: - Add it to your repository secrets as `ANTHROPIC_API_KEY` 2. **Configure Repository Permissions**: + - Ensure your workflow has `contents: write` and `pull-requests: write` permissions - For private repositories, you may need to adjust branch protection rules @@ -347,143 +364,3 @@ jobs: version_increment: ${{ github.event.inputs.version_increment || 'auto' }} auto_commit: true ``` - -### Custom Configuration - -```yaml -- name: Generate Changelog with Custom Settings - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: "docs/CHANGES.md" - target_name: "api-service" - commit_range: "20" - version_increment: "minor" - base_branch: "develop" - skip_if_no_changes: false - create_pr_suggestions: true -``` - -## 🧠 How It Works - -1. **Trigger Detection**: Runs on PR events, releases, or manual dispatch -2. **Loop Prevention**: Checks for suggestion commits and changelog-only changes -3. **Change Analysis**: Extracts PR commits, changed files, and git diffs -4. **AI Processing**: Claude AI analyzes changes and generates categorized changelog entries -5. **Version Management**: Automatically determines semantic version increments -6. **GitHub Integration**: Creates suggestions for one-click application in PRs - -### Commit Analysis - -The action intelligently categorizes commits based on conventional commit patterns: - -- **feat:** β†’ Added section, minor version increment -- **fix:** β†’ Fixed section, patch version increment -- **docs:** β†’ Changed section, patch version increment -- **BREAKING:** β†’ Major version increment -- **chore/style/refactor/test:** β†’ Technical Details section, patch increment - -### Version Strategy - -| Commit Types | Version Increment | -| ----------------------- | --------------------- | -| Breaking changes | Major (1.0.0 β†’ 2.0.0) | -| New features (feat:) | Minor (1.0.0 β†’ 1.1.0) | -| Bug fixes, docs, chores | Patch (1.0.0 β†’ 1.0.1) | - -## πŸ”§ Development - -### Project Structure - -``` -claude-changelog-action/ -β”œβ”€β”€ action.yml # Action definition -β”œβ”€β”€ lib/ -β”‚ └── generate-changelog.js # Core logic -β”œβ”€β”€ package.json # Dependencies -β”œβ”€β”€ README.md # Documentation -β”œβ”€β”€ LICENSE # MIT License -└── .github/ - └── workflows/ - └── test.yml # CI/CD pipeline -``` - -### Contributing - -1. Fork the repository -2. Create a feature branch: `git checkout -b feature/amazing-feature` -3. Make your changes and test thoroughly -4. Commit using conventional commits: `git commit -m 'feat: add amazing feature'` -5. Push to the branch: `git push origin feature/amazing-feature` -6. Open a Pull Request - -### Testing - -```bash -# Install dependencies -npm install - -# Run tests (when implemented) -npm test - -# Test locally with act -act pull_request -s ANTHROPIC_API_KEY=your_test_key -``` - -## πŸ§ͺ Testing & Development - -### Dual Workflow Approach - -Context Ledger provides two workflows for maximum flexibility: - -1. **Production Workflow** (`changelog.yml`) - Uses the published version (`@v1`) - - Stable, tested version - - What your users will experience - - Runs automatically on PRs and releases - -2. **Local Workflow** (`changelog-local.yml`) - Uses the PR's code (`./`) - - Test changes before merging - - Verify fixes work as expected - - Same functionality, different source - -### Release Process - -When ready to release a new version: - -```bash -# 1. Ensure CHANGELOG.md has the new version -# 2. Merge your PR to main -# 3. Run the release script -./scripts/release.sh -``` - -This will: -- Create a new version tag (e.g., `v1.0.19`) -- Update the floating major tag (e.g., `v1`) -- Push both tags to GitHub - -## πŸ›‘οΈ Security - -- **API Key Security**: Store your Anthropic API key in GitHub Secrets, never in code -- **Permissions**: Use minimal required permissions (`contents: write`, `pull-requests: write`) -- **Token Scope**: Action uses the provided GitHub token with repository scope only - -## πŸ“œ License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - -## 🀝 Support - -- πŸ“– [Documentation](https://github.com/lukemun/context-ledger) -- πŸ› [Report Issues](https://github.com/lukemun/context-ledger/issues) -- πŸ’¬ [Discussions](https://github.com/lukemun/context-ledger/discussions) - -## πŸ™ Acknowledgments - -- [Anthropic](https://anthropic.com) for the powerful Claude AI API -- [GitHub Actions](https://github.com/features/actions) for the automation platform -- The open source community for inspiration and feedback - ---- - -**Made with ❀️ by [Luke Munro](https://github.com/lukemun)** diff --git a/examples/migration-example.yml b/examples/migration-example.yml deleted file mode 100644 index 1b95100..0000000 --- a/examples/migration-example.yml +++ /dev/null @@ -1,155 +0,0 @@ -# Migration Example: Converting from inline workflow to the action -# -# BEFORE: Your existing .github/workflows/update-changelog.yml -# AFTER: This simplified version using the action - -name: Update Changelog with Claude - -on: - # Same triggers as your original workflow - pull_request: - branches: - - main - types: [opened, synchronize, reopened, ready_for_review] - paths-ignore: - - "docs/**" - - "**/CHANGELOG.md" - - "CHANGELOG.md" - - release: - types: [published] - - workflow_dispatch: - inputs: - target_changelog: - description: "Target changelog to update" - required: false - default: "project-wide" - type: choice - options: - - "project-wide" - - "decipher" - - "gf-crawler" - - "nextjs" - commit_range: - description: "Number of recent commits to analyze (default: 10)" - required: false - default: "10" - version_increment: - description: "Version increment type" - required: false - default: "auto" - type: choice - options: - - "auto" - - "patch" - - "minor" - - "major" - -permissions: - contents: write - pull-requests: write - issues: write - -jobs: - # Single job instead of complex multi-step workflow - update-changelog: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - # Determine which changelog to update (same logic as before) - - name: Determine target changelog - id: determine-target - run: | - TARGET="${{ github.event.inputs.target_changelog || 'project-wide' }}" - - case "$TARGET" in - "decipher") - CHANGELOG_PATH="decipher/documentation/CHANGELOG.md" - ;; - "gf-crawler") - CHANGELOG_PATH="gf-crawler/CHANGELOG.md" - ;; - "nextjs") - CHANGELOG_PATH="nextjs/CHANGELOG.md" - ;; - "project-wide") - CHANGELOG_PATH="CHANGELOG.md" - ;; - *) - CHANGELOG_PATH="CHANGELOG.md" - ;; - esac - - echo "changelog_path=$CHANGELOG_PATH" >> $GITHUB_OUTPUT - echo "target=$TARGET" >> $GITHUB_OUTPUT - - # This replaces ~500 lines of complex workflow logic! - - name: Generate Changelog with Claude - id: changelog - uses: lukemun/context-ledger@v1 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - changelog_path: ${{ steps.determine-target.outputs.changelog_path }} - target_name: ${{ steps.determine-target.outputs.target }} - commit_range: ${{ github.event.inputs.commit_range || '10' }} - version_increment: ${{ github.event.inputs.version_increment || 'auto' }} - # For non-PR events, auto-commit the changes - auto_commit: ${{ github.event_name != 'pull_request' }} - - # Optional: Create summary (replaces the complex summary logic) - - name: Create summary - if: always() - run: | - echo "## Changelog Update Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - STATUS="${{ steps.changelog.outputs.status }}" - TARGET="${{ steps.determine-target.outputs.target }}" - CHANGELOG_PATH="${{ steps.determine-target.outputs.changelog_path }}" - - case "$STATUS" in - "UPDATED") - if [ "${{ steps.changelog.outputs.has_changes }}" = "true" ]; then - echo "βœ… **Changelog updated successfully**" >> $GITHUB_STEP_SUMMARY - echo "- Target: \`$TARGET\`" >> $GITHUB_STEP_SUMMARY - echo "- File: \`$CHANGELOG_PATH\`" >> $GITHUB_STEP_SUMMARY - echo "- Version: \`${{ steps.changelog.outputs.version_generated }}\`" >> $GITHUB_STEP_SUMMARY - else - echo "ℹ️ **No changes detected in changelog**" >> $GITHUB_STEP_SUMMARY - fi - ;; - "NO_UPDATE_NEEDED"|"SKIPPED") - echo "ℹ️ **No changelog update needed**" >> $GITHUB_STEP_SUMMARY - echo "- Claude determined recent changes don't warrant changelog entry" >> $GITHUB_STEP_SUMMARY - ;; - "ERROR") - echo "❌ **Error updating changelog**" >> $GITHUB_STEP_SUMMARY - echo "- Check the workflow logs for details" >> $GITHUB_STEP_SUMMARY - ;; - esac - -# Benefits of this migration: -# -# 1. βœ… Reduced from ~850 lines to ~100 lines -# 2. βœ… All complex logic moved to reusable action -# 3. βœ… Same functionality with better error handling -# 4. βœ… Easier to maintain and debug -# 5. βœ… Can be used across multiple repositories -# 6. βœ… Regular updates via Dependabot -# 7. βœ… Better testing and validation -# 8. βœ… Cleaner, more readable workflow -# -# Migration steps: -# 1. Add ANTHROPIC_API_KEY to repository secrets -# 2. Replace your existing workflow with this one -# 3. Update the action reference to: lukemun/context-ledger@v1 -# 4. Test with a sample PR -# 5. Customize inputs as needed for your use case From 1f93125998ceb4f81b217a5b8add554880f26f91 Mon Sep 17 00:00:00 2001 From: lukemun Date: Fri, 15 Aug 2025 16:42:23 -0400 Subject: [PATCH 2/5] fix action --- CHANGELOG.md | 2 - README.md | 161 +++++++++++++++++++++++++++++++++++++- action.yml | 81 +++++++------------ lib/generate-changelog.js | 62 ++++++--------- 4 files changed, 213 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8835178..dfa7272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,5 +36,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Supports conventional commit message parsing - Includes comprehensive error handling and logging - Provides detailed outputs for integration with other workflows - - diff --git a/README.md b/README.md index 5051cbd..58035c8 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ jobs: ```markdown # Changelog -## [Unreleased] +All notable changes to this project will be documented in this file. - +## [Unreleased] ``` - **Open a PR**: The action analyzes your changes and suggests entries for `CHANGELOG.md`. @@ -209,8 +209,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - - +### Added + +- Initial features and functionality ``` #### Step 3: Get Anthropic API Key @@ -364,3 +365,155 @@ jobs: version_increment: ${{ github.event.inputs.version_increment || 'auto' }} auto_commit: true ``` + +### Custom Configuration + +```yaml +- name: Generate Changelog with Custom Settings + uses: lukemun/context-ledger@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + changelog_path: "docs/CHANGES.md" + target_name: "api-service" + commit_range: "20" + version_increment: "minor" + base_branch: "develop" + skip_if_no_changes: false + create_pr_suggestions: true +``` + +## 🧠 How It Works + +1. **Trigger Detection**: Runs on PR events, releases, or manual dispatch +2. **Loop Prevention**: Checks for suggestion commits and changelog-only changes +3. **Change Analysis**: Extracts PR commits, changed files, and git diffs +4. **AI Processing**: Claude AI analyzes changes and generates categorized changelog entries +5. **Version Management**: Automatically determines semantic version increments +6. **Changelog Updates**: Simply appends new entries to the end of your changelog file +7. **GitHub Integration**: Creates suggestions for one-click application in PRs + +### Changelog Generation + +The action uses a clean, marker-free approach: + +- Reads your existing changelog content +- Generates new entries based on PR changes +- Appends the new content to the end of the file +- No HTML comments or markers needed - just clean markdown + +### Commit Analysis + +The action intelligently categorizes commits based on conventional commit patterns: + +- **feat:** β†’ Added section, minor version increment +- **fix:** β†’ Fixed section, patch version increment +- **docs:** β†’ Changed section, patch version increment +- **BREAKING:** β†’ Major version increment +- **chore/style/refactor/test:** β†’ Technical Details section, patch increment + +### Version Strategy + +| Commit Types | Version Increment | +| ----------------------- | --------------------- | +| Breaking changes | Major (1.0.0 β†’ 2.0.0) | +| New features (feat:) | Minor (1.0.0 β†’ 1.1.0) | +| Bug fixes, docs, chores | Patch (1.0.0 β†’ 1.0.1) | + +## πŸ”§ Development + +### Project Structure + +``` +context-ledger/ +β”œβ”€β”€ action.yml # Action definition +β”œβ”€β”€ lib/ +β”‚ └── generate-changelog.js # Core logic +β”œβ”€β”€ package.json # Dependencies +β”œβ”€β”€ README.md # Documentation +β”œβ”€β”€ LICENSE # MIT License +└── .github/ + └── workflows/ + └── test.yml # CI/CD pipeline +``` + +### Contributing + +1. Fork the repository +2. Create a feature branch: `git checkout -b feature/amazing-feature` +3. Make your changes and test thoroughly +4. Commit using conventional commits: `git commit -m 'feat: add amazing feature'` +5. Push to the branch: `git push origin feature/amazing-feature` +6. Open a Pull Request + +### Testing + +```bash +# Install dependencies +npm install + +# Run tests (when implemented) +npm test + +# Test locally with act +act pull_request -s ANTHROPIC_API_KEY=your_test_key +``` + +## πŸ§ͺ Testing & Development + +### Dual Workflow Approach + +Context Ledger provides two workflows for maximum flexibility: + +1. **Production Workflow** (`changelog.yml`) - Uses the published version (`@v1`) + + - Stable, tested version + - What your users will experience + - Runs automatically on PRs and releases + +2. **Local Workflow** (`changelog-local.yml`) - Uses the PR's code (`./`) + - Test changes before merging + - Verify fixes work as expected + - Same functionality, different source + +### Release Process + +When ready to release a new version: + +```bash +# 1. Ensure CHANGELOG.md has the new version +# 2. Merge your PR to main +# 3. Run the release script +./scripts/release.sh +``` + +This will: + +- Create a new version tag (e.g., `v1.0.19`) +- Update the floating major tag (e.g., `v1`) +- Push both tags to GitHub + +## πŸ›‘οΈ Security + +- **API Key Security**: Store your Anthropic API key in GitHub Secrets, never in code +- **Permissions**: Use minimal required permissions (`contents: write`, `pull-requests: write`) +- **Token Scope**: Action uses the provided GitHub token with repository scope only + +## πŸ“œ License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## 🀝 Support + +- πŸ“– [Documentation](https://github.com/lukemun/context-ledger) +- πŸ› [Report Issues](https://github.com/lukemun/context-ledger/issues) +- πŸ’¬ [Discussions](https://github.com/lukemun/context-ledger/discussions) + +## πŸ™ Acknowledgments + +- [Anthropic](https://anthropic.com) for the powerful Claude AI API +- [GitHub Actions](https://github.com/features/actions) for the automation platform +- The open source community for inspiration and feedback + +--- + +**Made with ❀️ by [Luke Munro](https://github.com/lukemun)** diff --git a/action.yml b/action.yml index 457f898..e39d60f 100644 --- a/action.yml +++ b/action.yml @@ -287,20 +287,14 @@ runs: // Create placeholder content if no existing content found if (!existingContent) { - existingContent = '# Changelog\n\n## [Unreleased]\n- Placeholder for AI-generated changelog\n\n\n'; + existingContent = '# Changelog\n\nAll notable changes to this project will be documented in this file.\n'; } - // Ensure AI_APPEND_HERE marker is always present at the end - if (!existingContent.includes('')) { - existingContent += '\n\n'; - console.log('πŸ“ Added AI_APPEND_HERE marker'); - } - - // If file exists but not in PR diff, add timestamp to trigger PR inclusion + // If file exists but not in PR diff, add a small change to trigger PR inclusion if (fileExistsOnTarget) { - const timestamp = new Date().toISOString(); - existingContent += `\n\n`; - console.log('πŸ“ Adding timestamp to trigger PR diff inclusion'); + // Add a newline to trigger the diff + existingContent = existingContent.trimEnd() + '\n\n'; + console.log('πŸ“ Adding whitespace to trigger PR diff inclusion'); } // Prepare API parameters @@ -449,21 +443,24 @@ runs: echo "EOF" >> $GITHUB_OUTPUT fi - # For PRs, compare against the base branch + # For PRs, check if we should create suggestions if [ "${{ github.event_name }}" = "pull_request" ]; then echo "Fetching base branch for comparison..." BASE_BRANCH="${{ steps.analyze-changes.outputs.base_branch }}" git fetch origin "$BASE_BRANCH" - echo "Comparing with origin/$BASE_BRANCH..." - if git diff --quiet "origin/$BASE_BRANCH..HEAD" -- "${{ inputs.changelog_path }}"; then - echo "has_changes=false" >> $GITHUB_OUTPUT - echo "DEBUG: No differences from base branch" - else + echo "Checking for non-changelog changes in PR..." + # Get all changed files excluding changelog + NON_CHANGELOG_CHANGES=$(git diff --name-only "origin/$BASE_BRANCH..HEAD" | grep -v -E "(CHANGELOG\.md|.*CHANGELOG\.md)$" || true) + + if [ -n "$NON_CHANGELOG_CHANGES" ]; then echo "has_changes=true" >> $GITHUB_OUTPUT - echo "DEBUG: Changelog differs from base branch" - echo "Diff preview:" - git diff "origin/$BASE_BRANCH..HEAD" -- "${{ inputs.changelog_path }}" || true + echo "DEBUG: PR has non-changelog changes, suggestions should be created" + echo "Non-changelog files changed:" + echo "$NON_CHANGELOG_CHANGES" + else + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "DEBUG: PR only has changelog changes, skipping suggestions" fi else # For non-PR events, check local changes @@ -501,6 +498,11 @@ runs: git push - name: Create GitHub PR suggestions + # Only create suggestions if: + # - Changelog was generated (status == 'UPDATED') + # - This is a PR event + # - PR has non-changelog changes (has_changes == 'true') + # - User wants suggestions (create_pr_suggestions == 'true') if: | steps.check-status.outputs.status == 'UPDATED' && github.event_name == 'pull_request' && @@ -548,13 +550,12 @@ runs: if (changelogFile.status === 'added') { core.info('Changelog file is newly added - creating file replacement suggestion'); - // For new files, suggest inserting before the AI_APPEND_HERE marker - let fullNewChangelog; - if (currentChangelog.includes('')) { - fullNewChangelog = currentChangelog.replace(//, newContent); - } else { - fullNewChangelog = currentChangelog + '\n\n' + newContent; + // For new files, append content to existing changelog + let fullNewChangelog = currentChangelog.trimEnd(); + if (fullNewChangelog) { + fullNewChangelog += '\n\n'; } + fullNewChangelog += newContent + '\n'; await github.rest.pulls.createReview({ owner: context.repo.owner, @@ -578,12 +579,12 @@ runs: throw new Error('No patch available for modified file'); } - // Parse patch to find lines we can target + // Parse patch to find the last added line in the diff const patchLines = patch.split('\n'); let bestPosition = null; let currentPosition = 0; - // Look for the AI_APPEND_HERE marker in the patch + // Find the last added line in the patch for (let i = 0; i < patchLines.length; i++) { const line = patchLines[i]; if (line.startsWith('@@')) { @@ -594,34 +595,12 @@ runs: } } else if (line.startsWith('+')) { currentPosition++; - if (line.includes('AI_APPEND_HERE')) { - bestPosition = currentPosition; - break; - } + bestPosition = currentPosition; // Keep updating to get the last added line } else if (line.startsWith(' ')) { currentPosition++; } } - // If no marker found in patch, find last added line - if (!bestPosition) { - currentPosition = 0; - for (let i = 0; i < patchLines.length; i++) { - const line = patchLines[i]; - if (line.startsWith('@@')) { - const match = line.match(/@@ -\d+,?\d* \+(\d+),?\d* @@/); - if (match) { - currentPosition = parseInt(match[1]) - 1; - } - } else if (line.startsWith('+')) { - currentPosition++; - bestPosition = currentPosition; // Keep updating to get the last one - } else if (line.startsWith(' ')) { - currentPosition++; - } - } - } - if (!bestPosition) { throw new Error('Could not find suitable position in diff'); } diff --git a/lib/generate-changelog.js b/lib/generate-changelog.js index b21da62..dc6048a 100644 --- a/lib/generate-changelog.js +++ b/lib/generate-changelog.js @@ -145,33 +145,18 @@ function getGitDiff(commitCount, isPR, baseSha, headSha) { */ function getCurrentChangelog(changelogPath, maxLines = 100) { let currentChangelog = ''; - + try { // Try to get from main branch first to avoid conflicts const fullChangelog = execSync(`git show origin/main:${changelogPath}`, { encoding: 'utf8' }); console.log('Using latest changelog from main branch to avoid conflicts'); - + // Extract only recent entries for context (last N lines) const lines = fullChangelog.split('\n'); - - // Find the AI_APPEND_HERE marker or get last maxLines - const markerIndex = lines.findIndex(line => line.includes('')); - - if (markerIndex !== -1) { - // Get lines from beginning up to marker (usually recent entries are at top) - const startIndex = Math.max(0, markerIndex - maxLines); - currentChangelog = lines.slice(startIndex, markerIndex + 1).join('\n'); - - // Also include the header if we're cutting it off - if (startIndex > 10) { - const header = lines.slice(0, 10).join('\n'); - currentChangelog = header + '\n\n... [earlier entries omitted for context] ...\n\n' + currentChangelog; - } - } else { - // No marker, just get last maxLines - currentChangelog = lines.slice(-maxLines).join('\n'); - } - + + // Just get last maxLines for context + currentChangelog = lines.slice(-maxLines).join('\n'); + console.log(`Using ${currentChangelog.split('\n').length} lines of changelog for context`); } catch (error) { console.log('Could not get changelog from main branch, using local version'); @@ -352,27 +337,32 @@ async function updateChangelog() { newChangelogContent = newChangelogContent.replace(versionHeaderMatch[1], ''); } - // Insert new content before AI_APPEND_HERE marker or append to end - let finalChangelog; - if (currentChangelog.includes('')) { - // Insert before the marker to preserve it - finalChangelog = currentChangelog.replace( - //, - `${newChangelogContent}\n\n` - ); - } else { - // No marker found, append to end and add marker - finalChangelog = currentChangelog; - if (!finalChangelog.endsWith('\n')) { - finalChangelog += '\n'; + // Get the full current changelog from main branch or local file + let fullChangelog; + try { + fullChangelog = execSync(`git show origin/main:${changelogPath}`, { encoding: 'utf8' }); + } catch (error) { + if (fs.existsSync(changelogPath)) { + fullChangelog = fs.readFileSync(changelogPath, 'utf8'); + } else { + fullChangelog = ''; } - finalChangelog += '\n' + newChangelogContent + '\n\n'; } + // Clean up trailing whitespace and ensure proper formatting + fullChangelog = fullChangelog.trimEnd(); + + // Append new content with proper spacing + let finalChangelog = fullChangelog; + if (finalChangelog) { + finalChangelog += '\n\n'; + } + finalChangelog += newChangelogContent + '\n'; + // Write files fs.writeFileSync(changelogPath, finalChangelog); - // Save the new content WITHOUT the AI_APPEND_HERE marker (it will be added during file write) + // Save the new content for the action to use fs.writeFileSync('new_content.txt', newChangelogContent); fs.writeFileSync('changelog_status.txt', 'UPDATED'); From 4cb03c55ec6063ad75815309475921f26804f3aa Mon Sep 17 00:00:00 2001 From: lukemun Date: Fri, 15 Aug 2025 17:13:56 -0400 Subject: [PATCH 3/5] fix: improve changelog suggestion handling and marker removal - Fix suggestion creation to handle cases with minimal diff - Fall back to PR comment when inline suggestion isn't possible - Remove all AI_APPEND_HERE marker logic for cleaner changelogs - Update documentation to reflect simplified approach - Fix has_changes logic to check for non-changelog files --- action.yml | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/action.yml b/action.yml index e39d60f..bf725d8 100644 --- a/action.yml +++ b/action.yml @@ -292,9 +292,10 @@ runs: // If file exists but not in PR diff, add a small change to trigger PR inclusion if (fileExistsOnTarget) { - // Add a newline to trigger the diff - existingContent = existingContent.trimEnd() + '\n\n'; - console.log('πŸ“ Adding whitespace to trigger PR diff inclusion'); + // Add a comment with timestamp to ensure it shows in diff + const timestamp = new Date().toISOString(); + existingContent = existingContent.trimEnd() + '\n\n\n'; + console.log('πŸ“ Adding timestamp comment to trigger PR diff inclusion'); } // Prepare API parameters @@ -579,12 +580,13 @@ runs: throw new Error('No patch available for modified file'); } - // Parse patch to find the last added line in the diff + // Parse patch to find a suitable position for the suggestion const patchLines = patch.split('\n'); let bestPosition = null; let currentPosition = 0; + let lastContextLine = null; - // Find the last added line in the patch + // Find the last added or context line in the patch for (let i = 0; i < patchLines.length; i++) { const line = patchLines[i]; if (line.startsWith('@@')) { @@ -595,14 +597,29 @@ runs: } } else if (line.startsWith('+')) { currentPosition++; - bestPosition = currentPosition; // Keep updating to get the last added line + bestPosition = currentPosition; // Prefer added lines } else if (line.startsWith(' ')) { currentPosition++; + lastContextLine = currentPosition; // Track context lines as fallback } } + // Use the best position found, or fall back to last context line + if (!bestPosition && lastContextLine) { + bestPosition = lastContextLine; + } + if (!bestPosition) { - throw new Error('Could not find suitable position in diff'); + core.warning('Could not find ideal position in diff, attempting to create comment without line suggestion'); + // Instead of throwing, create a general PR comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `πŸ€– **AI Changelog Ready!**\n\nAdd this to your \`${targetPath}\`:\n\n\`\`\`markdown\n${newContent}\n\`\`\`\n\n*Note: Could not create an inline suggestion due to diff limitations. Please copy and paste the above content manually.*` + }); + core.info('βœ… Posted changelog as PR comment (could not create inline suggestion)'); + return; } // Create suggestion targeting the found position From 5246034cb0e8a368834dba05cba59fdd54536afb Mon Sep 17 00:00:00 2001 From: lukemun Date: Fri, 15 Aug 2025 17:20:06 -0400 Subject: [PATCH 4/5] feat: use CONTEXT_LEDGER_MARKER for changelog insertion - Replace generic AI_CONTENT with project-specific CONTEXT_LEDGER_MARKER - Marker stays at the end of file as insertion point - New entries are inserted before the marker - Prevents conflicts with actual changelog content --- CHANGELOG.md | 2 ++ README.md | 12 +++++++----- action.yml | 29 +++++++++++++++++++++++------ lib/generate-changelog.js | 27 +++++++++++++++++---------- 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa7272..d00b986 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,3 +36,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Supports conventional commit message parsing - Includes comprehensive error handling and logging - Provides detailed outputs for integration with other workflows + + diff --git a/README.md b/README.md index 58035c8..f368541 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ jobs: All notable changes to this project will be documented in this file. ## [Unreleased] + + ``` - **Open a PR**: The action analyzes your changes and suggests entries for `CHANGELOG.md`. @@ -394,12 +396,12 @@ jobs: ### Changelog Generation -The action uses a clean, marker-free approach: +The action uses a simple marker-based approach: -- Reads your existing changelog content -- Generates new entries based on PR changes -- Appends the new content to the end of the file -- No HTML comments or markers needed - just clean markdown +- Looks for the `` marker at the end of your changelog +- Inserts new entries just before this marker +- The marker always stays at the bottom of the file +- This ensures clean insertion points and prevents overwriting content ### Commit Analysis diff --git a/action.yml b/action.yml index bf725d8..058f67e 100644 --- a/action.yml +++ b/action.yml @@ -287,15 +287,24 @@ runs: // Create placeholder content if no existing content found if (!existingContent) { - existingContent = '# Changelog\n\nAll notable changes to this project will be documented in this file.\n'; + existingContent = '# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n\n'; + } + + // Ensure Context Ledger marker exists + if (!existingContent.includes('')) { + existingContent = existingContent.trimEnd() + '\n\n\n'; + console.log('πŸ“ Added Context Ledger marker'); } // If file exists but not in PR diff, add a small change to trigger PR inclusion if (fileExistsOnTarget) { - // Add a comment with timestamp to ensure it shows in diff + // Add a timestamp comment before the marker to ensure it shows in diff const timestamp = new Date().toISOString(); - existingContent = existingContent.trimEnd() + '\n\n\n'; - console.log('πŸ“ Adding timestamp comment to trigger PR diff inclusion'); + existingContent = existingContent.replace( + '', + `\n` + ); + console.log('πŸ“ Adding timestamp to trigger PR diff inclusion'); } // Prepare API parameters @@ -586,7 +595,7 @@ runs: let currentPosition = 0; let lastContextLine = null; - // Find the last added or context line in the patch + // Find the AI_CONTENT marker or the last added/context line for (let i = 0; i < patchLines.length; i++) { const line = patchLines[i]; if (line.startsWith('@@')) { @@ -597,9 +606,17 @@ runs: } } else if (line.startsWith('+')) { currentPosition++; - bestPosition = currentPosition; // Prefer added lines + if (line.includes('CONTEXT_LEDGER_MARKER')) { + bestPosition = currentPosition; + break; // Found our marker, stop searching + } + bestPosition = currentPosition; // Keep track of added lines } else if (line.startsWith(' ')) { currentPosition++; + if (line.includes('CONTEXT_LEDGER_MARKER')) { + bestPosition = currentPosition; + break; // Found our marker, stop searching + } lastContextLine = currentPosition; // Track context lines as fallback } } diff --git a/lib/generate-changelog.js b/lib/generate-changelog.js index dc6048a..76196df 100644 --- a/lib/generate-changelog.js +++ b/lib/generate-changelog.js @@ -337,7 +337,7 @@ async function updateChangelog() { newChangelogContent = newChangelogContent.replace(versionHeaderMatch[1], ''); } - // Get the full current changelog from main branch or local file + // Get the full current changelog from main branch or local file let fullChangelog; try { fullChangelog = execSync(`git show origin/main:${changelogPath}`, { encoding: 'utf8' }); @@ -348,16 +348,23 @@ async function updateChangelog() { fullChangelog = ''; } } - - // Clean up trailing whitespace and ensure proper formatting - fullChangelog = fullChangelog.trimEnd(); - - // Append new content with proper spacing - let finalChangelog = fullChangelog; - if (finalChangelog) { - finalChangelog += '\n\n'; + + // Look for the Context Ledger marker + const marker = ''; + let finalChangelog; + + if (fullChangelog.includes(marker)) { + // Insert new content before the marker + finalChangelog = fullChangelog.replace(marker, newChangelogContent + '\n\n' + marker); + } else { + // No marker found, append content and add marker + fullChangelog = fullChangelog.trimEnd(); + if (fullChangelog) { + finalChangelog = fullChangelog + '\n\n' + newChangelogContent + '\n\n' + marker + '\n'; + } else { + finalChangelog = newChangelogContent + '\n\n' + marker + '\n'; + } } - finalChangelog += newChangelogContent + '\n'; // Write files fs.writeFileSync(changelogPath, finalChangelog); From 8fb8645fb09c5cfd0d730db85b085f3f37421059 Mon Sep 17 00:00:00 2001 From: Luke Munro Date: Fri, 15 Aug 2025 17:21:37 -0400 Subject: [PATCH 5/5] Update CHANGELOG.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CHANGELOG.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d00b986..7f7d083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,4 +37,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Includes comprehensive error handling and logging - Provides detailed outputs for integration with other workflows - +## [1.1.0] - August 2025 + +Introduces improved changelog management with a dedicated marker system for automated insertions, along with streamlined documentation and configuration options for better usability. + +### Added +- New CONTEXT_LEDGER_MARKER system for precise changelog entry insertion +- Enhanced configuration options for changelog suggestion handling + +### Changed +- Streamlined documentation structure with improved README clarity +- Simplified action configuration with better defaults +- Optimized changelog generation process + +### Fixed +- Improved handling of changelog suggestions and marker removal +- Enhanced action stability and reliability + +### Removed +- Legacy migration files and outdated documentation +- Deprecated example configurations + +### Technical Details +- Refactored changelog generation logic for better maintainability +- Improved marker-based insertion system for more reliable updates