Skip to content

feat(composer): support full bot configuration #402

feat(composer): support full bot configuration

feat(composer): support full bot configuration #402

name: Auto-fix Issues
on:
workflow_dispatch:
inputs:
target_branch:
description: "Branch to check out, fix, validate, and push"
required: true
default: "main"
fix_command:
description: "Command that applies repository fixes before validation"
required: true
default: "python scripts/fix_issues.py"
commit_message:
description: "Commit message for pushed fixes"
required: true
default: "chore: auto-fix issue triage"
issue_comment:
types: [created]
permissions:
contents: write
issues: read
pull-requests: read
concurrency:
group: auto-fix-${{ github.ref }}
cancel-in-progress: false
jobs:
auto-fix:
if: github.event_name == 'workflow_dispatch' || contains(github.event.comment.body, '/fix-issues')
runs-on: ubuntu-latest
steps:
- name: Resolve target branch
id: target
uses: actions/github-script@v9
with:
script: |
if (context.eventName === "workflow_dispatch") {
const inputBranch = core.getInput("target_branch");
const inputCommand = core.getInput("fix_command");
// Keep manual dispatch execution pinned to the single trusted fixer.
if (inputCommand.trim() !== "python scripts/fix_issues.py") {
core.setFailed("fix_command must be exactly `python scripts/fix_issues.py`.");
return;
}
core.setOutput("branch", inputBranch);
core.setOutput("fix_command", "python scripts/fix_issues.py");
core.setOutput("commit_message", core.getInput("commit_message"));
return;
}
const issue = context.payload.issue;
if (!issue.pull_request) {
core.setFailed("/fix-issues comments are only supported on pull requests.");
return;
}
const { data: pull } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: issue.number,
});
if (pull.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`) {
core.setFailed("Auto-fix can only push to branches in this repository.");
return;
}
const commenter = context.payload.comment.user.login;
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: commenter,
});
const allowed = new Set(["admin", "maintain", "write"]);
if (!allowed.has(permission.permission)) {
core.setFailed("Only repository writers can trigger /fix-issues.");
return;
}
core.setOutput("branch", pull.head.ref);
core.setOutput("fix_command", "python scripts/fix_issues.py");
core.setOutput("commit_message", `chore: auto-fix PR #${issue.number} issue triage`);
- name: Check out target branch
uses: actions/checkout@v7
with:
ref: ${{ steps.target.outputs.branch }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: "3.11"
- name: Install project and build tools
run: python -m pip install --upgrade pip build ruff && python -m pip install -e ".[dev]"
- name: Apply fixes
run: ${{ steps.target.outputs.fix_command }}
- name: Lint
run: python -m ruff check .
- name: Run tests
run: python -m pytest
- name: Build package
run: python -m build
- name: Commit and push fixes
shell: bash
run: |
if git diff --quiet && git diff --cached --quiet; then
echo "No fixes produced."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
git commit -m "${{ steps.target.outputs.commit_message }}"
git push origin "HEAD:${{ steps.target.outputs.branch }}"