From 27ea43fe2fed7418f91c282b64469c632a2d4da8 Mon Sep 17 00:00:00 2001 From: aditya singh rathore Date: Wed, 15 Oct 2025 16:13:50 +0530 Subject: [PATCH 1/6] Added workflow for the PR --- .github/workflows/autolabel-pr-issue.yml | 130 +++++++++++++++++++++++ .github/workflows/autolabler.yml | 4 +- 2 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/autolabel-pr-issue.yml diff --git a/.github/workflows/autolabel-pr-issue.yml b/.github/workflows/autolabel-pr-issue.yml new file mode 100644 index 00000000..29ffdb59 --- /dev/null +++ b/.github/workflows/autolabel-pr-issue.yml @@ -0,0 +1,130 @@ +name: Auto Label PR from Linked Issue + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: write + issues: read + +jobs: + label-pr: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Extract Issue Numbers from PR Body + id: extract-issues + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const prBody = context.payload.pull_request.body || ''; + const prTitle = context.payload.pull_request.title || ''; + + // Regex patterns to find linked issues + // Matches: #123, fixes #123, closes #123, resolves #123, etc. + const patterns = [ + /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi, + /#(\d+)/g + ]; + + const issueNumbers = new Set(); + + // Search in PR body and title + const textToSearch = prBody + ' ' + prTitle; + + patterns.forEach(pattern => { + const matches = [...textToSearch.matchAll(pattern)]; + matches.forEach(match => { + issueNumbers.add(match[1]); + }); + }); + + const issues = Array.from(issueNumbers); + console.log('Found linked issues:', issues); + + // Return as JSON string + return JSON.stringify(issues); + + - name: Get Labels from Linked Issues + id: get-labels + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const issueNumbers = JSON.parse('${{ steps.extract-issues.outputs.result }}'); + + // Labels to exclude from being applied to PRs + const excludedLabels = ['recode', 'hacktoberfest-accepted']; + + if (!issueNumbers || issueNumbers.length === 0) { + console.log('No linked issues found'); + return JSON.stringify([]); + } + + const allLabels = new Set(); + + for (const issueNumber of issueNumbers) { + try { + const issue = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber) + }); + + console.log(`Issue #${issueNumber} labels:`, issue.data.labels.map(l => l.name)); + + issue.data.labels.forEach(label => { + // Only add label if it's not in the excluded list + if (!excludedLabels.includes(label.name.toLowerCase())) { + allLabels.add(label.name); + } else { + console.log(`Excluding label: ${label.name}`); + } + }); + } catch (error) { + console.log(`Could not fetch issue #${issueNumber}:`, error.message); + } + } + + const labels = Array.from(allLabels); + console.log('All labels to apply:', labels); + + return JSON.stringify(labels); + + - name: Apply Labels to PR + uses: actions/github-script@v7 + with: + script: | + const labels = ${{ steps.get-labels.outputs.result }}; + + if (!labels || labels.length === 0) { + console.log('No labels to apply'); + return; + } + + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + labels: labels + }); + + console.log(`Successfully applied ${labels.length} labels to PR #${context.payload.pull_request.number}`); + + // Add a comment to the PR + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body: `🏷️ Labels automatically applied from linked issue(s): ${labels.map(l => `\`${l}\``).join(', ')}` + }); + } catch (error) { + console.error('Error applying labels:', error.message); + core.setFailed(`Failed to apply labels: ${error.message}`); + } \ No newline at end of file diff --git a/.github/workflows/autolabler.yml b/.github/workflows/autolabler.yml index 36ea4bed..c93a9e50 100644 --- a/.github/workflows/autolabler.yml +++ b/.github/workflows/autolabler.yml @@ -24,10 +24,10 @@ jobs: await github.rest.issues.addLabels({ ...context.repo, issue_number: prNumber, - labels: ["recode", "level 1", "hacktoberfest-accepted"] + labels: ["recode","hacktoberfest-accepted"] }); - console.log(`Added labels [recode, level 1, hacktoberfest-accepted] to PR #${prNumber}`); + console.log(`Added labels [recode, hacktoberfest-accepted] to PR #${prNumber}`); - name: Add labels to Issue if: github.event_name == 'issues' From 8e0601e3131c2693581de455754887f28d99b68b Mon Sep 17 00:00:00 2001 From: aditya singh rathore Date: Wed, 15 Oct 2025 16:17:52 +0530 Subject: [PATCH 2/6] fix --- .github/workflows/autolabel-pr-issue.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/autolabel-pr-issue.yml b/.github/workflows/autolabel-pr-issue.yml index 29ffdb59..23759ff9 100644 --- a/.github/workflows/autolabel-pr-issue.yml +++ b/.github/workflows/autolabel-pr-issue.yml @@ -20,6 +20,7 @@ jobs: id: extract-issues uses: actions/github-script@v7 with: + github-token: ${{ secrets.GITHUB_TOKEN }} result-encoding: string script: | const prBody = context.payload.pull_request.body || ''; @@ -54,6 +55,7 @@ jobs: id: get-labels uses: actions/github-script@v7 with: + github-token: ${{ secrets.GITHUB_TOKEN }} result-encoding: string script: | const issueNumbers = JSON.parse('${{ steps.extract-issues.outputs.result }}'); @@ -99,6 +101,7 @@ jobs: - name: Apply Labels to PR uses: actions/github-script@v7 with: + github-token: ${{ secrets.GITHUB_TOKEN }} script: | const labels = ${{ steps.get-labels.outputs.result }}; From 1d6eefd51975eaa85f742d9e3974edfaf9a2463f Mon Sep 17 00:00:00 2001 From: aditya singh rathore Date: Wed, 15 Oct 2025 16:19:53 +0530 Subject: [PATCH 3/6] fix --- .github/workflows/autolabel-pr-issue.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/autolabel-pr-issue.yml b/.github/workflows/autolabel-pr-issue.yml index 23759ff9..4a485fd4 100644 --- a/.github/workflows/autolabel-pr-issue.yml +++ b/.github/workflows/autolabel-pr-issue.yml @@ -6,7 +6,8 @@ on: permissions: pull-requests: write - issues: read + issues: write + contents: read jobs: label-pr: From 8059d6c0e1f5ce61d3c660a9e69c9fe18dfdc8a2 Mon Sep 17 00:00:00 2001 From: aditya singh rathore Date: Wed, 15 Oct 2025 16:23:20 +0530 Subject: [PATCH 4/6] fix --- .github/workflows/autolabel-pr-issue.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autolabel-pr-issue.yml b/.github/workflows/autolabel-pr-issue.yml index 4a485fd4..d7c7e85e 100644 --- a/.github/workflows/autolabel-pr-issue.yml +++ b/.github/workflows/autolabel-pr-issue.yml @@ -1,7 +1,7 @@ name: Auto Label PR from Linked Issue on: - pull_request: + pull_request_target: types: [opened, edited, synchronize, reopened] permissions: From 8e358cb3658439acd69e471d065e663270076017 Mon Sep 17 00:00:00 2001 From: aditya singh rathore Date: Wed, 15 Oct 2025 16:28:35 +0530 Subject: [PATCH 5/6] final fix --- .github/workflows/autolabel-pr-issue.yml | 88 ++++++------------------ 1 file changed, 20 insertions(+), 68 deletions(-) diff --git a/.github/workflows/autolabel-pr-issue.yml b/.github/workflows/autolabel-pr-issue.yml index d7c7e85e..e2908877 100644 --- a/.github/workflows/autolabel-pr-issue.yml +++ b/.github/workflows/autolabel-pr-issue.yml @@ -1,7 +1,7 @@ name: Auto Label PR from Linked Issue on: - pull_request_target: + pull_request_target: types: [opened, edited, synchronize, reopened] permissions: @@ -12,11 +12,8 @@ permissions: jobs: label-pr: runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 + steps: - name: Extract Issue Numbers from PR Body id: extract-issues uses: actions/github-script@v7 @@ -26,31 +23,19 @@ jobs: script: | const prBody = context.payload.pull_request.body || ''; const prTitle = context.payload.pull_request.title || ''; - - // Regex patterns to find linked issues - // Matches: #123, fixes #123, closes #123, resolves #123, etc. const patterns = [ /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi, /#(\d+)/g ]; - const issueNumbers = new Set(); - - // Search in PR body and title const textToSearch = prBody + ' ' + prTitle; - patterns.forEach(pattern => { const matches = [...textToSearch.matchAll(pattern)]; matches.forEach(match => { - issueNumbers.add(match[1]); + if (/^\d+$/.test(match[1])) issueNumbers.add(match[1]); }); }); - - const issues = Array.from(issueNumbers); - console.log('Found linked issues:', issues); - - // Return as JSON string - return JSON.stringify(issues); + return JSON.stringify([...issueNumbers]); - name: Get Labels from Linked Issues id: get-labels @@ -60,17 +45,9 @@ jobs: result-encoding: string script: | const issueNumbers = JSON.parse('${{ steps.extract-issues.outputs.result }}'); - - // Labels to exclude from being applied to PRs const excludedLabels = ['recode', 'hacktoberfest-accepted']; - - if (!issueNumbers || issueNumbers.length === 0) { - console.log('No linked issues found'); - return JSON.stringify([]); - } - const allLabels = new Set(); - + for (const issueNumber of issueNumbers) { try { const issue = await github.rest.issues.get({ @@ -78,57 +55,32 @@ jobs: repo: context.repo.repo, issue_number: parseInt(issueNumber) }); - - console.log(`Issue #${issueNumber} labels:`, issue.data.labels.map(l => l.name)); - - issue.data.labels.forEach(label => { - // Only add label if it's not in the excluded list - if (!excludedLabels.includes(label.name.toLowerCase())) { + for (const label of issue.data.labels) { + if (!excludedLabels.includes(label.name.toLowerCase())) allLabels.add(label.name); - } else { - console.log(`Excluding label: ${label.name}`); - } - }); + } } catch (error) { console.log(`Could not fetch issue #${issueNumber}:`, error.message); } } - - const labels = Array.from(allLabels); - console.log('All labels to apply:', labels); - - return JSON.stringify(labels); + + return JSON.stringify([...allLabels]); - name: Apply Labels to PR uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const labels = ${{ steps.get-labels.outputs.result }}; - - if (!labels || labels.length === 0) { + const labels = JSON.parse('${{ steps.get-labels.outputs.result }}') + .filter(l => typeof l === 'string' && l.trim() !== ''); + if (labels.length === 0) { console.log('No labels to apply'); return; } - - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - labels: labels - }); - - console.log(`Successfully applied ${labels.length} labels to PR #${context.payload.pull_request.number}`); - - // Add a comment to the PR - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: `🏷️ Labels automatically applied from linked issue(s): ${labels.map(l => `\`${l}\``).join(', ')}` - }); - } catch (error) { - console.error('Error applying labels:', error.message); - core.setFailed(`Failed to apply labels: ${error.message}`); - } \ No newline at end of file + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + labels + }); + console.log(`Applied labels: ${labels.join(', ')}`); From de1b4bea960a5cc14c81635e7cd74de6e37406a2 Mon Sep 17 00:00:00 2001 From: aditya singh rathore Date: Wed, 15 Oct 2025 16:49:00 +0530 Subject: [PATCH 6/6] Added a fix --- .github/workflows/autolabel-pr-issue.yml | 198 +++++++++++++++++++---- 1 file changed, 165 insertions(+), 33 deletions(-) diff --git a/.github/workflows/autolabel-pr-issue.yml b/.github/workflows/autolabel-pr-issue.yml index e2908877..00823215 100644 --- a/.github/workflows/autolabel-pr-issue.yml +++ b/.github/workflows/autolabel-pr-issue.yml @@ -1,7 +1,7 @@ name: Auto Label PR from Linked Issue on: - pull_request_target: + pull_request_target: types: [opened, edited, synchronize, reopened] permissions: @@ -12,8 +12,11 @@ permissions: jobs: label-pr: runs-on: ubuntu-latest - + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Extract Issue Numbers from PR Body id: extract-issues uses: actions/github-script@v7 @@ -21,21 +24,69 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} result-encoding: string script: | - const prBody = context.payload.pull_request.body || ''; - const prTitle = context.payload.pull_request.title || ''; - const patterns = [ - /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi, - /#(\d+)/g - ]; - const issueNumbers = new Set(); - const textToSearch = prBody + ' ' + prTitle; - patterns.forEach(pattern => { - const matches = [...textToSearch.matchAll(pattern)]; - matches.forEach(match => { - if (/^\d+$/.test(match[1])) issueNumbers.add(match[1]); + let prNumber, prBody, prTitle; + + // Check if triggered by issue event + if (context.eventName === 'issues') { + // Find all open PRs that link to this issue + const issueNumber = context.payload.issue.number; + console.log(`Issue #${issueNumber} labels were updated`); + + // Search for PRs that mention this issue + const { data: pullRequests } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open' + }); + + const linkedPRs = []; + for (const pr of pullRequests) { + const prText = `${pr.title} ${pr.body || ''}`; + const patterns = [ + new RegExp(`(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\s+#${issueNumber}\\b`, 'i'), + new RegExp(`#${issueNumber}\\b`) + ]; + + if (patterns.some(p => p.test(prText))) { + linkedPRs.push(pr.number); + } + } + + if (linkedPRs.length === 0) { + console.log('No linked PRs found for this issue'); + return JSON.stringify({ prs: [], issue: issueNumber }); + } + + console.log(`Found linked PRs: ${linkedPRs.join(', ')}`); + return JSON.stringify({ prs: linkedPRs, issue: issueNumber }); + } else { + // Triggered by PR event - original logic + prBody = context.payload.pull_request.body || ''; + prTitle = context.payload.pull_request.title || ''; + + const patterns = [ + /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi, + /#(\d+)/g + ]; + + const issueNumbers = new Set(); + const textToSearch = prBody + ' ' + prTitle; + + patterns.forEach(pattern => { + const matches = [...textToSearch.matchAll(pattern)]; + matches.forEach(match => { + issueNumbers.add(match[1]); + }); + }); + + const issues = Array.from(issueNumbers); + console.log('Found linked issues:', issues); + + return JSON.stringify({ + prs: [context.payload.pull_request.number], + issues: issues }); - }); - return JSON.stringify([...issueNumbers]); + } - name: Get Labels from Linked Issues id: get-labels @@ -44,10 +95,32 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} result-encoding: string script: | - const issueNumbers = JSON.parse('${{ steps.extract-issues.outputs.result }}'); + const extractData = JSON.parse('${{ steps.extract-issues.outputs.result }}'); + + // Labels to exclude from being applied to PRs const excludedLabels = ['recode', 'hacktoberfest-accepted']; + + let issueNumbers = []; + let prsToUpdate = []; + + // Handle both PR and issue events + if (extractData.issue) { + // Issue event - update all linked PRs + issueNumbers = [extractData.issue]; + prsToUpdate = extractData.prs || []; + } else { + // PR event - update the current PR + issueNumbers = extractData.issues || []; + prsToUpdate = extractData.prs || []; + } + + if (!issueNumbers || issueNumbers.length === 0) { + console.log('No linked issues found'); + return JSON.stringify({ labels: [], prs: prsToUpdate }); + } + const allLabels = new Set(); - + for (const issueNumber of issueNumbers) { try { const issue = await github.rest.issues.get({ @@ -55,32 +128,91 @@ jobs: repo: context.repo.repo, issue_number: parseInt(issueNumber) }); - for (const label of issue.data.labels) { - if (!excludedLabels.includes(label.name.toLowerCase())) + + console.log(`Issue #${issueNumber} labels:`, issue.data.labels.map(l => l.name)); + + issue.data.labels.forEach(label => { + // Only add label if it's not in the excluded list + if (!excludedLabels.includes(label.name.toLowerCase())) { allLabels.add(label.name); - } + } else { + console.log(`Excluding label: ${label.name}`); + } + }); } catch (error) { console.log(`Could not fetch issue #${issueNumber}:`, error.message); } } - - return JSON.stringify([...allLabels]); + + const labels = Array.from(allLabels); + console.log('All labels to apply:', labels); + + return JSON.stringify({ labels: labels, prs: prsToUpdate }); - name: Apply Labels to PR uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const labels = JSON.parse('${{ steps.get-labels.outputs.result }}') - .filter(l => typeof l === 'string' && l.trim() !== ''); - if (labels.length === 0) { + const data = JSON.parse('${{ steps.get-labels.outputs.result }}'); + const labels = data.labels || []; + const prsToUpdate = data.prs || []; + + if (!labels || labels.length === 0) { console.log('No labels to apply'); return; } - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - labels - }); - console.log(`Applied labels: ${labels.join(', ')}`); + + if (!prsToUpdate || prsToUpdate.length === 0) { + console.log('No PRs to update'); + return; + } + + // Update each PR + for (const prNumber of prsToUpdate) { + try { + // First, get current PR labels + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber + }); + + // Remove all existing labels first (to handle removed issue labels) + const currentLabels = pr.labels.map(l => l.name); + if (currentLabels.length > 0) { + for (const label of currentLabels) { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + name: label + }); + } catch (e) { + console.log(`Could not remove label ${label}: ${e.message}`); + } + } + } + + // Apply new labels + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: labels + }); + + console.log(`Successfully applied ${labels.length} labels to PR #${prNumber}`); + + // Add a comment to the PR + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `🏷️ Labels automatically synced from linked issue(s): ${labels.map(l => `\`${l}\``).join(', ')}` + }); + } catch (error) { + console.error(`Error updating PR #${prNumber}:`, error.message); + } + } \ No newline at end of file