diff --git a/.github/workflows/assign-prs.yml b/.github/workflows/assign-prs.yml index 7ba524d..748e918 100644 --- a/.github/workflows/assign-prs.yml +++ b/.github/workflows/assign-prs.yml @@ -15,8 +15,11 @@ name: PR assignment on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] - needs write token on fork PRs; never checks out or runs PR code types: [opened, edited, reopened] + branches: [main] + +permissions: {} jobs: auto-assign: @@ -26,7 +29,7 @@ jobs: pull-requests: write steps: - name: "Auto-assign PR" - uses: pozil/auto-assign-issue@v2 + uses: pozil/auto-assign-issue@7bf9d82c77d45976224660b873fc83e60576c5aa # v2 with: assignees: dolphin1999,isaurabhuttam numOfAssignee: 1 diff --git a/.github/workflows/mirror-changelog.yml b/.github/workflows/mirror-changelog.yml deleted file mode 100644 index 079ec7e..0000000 --- a/.github/workflows/mirror-changelog.yml +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Mirror Toolbox Changelog - -on: - pull_request_target: - types: [opened, edited] - -jobs: - add-release-notes: - if: github.actor == 'renovate-bot' && startsWith(github.head_ref, 'renovate/googleapis-mcp-toolbox') - runs-on: ubuntu-latest - permissions: - pull-requests: write - - steps: - - name: Add Toolbox Release Notes to PR Body - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - REQUIRED_KEYWORDS: 'postgres' - with: - script: | - const requiredKeywordsEnv = process.env.REQUIRED_KEYWORDS; - const requiredKeywords = requiredKeywordsEnv.split(',').map(kw => kw.trim()).filter(kw => kw.length > 0); - - const prBody = context.payload.pull_request.body || ''; - - // Extract the relevant changelog section - const startMarker = 'googleapis/mcp-toolbox'; - const endMarker = ''; - const startIndex = prBody.indexOf(startMarker); - const endIndex = prBody.indexOf(endMarker, startIndex); - - if (startIndex === -1 || endIndex === -1) { - console.log('Could not find the release notes section in the PR body. Exiting.'); - return; - } - const releaseNotesSection = prBody.substring(startIndex, endIndex); - - // Parse, Filter, and transform - const prefixesToFilter = ['source/', 'sources/', 'tool/', 'tools/']; - - // Use a map for cleaner type switching - const typeMap = { - '##### ⚠ BREAKING CHANGES': 'feat!', - '##### Features': 'feat', - '##### Bug Fixes': 'fix', - '##### Chores': 'ignore', - '##### Miscellaneous Chores': 'ignore', - '##### Documentation': 'ignore', - }; - - let currentType = 'feat'; // Default - const newChangelog = []; - - for (const line of releaseNotesSection.split('\n')) { - const trimmedLine = line.trim(); - - // Update current type if it's a header - if (typeMap[trimmedLine]) { - currentType = typeMap[trimmedLine]; - continue; - } - - // Skip ignored sections - if (currentType === 'ignore') { - continue; - } - - // Match and extract changelog item - const itemMatch = trimmedLine.match(/^[*-]\s(.*)$/); - if (itemMatch) { - let originalContent = itemMatch[1]; - - // This is a two-step process to prevent `release-please` from - // creating mangled, doubly-nested links for PRs. - - // STEP 1: CLEAN THE INPUT. - // The source changelog contains a zero-width space as an HTML entity (`​`). - // This breaks the regex in the next step, so we must remove it first. - // E.g., "[#​1770](...)" becomes "[#1770](...)" - originalContent = originalContent.replace(/​/g, ''); - - // STEP 2: PROTECT THE OUTPUT. - // `release-please` aggressively tries to auto-link any text that looks like `#1234`. - // To prevent this, we insert an invisible Unicode zero-width space (`\u200B`) - // between the '#' and the number in the link text. This breaks the parser's - // pattern matching without changing the visual appearance of the link. - // E.g., "[#1770](...)" becomes "[mcp-toolbox#​1770](...)" - originalContent = originalContent.replace(/\[#(\d+)\](\([^)]+\))/g, '[mcp-toolbox#\u200B$1]$2'); - - const lineAsLowerCase = originalContent.toLowerCase(); - const hasPrefix = prefixesToFilter.some(prefix => lineAsLowerCase.includes(prefix)); - - // Check if the line includes ANY of the required keywords - let hasAnyRequiredKeyword = false; - if (requiredKeywords.length > 0) { - hasAnyRequiredKeyword = requiredKeywords.some(keyword => lineAsLowerCase.includes(keyword)); - } - - // Include if it doesn't have a prefix OR it has any of the required keywords - if (!hasPrefix || hasAnyRequiredKeyword) { - newChangelog.push(`${currentType}: ${originalContent}`); - } else { - console.log(`Filtering out: ${originalContent}`); - } - } - } - - if (newChangelog.length === 0) { - console.log('Found no changelog items to add after filtering. Exiting.'); - return; - } - - // Construct the override block - const overrideBlock = [ - '\n\nBEGIN_COMMIT_OVERRIDE', - ...newChangelog, - 'END_COMMIT_OVERRIDE' - ].join('\n'); - - // Update PR body - const baseBody = prBody.split('\n\nBEGIN_COMMIT_OVERRIDE')[0].trim(); - const finalBody = baseBody + overrideBlock; - - if (finalBody === prBody) { - console.log('The generated changelog is identical. No update needed.'); - return; - } - - // Update the PR - await github.rest.pulls.update({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - body: finalBody, - }); - - console.log('Successfully updated the PR body with filtered release notes.'); diff --git a/DEVELOPER.md b/DEVELOPER.md index 517b701..346ba6b 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -96,39 +96,7 @@ The primary maintainers for this repository are defined in the ### Releasing -The release process is automated using `release-please`. It consists of an automated changelog preparation step followed by the manual merging of a Release PR. - -#### Automated Changelog Enrichment - -Before a Release PR is even created, a special workflow automatically mirrors -relevant changelogs from the core `googleapis/genai-toolbox` dependency. This -ensures that the release notes for this extension accurately reflect important -upstream changes. - -The process is handled by the [`mirror-changelog.yml`](.github/workflows/mirror-changelog.yml) workflow: - -1. **Trigger:** The workflow runs automatically on pull requests created by - Renovate for `toolbox` version updates. -2. **Parsing:** It reads the detailed release notes that Renovate includes in - the PR body. -3. **Filtering:** These release notes are filtered to include only changes - relevant to this extension. The relevance is determined by a keyword (e.g., - `postgres`), passed as an environment variable in the workflow file. -4. **Changelog Injection:** The script formats the filtered entries as - conventional commits and injects them into the PR body within a - `BEGIN_COMMIT_OVERRIDE` block. -5. **Release Please:** When the main Release PR is created, `release-please` - reads this override block instead of the standard `chore(deps): ...` commit - message, effectively mirroring the filtered upstream changelog into this - project's release notes. - -> **Note for Maintainers:** The filtering script is an automation aid, but it -> may occasionally produce "false positives" (e.g., an internal logging change -> that happens to contain the keyword). Before merging a `toolbox` dependency -> PR, maintainers must **review the generated `BEGIN_COMMIT_OVERRIDE` block** -> and manually delete any lines that are not relevant to the end-users of this -> extension. The curated override block is the final source of truth for the -> release changelog. +The release process is automated using `release-please`. It consists of the manual merging of a Release PR. #### Release Process