diff --git a/.github/workflows/lint-autofix.yml b/.github/workflows/lint-autofix.yml new file mode 100644 index 00000000000..dc6cc1a9be8 --- /dev/null +++ b/.github/workflows/lint-autofix.yml @@ -0,0 +1,145 @@ +name: Lint and Format Auto-fix + +on: + workflow_run: + workflows: [CI] + types: + - completed + +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + +jobs: + autofix: + # Only run on pull requests where lint or format failed + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'failure' + runs-on: ubuntu-latest + steps: + - name: Generate token + id: generate_token + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.PRIVATE_KEY }} + + - name: Get Pull Request + id: pr + uses: actions/github-script@5c56fde4671bc2d3592fb0f2c5b5bab9ddae03b1 + with: + script: | + const response = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: '${{ github.event.workflow_run.head_sha }}' + }); + + if (response.data.length === 0) { + core.info('No pull request found for this commit'); + return; + } + + const pr = response.data[0]; + core.setOutput('number', pr.number); + core.setOutput('head_ref', pr.head.ref); + core.setOutput('head_repo', pr.head.repo?.full_name || ''); + + - name: Check which jobs failed + id: check_jobs + uses: actions/github-script@5c56fde4671bc2d3592fb0f2c5b5bab9ddae03b1 + with: + script: | + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{ github.event.workflow_run.id }} + }); + + const lintJob = jobs.data.jobs.find(job => job.name === 'lint'); + const formatJob = jobs.data.jobs.find(job => job.name === 'format'); + + const lintFailed = lintJob && lintJob.conclusion === 'failure'; + const formatFailed = formatJob && formatJob.conclusion === 'failure'; + + core.setOutput('lint_failed', lintFailed ? 'true' : 'false'); + core.setOutput('format_failed', formatFailed ? 'true' : 'false'); + core.setOutput('should_fix', (lintFailed || formatFailed) ? 'true' : 'false'); + + if (lintFailed) { + core.info('Lint job failed, will attempt auto-fix'); + } + if (formatFailed) { + core.info('Format job failed, will attempt auto-fix'); + } + if (!lintFailed && !formatFailed) { + core.info('Neither lint nor format jobs failed'); + } + + - name: Checkout PR branch + if: steps.check_jobs.outputs.should_fix == 'true' && steps.pr.outputs.head_ref != '' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + repository: ${{ steps.pr.outputs.head_repo }} + ref: ${{ steps.pr.outputs.head_ref }} + token: ${{ steps.generate_token.outputs.token }} + fetch-depth: 0 + + - name: Set up Node.js + if: steps.check_jobs.outputs.should_fix == 'true' && steps.pr.outputs.head_ref != '' + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version-file: '.nvmrc' + cache: 'npm' + + - name: Install dependencies + if: steps.check_jobs.outputs.should_fix == 'true' && steps.pr.outputs.head_ref != '' + run: npm ci + + - name: Run format auto-fix + if: steps.check_jobs.outputs.format_failed == 'true' && steps.pr.outputs.head_ref != '' + run: npm run format + + - name: Run lint auto-fix + if: steps.check_jobs.outputs.lint_failed == 'true' && steps.pr.outputs.head_ref != '' + run: | + npm run lint:fix || true + npm run lint:css:fix || true + + - name: Commit and push changes + if: steps.check_jobs.outputs.should_fix == 'true' && steps.pr.outputs.head_ref != '' + uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 + with: + commit_message: 'chore: auto-fix lint and formatting issues' + commit_user_name: 'github-actions[bot]' + commit_user_email: 'github-actions[bot]@users.noreply.github.com' + + - name: Comment on PR + if: steps.check_jobs.outputs.should_fix == 'true' && steps.pr.outputs.number != '' + uses: actions/github-script@5c56fde4671bc2d3592fb0f2c5b5bab9ddae03b1 + with: + github-token: ${{ steps.generate_token.outputs.token }} + script: | + const lintFailed = '${{ steps.check_jobs.outputs.lint_failed }}' === 'true'; + const formatFailed = '${{ steps.check_jobs.outputs.format_failed }}' === 'true'; + + let message = '🤖 '; + if (lintFailed && formatFailed) { + message += 'Lint and formatting issues have been automatically fixed and committed to this PR.'; + } else if (lintFailed) { + message += 'Lint issues have been automatically fixed and committed to this PR.'; + } else if (formatFailed) { + message += 'Formatting issues have been automatically fixed and committed to this PR.'; + } + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ steps.pr.outputs.number }}, + body: message + });