rarajes2 triggered release comment bot #46
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Release Comment Bot | |
| run-name: ${{ github.actor }} triggered release comment bot | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| test_version: | |
| description: 'Test version number (e.g., 3.4.0)' | |
| required: false | |
| default: '3.4.0' | |
| test_pr_number: | |
| description: 'Test PR number (e.g., 2) - leave empty to auto-detect' | |
| required: false | |
| default: '' | |
| workflow_run: | |
| workflows: ["Deploy CD"] | |
| types: | |
| - completed | |
| branches: | |
| - next | |
| jobs: | |
| comment-on-prs: | |
| name: Comment on Released PRs | |
| runs-on: ubuntu-latest | |
| # Only run if manually triggered or Deploy CD succeeded | |
| if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v3 | |
| with: | |
| fetch-depth: 0 # Fetch all history to find commits | |
| - name: Get Version and PR from Tag | |
| id: tag-info | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.test_version }}" | |
| PR_NUMBER="${{ github.event.inputs.test_pr_number }}" | |
| echo "π§ͺ TEST MODE: version=${VERSION}, pr=${PR_NUMBER}" | |
| else | |
| git fetch --tags | |
| VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| if [ -z "$VERSION" ]; then | |
| echo "β No tags found" | |
| exit 1 | |
| fi | |
| TAG_MESSAGE=$(git tag -l --format='%(contents:subject)' "$VERSION") | |
| PR_NUMBER=$(echo "$TAG_MESSAGE" | grep -oE '#[0-9]+' | head -1 | tr -d '#') | |
| echo "π¦ Tag: ${VERSION}, PR: #${PR_NUMBER}" | |
| fi | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT | |
| echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT | |
| - name: Get Packages from PR | |
| id: get-prs | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const prNumber = '${{ steps.tag-info.outputs.pr_number }}'; | |
| if (!prNumber) { | |
| console.log('β No PR number found from tag, skipping'); | |
| core.setOutput('pr_numbers', JSON.stringify([])); | |
| core.setOutput('packages', JSON.stringify([])); | |
| core.setOutput('package_versions', JSON.stringify({})); | |
| core.setOutput('primary_package', ''); | |
| core.setOutput('primary_package_version', ''); | |
| core.setOutput('commit_count', '0'); | |
| return { prs: [], packages: [] }; | |
| } | |
| console.log(`β Using PR #${prNumber} from tag`); | |
| const { packages, packageVersions, primaryPackage, primaryPackageVersion } = | |
| await getPackagesForPr(prNumber); | |
| core.setOutput('pr_numbers', JSON.stringify([prNumber])); | |
| core.setOutput('packages', JSON.stringify(packages)); | |
| core.setOutput('package_versions', JSON.stringify(packageVersions)); | |
| core.setOutput('primary_package', primaryPackage); | |
| core.setOutput('primary_package_version', primaryPackageVersion); | |
| core.setOutput('commit_count', '1'); | |
| return { prs: [prNumber], packages: packages }; | |
| async function getPackagesForPr(prNumber) { | |
| const packageSet = new Set(); | |
| try { | |
| const files = await github.paginate(github.rest.pulls.listFiles, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: parseInt(prNumber, 10), | |
| per_page: 100 | |
| }); | |
| for (const file of files) { | |
| const filename = file.filename; | |
| if (!filename.startsWith('packages/')) { | |
| continue; | |
| } | |
| const parts = filename.split('/'); | |
| if (parts[1] === '@webex' && parts.length >= 3) { | |
| packageSet.add(`@webex/${parts[2]}`); | |
| } else if (parts.length >= 2) { | |
| packageSet.add(parts[1]); | |
| } | |
| } | |
| } catch (error) { | |
| console.log(`Error listing PR files: ${error.message}`); | |
| } | |
| if (packageSet.size === 0) { | |
| packageSet.add('webex'); | |
| } | |
| const packages = Array.from(packageSet); | |
| const packageVersions = {}; | |
| for (const packageName of packages) { | |
| const packageJsonPath = packageName.startsWith('@webex/') | |
| ? path.join(process.env.GITHUB_WORKSPACE, 'packages', '@webex', packageName.split('/')[1], 'package.json') | |
| : path.join(process.env.GITHUB_WORKSPACE, 'packages', packageName, 'package.json'); | |
| try { | |
| const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); | |
| if (packageJson.version) { | |
| packageVersions[packageName] = packageJson.version; | |
| } | |
| } catch (error) { | |
| console.log(`Error reading ${packageJsonPath}: ${error.message}`); | |
| } | |
| } | |
| const primaryPackage = packages[0] || ''; | |
| const primaryPackageVersion = primaryPackage ? (packageVersions[primaryPackage] || '') : ''; | |
| return { packages, packageVersions, primaryPackage, primaryPackageVersion }; | |
| } | |
| - name: Post Release Comment on PR | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const version = '${{ steps.tag-info.outputs.version }}'; | |
| const versionNumber = '${{ steps.tag-info.outputs.version_number }}'; | |
| const stableVersion = versionNumber.replace(/-next\..*$/, ''); | |
| const prNumbersRaw = '${{ steps.get-prs.outputs.pr_numbers }}'; | |
| const packagesRaw = '${{ steps.get-prs.outputs.packages }}'; | |
| const packageVersionsRaw = '${{ steps.get-prs.outputs.package_versions }}'; | |
| const primaryPackage = '${{ steps.get-prs.outputs.primary_package }}'; | |
| const primaryPackageVersion = '${{ steps.get-prs.outputs.primary_package_version }}'; | |
| const prNumbers = prNumbersRaw ? JSON.parse(prNumbersRaw) : []; | |
| const packages = packagesRaw ? JSON.parse(packagesRaw) : []; | |
| const packageVersions = packageVersionsRaw ? JSON.parse(packageVersionsRaw) : {}; | |
| const prNumber = prNumbers[0]; | |
| console.log(`Posting comment to PR #${prNumber}`); | |
| if (prNumbers.length === 0) { | |
| console.log('No PRs found to comment on'); | |
| return; | |
| } | |
| // Build the changelog URL | |
| // If 'webex' package is in the list, use it. Otherwise use the first detected package. | |
| const hasWebexPackage = packages.includes('webex'); | |
| const changelogPackage = hasWebexPackage ? 'webex' : packages[0]; | |
| const changelogUrl = new URL('https://web-sdk.webex.com/changelog/'); | |
| changelogUrl.searchParams.set('stable_version', stableVersion); | |
| changelogUrl.searchParams.set('package', changelogPackage); | |
| changelogUrl.searchParams.set('version', versionNumber); | |
| console.log(`π¦ Changelog URL package: ${changelogPackage}`); | |
| console.log(`π¦ Changelog URL version: ${versionNumber}`); | |
| console.log(`π Full URL: ${changelogUrl.toString()}`); | |
| // Build the package list markdown | |
| const packageList = packages.slice(0, 5).map(p => `\`${p}\``).join(', '); | |
| const morePackages = packages.length > 5 ? ` and ${packages.length - 5} more` : ''; | |
| // Create the comment body | |
| const commentBody = [ | |
| '## π Your changes are now available!', | |
| '', | |
| `**Released in:** [\`${version}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${version})`, | |
| `**Packages updated:** ${packageList}${morePackages}`, | |
| '', | |
| `π **[View full changelog β](${changelogUrl})**`, | |
| '', | |
| `Thank you for your contribution!`, | |
| '', | |
| '---', | |
| `<sub>π€ This is an automated message. For questions, please refer to the [documentation](https://github.com/${context.repo.owner}/${context.repo.repo}#readme).</sub>` | |
| ].join('\n'); | |
| try { | |
| console.log(`Commenting on PR #${prNumber}`); | |
| // Check if PR exists and is merged | |
| let pr; | |
| try { | |
| pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: parseInt(prNumber) | |
| }); | |
| } catch (error) { | |
| console.log(`PR #${prNumber} not found or error: ${error.message}`); | |
| return; | |
| } | |
| if (!pr.data.merged_at) { | |
| console.log(`PR #${prNumber} is not merged, skipping`); | |
| return; | |
| } | |
| // Check if we've already commented (to avoid duplicates) | |
| const existingComments = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: parseInt(prNumber) | |
| }); | |
| const botCommentExists = existingComments.data.some(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('Your changes are now available') && | |
| comment.body.includes(version) | |
| ); | |
| if (botCommentExists) { | |
| console.log(`Already commented on PR #${prNumber} for version ${version}`); | |
| return; | |
| } | |
| // Post the comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: parseInt(prNumber), | |
| body: commentBody | |
| }); | |
| console.log(`β Successfully commented on PR #${prNumber}`); | |
| } catch (error) { | |
| console.error(`Failed to comment on PR #${prNumber}:`, error.message); | |
| } | |
| console.log('β¨ Comment posted successfully!'); | |