name: Comment on issue when it is closed automatically on: issues: types: [closed] jobs: comment-on-issue-closure: runs-on: ubuntu-latest steps: - name: Generate GitHub App token id: generate-token uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 with: app-id: ${{ secrets.BOT_APP_ID }} private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} - name: Check if issue was closed by commit id: check-commit uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: github-token: ${{ steps.generate-token.outputs.token }} script: | const issueNumber = context.payload.issue.number; // Get the issue events to find the "closed" event with commit_id const { data: events } = await github.rest.issues.listEvents({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issueNumber }); // Find the most recent "closed" event const closedEvent = events .filter(event => event.event === 'closed') .pop(); // Get the last (most recent) closed event // Find the most recent "referenced" event const referencedEvent = events .filter(event => event.event === 'referenced') .pop(); // Get the last (most recent) referenced event console.log({closedEvent, referencedEvent}); if (closedEvent && (closedEvent.commit_id || referencedEvent)) { const commitId = closedEvent.commit_id ?? referencedEvent.commit_id console.log(`✅ Issue #${issueNumber} was closed by commit: ${commitId}`); // Get commit details const { data: commit } = await github.rest.git.getCommit({ owner: context.repo.owner, repo: context.repo.repo, commit_sha: commitId }); core.setOutput('closed_by_commit', 'true'); core.setOutput('commit_sha', commitId); // Escape backslashes, backticks and ${ to prevent breaking JS template strings const escapedMessage = commit.message.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${'); core.setOutput('commit_message', escapedMessage); core.setOutput('commit_url', closedEvent.commit_url); } else { console.log(`â„šī¸ Issue #${issueNumber} was closed manually (not by commit)`); core.setOutput('closed_by_commit', 'false'); } - name: Determine closure method and comment on issue if: steps.check-commit.outputs.closed_by_commit == 'true' uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: github-token: ${{ steps.generate-token.outputs.token }} script: | const issueNumber = context.payload.issue.number; const commitSha = '${{ steps.check-commit.outputs.commit_sha }}'; const commitMessage = `${{ steps.check-commit.outputs.commit_message }}`; const commitUrl = '${{ steps.check-commit.outputs.commit_url }}'; try { // Find PRs that include this commit const { data: prs } = await github.rest.pulls.list({ owner: context.repo.owner, repo: context.repo.repo, state: 'all', sort: 'updated', direction: 'desc', per_page: 100 }); let closingPR = null; // Check each PR to see if it contains our commit for (const pr of prs) { try { const { data: commits } = await github.rest.pulls.listCommits({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number }); if (commits.some(commit => commit.sha === commitSha)) { closingPR = pr; console.log(`✅ Found PR #${pr.number} containing commit ${commitSha.substring(0, 7)}`); break; } } catch (error) { console.log(`Error checking commits for PR #${pr.number}: ${error.message}`); } } // If no PR found with the exact commit, try alternative approaches if (!closingPR) { console.log(`🔍 No PR found with exact commit ${commitSha.substring(0, 7)}, trying alternative search...`); // Try to find a merged PR that mentions this issue const relatedPRs = prs.filter(pr => pr.state === 'closed' && pr.merged_at && (pr.title.includes(`#${issueNumber}`) || pr.body?.includes(`#${issueNumber}`)) ); if (relatedPRs.length > 0) { closingPR = relatedPRs[0]; console.log(`✅ Found related PR #${closingPR.number} that mentions issue #${issueNumber}`); } } const closedRef = closingPR ? `#${closingPR.number}` : `[\`${commitSha.substring(0, 7)}\`](${commitUrl})` const comment = `This issue has been fixed in ${closedRef}, please check with the next unstable build (should be ready for deployment in ~30min, also on [the demo](https://try.vikunja.io)).` await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issueNumber, body: comment, }); if (closingPR) { console.log(`✅ Added comment to issue #${issueNumber} (closed by PR #${closingPR.number})`); } else { console.log(`✅ Added comment to issue #${issueNumber} (closed by direct commit ${commitSha.substring(0, 7)})`); } } catch (error) { console.error(`❌ Error processing issue #${issueNumber}: ${error.message}`); throw error; }