From 36d40afb4eec31b9f7679e649e11e1455f46d160 Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 18:58:51 -0800 Subject: [PATCH 1/7] 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", From 5db9ad2585ab5c7441037e525233c9bb57969bc8 Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 19:06:34 -0800 Subject: [PATCH 2/7] revert to older config --- .changeset/changelog-config.js | 20 -------------------- .changeset/config.json | 4 ++-- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 .changeset/changelog-config.js diff --git a/.changeset/changelog-config.js b/.changeset/changelog-config.js deleted file mode 100644 index 1e64dbf093..0000000000 --- a/.changeset/changelog-config.js +++ /dev/null @@ -1,20 +0,0 @@ -// 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 bcd6eefa00..42efc1c834 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,6 +1,6 @@ { - "$schema": "https://unpkg.com/@changesets/config@3.0.4/schema.json", - "changelog": "./changelog-config.js", + "$schema": "https://unpkg.com/@changesets/config@3.0.5/schema.json", + "changelog": "@changesets/cli/changelog", "commit": false, "fixed": [], "linked": [], From 42c6dc7e94ba21d8854997253e10cf797ff1d20e Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 19:20:18 -0800 Subject: [PATCH 3/7] update based on automated feedback --- .github/scripts/overwrite_changeset_changelog.py | 15 ++++++++++++--- .github/workflows/changeset-release.yml | 16 ++++++++++------ .github/workflows/check-changeset.yml | 8 ++++++-- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/.github/scripts/overwrite_changeset_changelog.py b/.github/scripts/overwrite_changeset_changelog.py index 0be482c555..eb3361bf2f 100644 --- a/.github/scripts/overwrite_changeset_changelog.py +++ b/.github/scripts/overwrite_changeset_changelog.py @@ -35,15 +35,24 @@ def overwrite_changelog_section(changelog_text: str, new_content: str): print(f"latest version: {VERSION}") print(f"prev_version: {PREV_VERSION}") - notes_start_index = changelog_text.find(version_pattern) + len(version_pattern) + version_index = changelog_text.find(version_pattern) + if version_index == -1: + raise ValueError(f"Could not find version {VERSION} in changelog") + + notes_start_index = version_index + 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:]) + # Ensure we have at least 2 lines before removing them + if len(changeset_lines) < 2: + print("Warning: Changeset content has fewer than 2 lines") + parsed_lines = "\n".join(changeset_lines) + else: + # 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 diff --git a/.github/workflows/changeset-release.yml b/.github/workflows/changeset-release.yml index 0e97893d1d..332b98a66d 100644 --- a/.github/workflows/changeset-release.yml +++ b/.github/workflows/changeset-release.yml @@ -1,6 +1,10 @@ name: Changeset Release run-name: Changeset Release ${{ github.actor != 'cline-bot' && '- Create PR' || '- Update Changelog' }} +permissions: + contents: write + pull-requests: write + on: workflow_dispatch: pull_request: @@ -25,13 +29,13 @@ jobs: pull-requests: write steps: - name: Git Checkout - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 ref: ${{ env.GIT_REF }} - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4 with: node-version: 20 cache: "npm" @@ -51,7 +55,7 @@ jobs: - name: Changeset Pull Request if: steps.check-changesets.outputs.new_changesets != '0' id: changesets - uses: changesets/action@v1 + uses: changesets/action@e9cc34b540dd3ad1b030c57fd97269e8f6ad905a # v1 with: commit: "changeset version bump" title: "Changeset version bump" @@ -89,7 +93,7 @@ jobs: fi - name: Checkout Repo - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 @@ -132,7 +136,7 @@ jobs: # 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 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -146,7 +150,7 @@ jobs: # 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 + uses: hmarr/auto-approve-action@de8bf34d0402c38aa2c8346973342b2cb02c4435 # v4 with: review-message: "I'm approving since it's a bump version PR" diff --git a/.github/workflows/check-changeset.yml b/.github/workflows/check-changeset.yml index 29c7b20801..9d8f7a3469 100644 --- a/.github/workflows/check-changeset.yml +++ b/.github/workflows/check-changeset.yml @@ -1,6 +1,10 @@ name: Check Changeset run-name: Check for Changeset in PR +permissions: + contents: read + pull-requests: write + on: pull_request: branches: @@ -51,7 +55,7 @@ jobs: fi - name: Find Comment - uses: peter-evans/find-comment@v3 + uses: peter-evans/find-comment@45803def666fc704971eff4c7d57d650f81ae24a # v3 if: failure() id: find-comment with: @@ -60,7 +64,7 @@ jobs: body-includes: This PR requires a changeset - name: Create Comment - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@23ff15e22924c50649c1d63cc73f02f16fc0a8e8 # v4 if: failure() && steps.find-comment.outputs.comment-id == '' with: issue-number: ${{ github.event.pull_request.number }} From 15c147cf93c2e0d1cb9940756d8328150d68d289 Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 21:45:15 -0800 Subject: [PATCH 4/7] fix check changeset git action --- .github/workflows/check-changeset.yml | 91 +++++++++++++++++++-------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/.github/workflows/check-changeset.yml b/.github/workflows/check-changeset.yml index 9d8f7a3469..48ffc1ca41 100644 --- a/.github/workflows/check-changeset.yml +++ b/.github/workflows/check-changeset.yml @@ -18,18 +18,31 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} - name: Check for changeset id: check-changeset run: | + # Debug info + echo "Current directory: $(pwd)" + echo "PR Base Ref: ${{ github.event.pull_request.base.ref }}" + echo "PR Head Ref: ${{ github.event.pull_request.head.ref }}" + echo "PR Head SHA: ${{ github.event.pull_request.head.sha }}" + echo "Git status:" + git status + # Get list of changed files - CHANGED_FILES=$(git diff --name-only origin/main...HEAD) + git fetch origin ${{ github.event.pull_request.base.ref }} + CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }} HEAD) echo "Changed files:" echo "$CHANGED_FILES" + echo "Listing .changeset directory:" + ls -la .changeset/ + # Check if any of the changed files are in docs/ or .github/ DOCS_ONLY=true while IFS= read -r file; do @@ -45,38 +58,62 @@ jobs: 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" + # Check if any changeset files are in the changed files + CHANGESET_IN_PR=false + while IFS= read -r file; do + if [[ "$file" =~ ^\.changeset/.*\.md$ && "$file" != ".changeset/README.md" ]]; then + echo "Found changeset file in PR: $file" + CHANGESET_IN_PR=true + break + fi + done <<< "$CHANGED_FILES" - if [ "$CHANGESETS" -eq 0 ]; then - echo "::error::No changeset file found. Please run 'npm run changeset' to create one." - exit 1 + if [ "$CHANGESET_IN_PR" = false ]; then + # Double check local changeset files as backup + CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ') + echo "Number of local changesets: $CHANGESETS" + + if [ "$CHANGESETS" -eq 0 ]; then + echo "::error::No changeset file found in PR changes or local directory. Please run 'npm run changeset' to create one." + exit 1 + fi fi - - name: Find Comment - uses: peter-evans/find-comment@45803def666fc704971eff4c7d57d650f81ae24a # v3 + - name: Comment on PR if: failure() - id: find-comment + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: "github-actions[bot]" - body-includes: This PR requires a changeset + script: | + const message = `This PR requires a changeset since it includes user-facing changes. Please: - - name: Create Comment - uses: peter-evans/create-or-update-comment@23ff15e22924c50649c1d63cc73f02f16fc0a8e8 # 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 + 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) + - \`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. + Note: Documentation-only changes do not require a changeset.`; + + // Get existing comments + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + + // Check if we already commented + const botComment = comments.data.find(comment => + comment.user.login === 'github-actions[bot]' && + comment.body.includes('This PR requires a changeset') + ); + + if (!botComment) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: message + }); + } From 9fbd8318f0a161ad022d0af8dfd9906d001010b2 Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 21:49:41 -0800 Subject: [PATCH 5/7] error handling when notes_start_index is invalid --- .../scripts/overwrite_changeset_changelog.py | 53 +++++++++++++++---- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/.github/scripts/overwrite_changeset_changelog.py b/.github/scripts/overwrite_changeset_changelog.py index eb3361bf2f..36fde943b4 100644 --- a/.github/scripts/overwrite_changeset_changelog.py +++ b/.github/scripts/overwrite_changeset_changelog.py @@ -31,13 +31,25 @@ 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" + bracketed_version_pattern = f"## [{VERSION}]\n" prev_version_pattern = f"## [{PREV_VERSION}]\n" print(f"latest version: {VERSION}") print(f"prev_version: {PREV_VERSION}") + # Try both unbracketed and bracketed version patterns version_index = changelog_text.find(version_pattern) if version_index == -1: - raise ValueError(f"Could not find version {VERSION} in changelog") + version_index = changelog_text.find(bracketed_version_pattern) + if version_index == -1: + # If version not found, add it at the top (after the first line) + first_newline = changelog_text.find('\n') + if first_newline == -1: + # If no newline found, just prepend + return f"## [{VERSION}]\n\n{changelog_text}" + return f"{changelog_text[:first_newline + 1]}## [{VERSION}]\n\n{changelog_text[first_newline + 1:]}" + else: + # Using bracketed version + version_pattern = bracketed_version_pattern notes_start_index = version_index + 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) @@ -54,18 +66,37 @@ def overwrite_changelog_section(changelog_text: str, new_content: str): # 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:] + # Ensure version number is bracketed updated_changelog = updated_changelog.replace(f"## {VERSION}", f"## [{VERSION}]") return updated_changelog -with open(CHANGELOG_PATH, 'r') as f: - changelog_content = f.read() +try: + print(f"Reading changelog from: {CHANGELOG_PATH}") + 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 content length: {len(changelog_content)} characters") + print("First 200 characters of changelog:") + print(changelog_content[:200]) + print("----------------------------------------------------------------------------------") -print(f"{CHANGELOG_PATH} updated successfully!") + new_changelog = overwrite_changelog_section(changelog_content, NEW_CONTENT) + + print("New changelog content:") + print("----------------------------------------------------------------------------------") + print(new_changelog) + print("----------------------------------------------------------------------------------") + + print(f"Writing updated changelog back to: {CHANGELOG_PATH}") + with open(CHANGELOG_PATH, 'w') as f: + f.write(new_changelog) + + print(f"{CHANGELOG_PATH} updated successfully!") + +except FileNotFoundError: + print(f"Error: Changelog file not found at {CHANGELOG_PATH}") + exit(1) +except Exception as e: + print(f"Error updating changelog: {str(e)}") + print(f"Current working directory: {os.getcwd()}") + exit(1) From 1415c8ce7b55368eb6353a95a6b5955dbce9686a Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 21:56:53 -0800 Subject: [PATCH 6/7] use sys.exit --- .github/scripts/overwrite_changeset_changelog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/scripts/overwrite_changeset_changelog.py b/.github/scripts/overwrite_changeset_changelog.py index 36fde943b4..56fea2ad37 100644 --- a/.github/scripts/overwrite_changeset_changelog.py +++ b/.github/scripts/overwrite_changeset_changelog.py @@ -22,6 +22,7 @@ Environment Variables: #!/usr/bin/env python3 import os +import sys CHANGELOG_PATH = os.environ.get("CHANGELOG_PATH", "CHANGELOG.md") VERSION = os.environ['VERSION'] @@ -95,7 +96,7 @@ try: except FileNotFoundError: print(f"Error: Changelog file not found at {CHANGELOG_PATH}") - exit(1) + sys.exit(1) except Exception as e: print(f"Error updating changelog: {str(e)}") print(f"Current working directory: {os.getcwd()}") From 6937823b690e0399ad4f8ae15164fc255dcf8172 Mon Sep 17 00:00:00 2001 From: Ocasta Date: Tue, 4 Feb 2025 22:05:03 -0800 Subject: [PATCH 7/7] use sys.exit, again --- .github/scripts/overwrite_changeset_changelog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/overwrite_changeset_changelog.py b/.github/scripts/overwrite_changeset_changelog.py index 56fea2ad37..67fdb6a647 100644 --- a/.github/scripts/overwrite_changeset_changelog.py +++ b/.github/scripts/overwrite_changeset_changelog.py @@ -100,4 +100,4 @@ except FileNotFoundError: except Exception as e: print(f"Error updating changelog: {str(e)}") print(f"Current working directory: {os.getcwd()}") - exit(1) + sys.exit(1)