Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions .github/workflows/lint-autofix.yml
Original file line number Diff line number Diff line change
@@ -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'
Comment on lines +19 to +22
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow will fail when attempting to auto-fix lint/format issues on pull requests from forks. When a PR comes from a fork, the GitHub App token won't have permission to push to the fork repository. The workflow should check if the PR is from a fork and skip execution in that case, similar to how other workflows in this repository handle forks (e.g., deploy_preview.yml checks github.event.pull_request.head.repo.full_name == 'primer/react').

Add a check in the job-level condition to skip fork PRs. You can check this by comparing the head repo with the base repo, or by adding a check in the "Get Pull Request" step to set an output indicating whether it's from a fork, then use that in subsequent step conditions.

Suggested change
# Only run on pull requests where lint or format failed
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'failure'
# Only run on pull requests from this repository where lint or format failed
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'failure' &&
github.event.workflow_run.head_repository.full_name == github.repository

Copilot uses AI. Check for mistakes.
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: |
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow doesn't run npm run lint:md auto-fix, but the CI workflow includes a markdown linting step (npm run lint:md in the lint job). While markdownlint-cli2 doesn't have a built-in --fix flag, if markdown linting failures can be auto-fixed in the future, this workflow should be updated to include those fixes as well. Consider adding a comment noting this limitation or investigating if there's a fix command available for markdown linting.

Suggested change
run: |
run: |
# Note: CI runs `npm run lint:md` for markdown linting, but markdownlint-cli2
# does not currently support auto-fix. If a markdown lint auto-fix command
# (e.g. `npm run lint:md:fix`) is added in the future, update this step to run it.

Copilot uses AI. Check for mistakes.
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
});
Comment on lines +122 to +145
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow will create a PR comment even when no fixes were actually committed. The git-auto-commit-action by default doesn't fail or skip when there are no changes to commit - it just doesn't create a commit. However, the "Comment on PR" step will still run and post a misleading message saying issues were fixed.

To fix this, you can capture the output from the git-auto-commit-action step (it sets a changes_detected output) and only run the comment step when changes were actually committed. For example:

  • Add an id to the "Commit and push changes" step
  • Update the "Comment on PR" condition to also check steps.commit_step_id.outputs.changes_detected == 'true'

Copilot uses AI. Check for mistakes.
Loading