From 36d40afb4eec31b9f7679e649e11e1455f46d160 Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 18:58:51 -0800 Subject: [PATCH] changelogs --- .changeset/changelog-config.js | 20 +++ .changeset/config.json | 4 +- .changeset/twelve-deers-search.md | 5 + .github/pull_request_template.md | 1 + .../scripts/overwrite_changeset_changelog.py | 62 +++++++ .github/workflows/changeset-release.yml | 158 ++++++++++++++++++ .github/workflows/check-changeset.yml | 78 +++++++++ CONTRIBUTING.md | 16 +- package-lock.json | 4 +- package.json | 3 +- 10 files changed, 343 insertions(+), 8 deletions(-) create mode 100644 .changeset/changelog-config.js create mode 100644 .changeset/twelve-deers-search.md create mode 100644 .github/scripts/overwrite_changeset_changelog.py create mode 100644 .github/workflows/changeset-release.yml create mode 100644 .github/workflows/check-changeset.yml diff --git a/.changeset/changelog-config.js b/.changeset/changelog-config.js new file mode 100644 index 0000000000..1e64dbf093 --- /dev/null +++ b/.changeset/changelog-config.js @@ -0,0 +1,20 @@ +// Half-works to simplify the format but needs 'overwrite_changeset_changelog.py' in GHA to finish formatting + +const getReleaseLine = async (changeset) => { + const [firstLine] = changeset.summary + .split("\n") + .map((l) => l.trim()) + .filter(Boolean) + return `- ${firstLine}` +} + +const getDependencyReleaseLine = async () => { + return "" +} + +const changelogFunctions = { + getReleaseLine, + getDependencyReleaseLine, +} + +module.exports = changelogFunctions diff --git a/.changeset/config.json b/.changeset/config.json index 42efc1c834..bcd6eefa00 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,6 +1,6 @@ { - "$schema": "https://unpkg.com/@changesets/config@3.0.5/schema.json", - "changelog": "@changesets/cli/changelog", + "$schema": "https://unpkg.com/@changesets/config@3.0.4/schema.json", + "changelog": "./changelog-config.js", "commit": false, "fixed": [], "linked": [], diff --git a/.changeset/twelve-deers-search.md b/.changeset/twelve-deers-search.md new file mode 100644 index 0000000000..f87090b079 --- /dev/null +++ b/.changeset/twelve-deers-search.md @@ -0,0 +1,5 @@ +--- +"claude-dev": minor +--- + +Adding changesets for automating version bumping and release notes diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 22a8a9976e..989040aab2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -21,6 +21,7 @@ - [ ] Changes are limited to a single feature, bugfix or chore (split larger changes into separate PRs) - [ ] Tests are passing (`npm test`) and code is formatted and linted (`npm run format && npm run lint`) +- [ ] I have created a changeset using `npm run changeset` (required for user-facing changes) - [ ] I have reviewed [contributor guidelines](https://github.com/cline/cline/blob/main/CONTRIBUTING.md) ### Screenshots diff --git a/.github/scripts/overwrite_changeset_changelog.py b/.github/scripts/overwrite_changeset_changelog.py new file mode 100644 index 0000000000..0be482c555 --- /dev/null +++ b/.github/scripts/overwrite_changeset_changelog.py @@ -0,0 +1,62 @@ +""" +This script updates a specific version's release notes section in CHANGELOG.md with new content +or reformats existing content. + +The script: +1. Takes a version number, changelog path, and optionally new content as input from environment variables +2. Finds the section in the changelog for the specified version +3. Either: + a) Replaces the content with new content if provided, or + b) Reformats existing content by: + - Removing the first two lines of the changeset format + - Ensuring version numbers are wrapped in square brackets +4. Writes the updated changelog back to the file + +Environment Variables: + CHANGELOG_PATH: Path to the changelog file (defaults to 'CHANGELOG.md') + VERSION: The version number to update/format + PREV_VERSION: The previous version number (used to locate section boundaries) + NEW_CONTENT: Optional new content to insert for this version +""" + +#!/usr/bin/env python3 + +import os + +CHANGELOG_PATH = os.environ.get("CHANGELOG_PATH", "CHANGELOG.md") +VERSION = os.environ['VERSION'] +PREV_VERSION = os.environ.get("PREV_VERSION", "") +NEW_CONTENT = os.environ.get("NEW_CONTENT", "") + +def overwrite_changelog_section(changelog_text: str, new_content: str): + # Find the section for the specified version + version_pattern = f"## {VERSION}\n" + prev_version_pattern = f"## [{PREV_VERSION}]\n" + print(f"latest version: {VERSION}") + print(f"prev_version: {PREV_VERSION}") + + notes_start_index = changelog_text.find(version_pattern) + len(version_pattern) + notes_end_index = changelog_text.find(prev_version_pattern, notes_start_index) if PREV_VERSION and prev_version_pattern in changelog_text else len(changelog_text) + + if new_content: + return changelog_text[:notes_start_index] + f"{new_content}\n" + changelog_text[notes_end_index:] + else: + changeset_lines = changelog_text[notes_start_index:notes_end_index].split("\n") + # Remove the first two lines from the regular changeset format, ex: \n### Patch Changes + parsed_lines = "\n".join(changeset_lines[2:]) + updated_changelog = changelog_text[:notes_start_index] + parsed_lines + changelog_text[notes_end_index:] + updated_changelog = updated_changelog.replace(f"## {VERSION}", f"## [{VERSION}]") + return updated_changelog + +with open(CHANGELOG_PATH, 'r') as f: + changelog_content = f.read() + +new_changelog = overwrite_changelog_section(changelog_content, NEW_CONTENT) +print("----------------------------------------------------------------------------------") +print(new_changelog) +print("----------------------------------------------------------------------------------") +# Write back to CHANGELOG.md +with open(CHANGELOG_PATH, 'w') as f: + f.write(new_changelog) + +print(f"{CHANGELOG_PATH} updated successfully!") diff --git a/.github/workflows/changeset-release.yml b/.github/workflows/changeset-release.yml new file mode 100644 index 0000000000..0e97893d1d --- /dev/null +++ b/.github/workflows/changeset-release.yml @@ -0,0 +1,158 @@ +name: Changeset Release +run-name: Changeset Release ${{ github.actor != 'cline-bot' && '- Create PR' || '- Update Changelog' }} + +on: + workflow_dispatch: + pull_request: + types: [closed, opened, labeled] + +env: + REPO_PATH: ${{ github.repository }} + GIT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || 'main' }} + +jobs: + # Job 1: Create version bump PR when changesets are merged to main + changeset-pr-version-bump: + if: > + ( github.event_name == 'pull_request' && + github.event.pull_request.merged == true && + github.event.pull_request.base.ref == 'main' && + github.actor != 'cline-bot' ) || + github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ env.GIT_REF }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + + - name: Install Dependencies + run: npm run install:all + + # Check if there are any new changesets to process + - name: Check for changesets + id: check-changesets + run: | + NEW_CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ') + echo "Changesets diff with previous version: $NEW_CHANGESETS" + echo "new_changesets=$NEW_CHANGESETS" >> $GITHUB_OUTPUT + + # Create version bump PR using changesets/action if there are new changesets + - name: Changeset Pull Request + if: steps.check-changesets.outputs.new_changesets != '0' + id: changesets + uses: changesets/action@v1 + with: + commit: "changeset version bump" + title: "Changeset version bump" + version: npm run version-packages # This performs the changeset version bump + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Job 2: Process version bump PR created by cline-bot + changeset-pr-edit-approve: + name: Auto approve and merge Bump version PRs + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + if: > + github.event_name == 'pull_request' && + github.event.pull_request.base.ref == 'main' && + github.actor == 'cline-bot' && + contains(github.event.pull_request.title, 'Changeset version bump') + steps: + - name: Determine checkout ref + id: checkout-ref + run: | + echo "Event action: ${{ github.event.action }}" + echo "Actor: ${{ github.actor }}" + echo "Head ref: ${{ github.head_ref }}" + echo "PR SHA: ${{ github.event.pull_request.head.sha }}" + + if [[ "${{ github.event.action }}" == "opened" && "${{ github.actor }}" == "cline-bot" ]]; then + echo "Using branch ref: ${{ github.head_ref }}" + echo "git_ref=${{ github.head_ref }}" >> $GITHUB_OUTPUT + else + echo "Using SHA ref: ${{ github.event.pull_request.head.sha }}" + echo "git_ref=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT + fi + + - name: Checkout Repo + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + ref: ${{ steps.checkout-ref.outputs.git_ref }} + + # Get current and previous versions to edit changelog entry + - name: Get version + id: get_version + run: | + VERSION=$(git show HEAD:package.json | jq -r '.version') + echo "version=$VERSION" >> $GITHUB_OUTPUT + PREV_VERSION=$(git show origin/main:package.json | jq -r '.version') + echo "prev_version=$PREV_VERSION" >> $GITHUB_OUTPUT + echo "version=$VERSION" + echo "prev_version=$PREV_VERSION" + + # Update CHANGELOG.md with proper format + - name: Update Changelog Format + if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} + env: + VERSION: ${{ steps.get_version.outputs.version }} + PREV_VERSION: ${{ steps.get_version.outputs.prev_version }} + run: python .github/scripts/overwrite_changeset_changelog.py + + # Commit and push changelog updates + - name: Push Changelog updates + if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} + run: | + git config user.name "cline-bot" + git config user.email github-actions@github.com + echo "Running git add and commit..." + git add CHANGELOG.md + git commit -m "Updating CHANGELOG.md format" + git status + echo "--------------------------------------------------------------------------------" + echo "Pushing to remote..." + echo "--------------------------------------------------------------------------------" + git push + + # Add label to indicate changelog has been formatted + - name: Add changelog-ready label + if: ${{ !contains(github.event.pull_request.labels.*.name, 'changelog-ready') }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['changelog-ready'] + }); + + # Auto-approve PR only after it has been labeled + - name: Auto approve PR + if: contains(github.event.pull_request.labels.*.name, 'changelog-ready') + uses: hmarr/auto-approve-action@v4 + with: + review-message: "I'm approving since it's a bump version PR" + + # Auto-merge PR + - name: Automerge on PR + if: false # Needs enablePullRequestAutoMerge in repo settings to work contains(github.event.pull_request.labels.*.name, 'changelog-ready') + run: gh pr merge --auto --merge ${{ github.event.pull_request.number }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/check-changeset.yml b/.github/workflows/check-changeset.yml new file mode 100644 index 0000000000..29c7b20801 --- /dev/null +++ b/.github/workflows/check-changeset.yml @@ -0,0 +1,78 @@ +name: Check Changeset +run-name: Check for Changeset in PR + +on: + pull_request: + branches: + - main + types: [opened, synchronize, reopened, ready_for_review] + +jobs: + check-changeset: + # Skip draft PRs and dependabot PRs + if: github.event.pull_request.draft == false && github.actor != 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for changeset + id: check-changeset + run: | + # Get list of changed files + CHANGED_FILES=$(git diff --name-only origin/main...HEAD) + echo "Changed files:" + echo "$CHANGED_FILES" + + # Check if any of the changed files are in docs/ or .github/ + DOCS_ONLY=true + while IFS= read -r file; do + if [[ ! "$file" =~ ^(docs/|.github/) ]]; then + DOCS_ONLY=false + break + fi + done <<< "$CHANGED_FILES" + + # If changes are docs-only, skip changeset check + if [ "$DOCS_ONLY" = true ]; then + echo "Only documentation files were changed, skipping changeset check" + exit 0 + fi + + # Count number of changeset files (excluding README.md) + CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ') + echo "Number of changesets: $CHANGESETS" + + if [ "$CHANGESETS" -eq 0 ]; then + echo "::error::No changeset file found. Please run 'npm run changeset' to create one." + exit 1 + fi + + - name: Find Comment + uses: peter-evans/find-comment@v3 + if: failure() + id: find-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: "github-actions[bot]" + body-includes: This PR requires a changeset + + - name: Create Comment + uses: peter-evans/create-or-update-comment@v4 + if: failure() && steps.find-comment.outputs.comment-id == '' + with: + issue-number: ${{ github.event.pull_request.number }} + body: | + This PR requires a changeset since it includes user-facing changes. Please: + + 1. Run `npm run changeset` locally + 2. Choose the appropriate version bump: + - `major` for breaking changes (1.0.0 → 2.0.0) + - `minor` for new features (1.0.0 → 1.1.0) + - `patch` for bug fixes (1.0.0 → 1.0.1) + 3. Write a clear description of your changes + 4. Commit the generated changeset file + + Note: Documentation-only changes do not require a changeset. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75edd9ed43..ce24b906bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,20 +56,30 @@ Anyone can contribute code to Cline, but we ask that you follow these guidelines - Update existing tests if your changes affect them - Include both unit tests and integration tests where appropriate -4. **Commit Guidelines** +4. **Version Management with Changesets** + + - Create a changeset for any user-facing changes using `npm run changeset` + - Choose the appropriate version bump: + - `major` for breaking changes (1.0.0 → 2.0.0) + - `minor` for new features (1.0.0 → 1.1.0) + - `patch` for bug fixes (1.0.0 → 1.0.1) + - Write clear, descriptive changeset messages that explain the impact + - Documentation-only changes don't require changesets + +5. **Commit Guidelines** - Write clear, descriptive commit messages - Use conventional commit format (e.g., "feat:", "fix:", "docs:") - Reference relevant issues in commits using #issue-number -5. **Before Submitting** +6. **Before Submitting** - Rebase your branch on the latest main - Ensure your branch builds successfully - Double-check all tests are passing - Review your changes for any debugging code or console logs -6. **Pull Request Description** +7. **Pull Request Description** - Clearly describe what your changes do - Include steps to test the changes - List any breaking changes diff --git a/package-lock.json b/package-lock.json index f859809461..25b4a9e508 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "claude-dev", - "version": "3.2.10", + "version": "3.2.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "claude-dev", - "version": "3.2.10", + "version": "3.2.12", "license": "Apache-2.0", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", diff --git a/package.json b/package.json index 03702f04fa..f33033f379 100644 --- a/package.json +++ b/package.json @@ -187,7 +187,8 @@ "publish:marketplace": "vsce publish && ovsx publish", "publish:marketplace:prerelease": "vsce publish --pre-release && ovsx publish --pre-release", "prepare": "husky", - "changeset": "changeset" + "changeset": "changeset", + "version-packages": "changeset version" }, "devDependencies": { "@changesets/cli": "^2.27.12",