diff --git a/.github/scripts/bot-pr-missing-linked-issue.js b/.github/scripts/bot-pr-missing-linked-issue.js index ec8f9764c..4e0726f08 100644 --- a/.github/scripts/bot-pr-missing-linked-issue.js +++ b/.github/scripts/bot-pr-missing-linked-issue.js @@ -1,28 +1,46 @@ module.exports = async ({ github, context }) => { - const body = context.payload.pull_request.body || ""; - const regex = /\bFixes\s*:?\s*(#\d+)(\s*,\s*#\d+)*/i; + let prNumber; + try { + const isDryRun = process.env.DRY_RUN === 'true'; + prNumber = parseInt(process.env.PR_NUMBER) || context.payload.pull_request.number; + + console.log(`Processing PR #${prNumber} (Dry run: ${isDryRun})`); + + // For workflow_dispatch, we need to fetch PR details + let prData; + if (context.payload.pull_request) { + prData = context.payload.pull_request; + } else { + // workflow_dispatch case - fetch PR data + const prResponse = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + prData = prResponse.data; + } - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - }); + const body = prData.body || ""; + const regex = /\bFixes\s*:?\s*(#\d+)(\s*,\s*#\d+)*/i; - const alreadyCommented = comments.data.some(comment => - comment.body.includes("this is LinkBot") - ); - - if (alreadyCommented) { - return; - } - - if (!regex.test(body)) { - await github.rest.issues.createComment({ + const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: [ - `Hi @${context.payload.pull_request.user.login}, this is **LinkBot** 👋`, + issue_number: prNumber, + }); + + const alreadyCommented = comments.data.some(comment => + comment.body.includes("this is LinkBot") + ); + + if (alreadyCommented) { + console.log('LinkBot already commented on this PR'); + return; + } + + if (!regex.test(body)) { + const commentBody = [ + `Hi @${prData.user.login}, this is **LinkBot** 👋`, ``, `Linking pull requests to issues helps us significantly with reviewing pull requests and keeping the repository healthy.`, ``, @@ -38,8 +56,30 @@ module.exports = async ({ github, context }) => { `[docs/sdk_developers/creating_issues.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/docs/sdk_developers/creating_issues.md)`, ``, `Thanks!` - ].join('\n') - }); + ].join('\n'); + + if (isDryRun) { + console.log('DRY RUN: Would post the following comment:'); + console.log('---'); + console.log(commentBody); + console.log('---'); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: commentBody, + }); + console.log('LinkBot comment posted successfully'); + } + } else { + console.log('PR has linked issue - no comment needed'); + } + } catch (error) { + console.error('Error processing PR:', error); + console.error('PR number:', prNumber); + console.error('Repository:', `${context.repo.owner}/${context.repo.repo}`); + throw error; } }; diff --git a/.github/workflows/bot-pr-missing-linked-issue.yml b/.github/workflows/bot-pr-missing-linked-issue.yml index baea7362f..fd39c4431 100644 --- a/.github/workflows/bot-pr-missing-linked-issue.yml +++ b/.github/workflows/bot-pr-missing-linked-issue.yml @@ -1,19 +1,34 @@ +# This workflow checks PRs for linked issues and posts a reminder comment if missing. +# Uses pull_request_target to enable write permissions for fork PRs while checking out +# only the base branch code (ref: main) to avoid executing untrusted fork code. name: PR Missing Linked Issue Reminder on: - pull_request: + pull_request_target: types: [opened, edited, reopened] + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to check' + required: true + type: number + dry_run: + description: 'Dry run (only log, no comments)' + required: false + type: boolean + default: true permissions: pull-requests: write contents: read + issues: write jobs: check-linked-issue: runs-on: ubuntu-latest concurrency: - group: bot-pr-missing-linked-issue-${{ github.event.pull_request.number }} + group: bot-pr-missing-linked-issue-${{ github.event.pull_request.number || github.event.inputs.pr_number }} cancel-in-progress: true steps: @@ -24,10 +39,14 @@ jobs: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + ref: main - name: Check PR body for linked issue env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} + PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }} uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | diff --git a/CHANGELOG.md b/CHANGELOG.md index ba152e27d..9e2706a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -155,6 +155,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. - Workflow does not contain permissions for `pr-check-test-files` and `pr-check-codecov` - Fixed `cron-check-broken-links.yml` string parsing issue in context input `dry_run` (#1235) - Flaky tests by disabling TLS in mock Hedera nodes in `mock_server.py` +- Fixed LinkBot permission issue for fork PRs by changing trigger to pull_request_target and adding proper permissions. ### Breaking Change