diff --git a/.github/workflows/copy-issues-labels.yml b/.github/workflows/copy-issues-labels.yml new file mode 100644 index 0000000000..4701840475 --- /dev/null +++ b/.github/workflows/copy-issues-labels.yml @@ -0,0 +1,105 @@ +name: Copy issues labels to pull request + +on: + workflow_dispatch: + inputs: + pr_number: + description: Pull request number + required: true + type: string + issues: + description: JSON encoded list of issue ids + required: true + type: string + +jobs: + run: + name: Run + runs-on: ubuntu-latest + steps: + - name: Find unique labels + id: find_unique_labels + uses: actions/github-script@v7 + env: + ISSUES: ${{ inputs.issues }} + with: + script: | + const issues = JSON.parse(process.env.ISSUES); + + const WHITE_LISTED_LABELS = [ + 'client feature', + 'feature', + + 'bug', + + 'dependencies', + 'performance', + + 'chore', + 'enhancement', + 'refactoring', + 'tech', + ] + + const labels = await Promise.all(issues.map(getIssueLabels)); + const uniqueLabels = uniqueStringArray(labels.flat().filter((label) => WHITE_LISTED_LABELS.includes(label))); + + if (uniqueLabels.length === 0) { + core.info('No labels found.\n'); + return []; + } + + core.info(`Found following labels: ${ uniqueLabels.join(', ') }.\n`); + return uniqueLabels; + + async function getIssueLabels(issue) { + core.info(`Obtaining labels list for the issue #${ issue }...`); + + try { + const response = await octokit.request('GET /repos/{owner}/{repo}/issues/{issue_number}/labels', { + owner: 'blockscout', + repo: 'frontend', + issue_number: issue, + }); + return response.data.map(({ name }) => name); + } catch (error) { + core.error(`Failed to obtain labels for the issue #${ issue }: ${ error.message }`); + return []; + } + } + + function uniqueStringArray(array) { + return Array.from(new Set(array)); + } + + - name: Update pull request labels + id: update_pr_labels + uses: actions/github-script@v7 + env: + LABELS: ${{ steps.find_unique_labels.outputs.result }} + PR_NUMBER: ${{ inputs.pr_number }} + with: + script: | + const labels = JSON.parse(process.env.LABELS); + const prNumber = Number(process.env.PR_NUMBER); + + if (labels.length === 0) { + core.info('Nothing to update.\n'); + return; + } + + for (const label of labels) { + await addLabelToPr(prNumber, label); + } + core.info('Done.\n'); + + async function addLabelToPr(prNumber, label) { + console.log(`Adding label to the pull request #${ prNumber }...`); + + return await octokit.request('POST /repos/{owner}/{repo}/issues/{issue_number}/labels', { + owner: 'blockscout', + repo: 'frontend', + issue_number: prNumber, + labels: [ label ], + }); + } \ No newline at end of file diff --git a/.github/workflows/project-management.yml b/.github/workflows/project-management.yml index ce53245267..1da733baeb 100644 --- a/.github/workflows/project-management.yml +++ b/.github/workflows/project-management.yml @@ -28,7 +28,7 @@ jobs: issues: "[${{ github.event.issue.number }}]" secrets: inherit - review_requested_issues: + pr_linked_issues: name: Get issues linked to PR runs-on: ubuntu-latest if: ${{ github.event.pull_request && github.event.action == 'review_requested' }} @@ -76,14 +76,24 @@ jobs: return issues; - review_requested_tasks: + issues_in_review: name: Update status for issues in review - needs: [ review_requested_issues ] - if: ${{ needs.review_requested_issues.outputs.issues }} + needs: [ pr_linked_issues ] + if: ${{ needs.pr_linked_issues.outputs.issues }} uses: './.github/workflows/update-project-cards.yml' secrets: inherit with: project_name: ${{ vars.PROJECT_NAME }} field_name: Status field_value: Review - issues: ${{ needs.review_requested_issues.outputs.issues }} + issues: ${{ needs.pr_linked_issues.outputs.issues }} + + copy_labels: + name: Copy issues labels to pull request + needs: [ pr_linked_issues ] + if: ${{ needs.pr_linked_issues.outputs.issues }} + uses: './.github/workflows/copy-issues-labels.yml' + secrets: inherit + with: + pr_number: ${{ github.event.pull_request.number }} + issues: ${{ needs.pr_linked_issues.outputs.issues }}