-
Notifications
You must be signed in to change notification settings - Fork 571
Claude fix issue workflow: properly reference issue in PR title #5093
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| name: "Claude Fix Issue" | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| issue-number: | ||
| description: "Issue number from phpstan/phpstan repository" | ||
| required: true | ||
| type: string | ||
| workflow_call: | ||
| inputs: | ||
| issue-number: | ||
| description: "Issue number from phpstan/phpstan repository" | ||
| required: true | ||
| type: string | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| fix: | ||
| name: "Fix #${{ inputs.issue-number }}" | ||
| runs-on: "ubuntu-latest" | ||
| timeout-minutes: 60 | ||
| permissions: | ||
| contents: read | ||
| issues: read | ||
| pull-requests: write | ||
|
|
||
| steps: | ||
| - name: Harden the runner (Audit all outbound calls) | ||
| uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: "Checkout" | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | ||
| with: | ||
| ref: 2.1.x | ||
Check failureCode scanning / octoscan Use of 'actions/checkout' with a custom ref. Error
Use of 'actions/checkout' with a custom ref.
|
||
| repository: phpstan/phpstan-src | ||
| fetch-depth: 0 | ||
|
Comment on lines
+36
to
+41
Check warningCode scanning / zizmor credential persistence through GitHub Actions artifacts Warning
credential persistence through GitHub Actions artifacts
|
||
|
|
||
| - name: "Install PHP" | ||
| uses: "shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1" # v2 | ||
| with: | ||
| coverage: "none" | ||
| php-version: "8.4" | ||
| ini-file: development | ||
| extensions: mbstring | ||
|
|
||
| - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 | ||
|
|
||
| - name: "Install Claude Code" | ||
| run: npm install -g @anthropic-ai/claude-code | ||
|
|
||
| - name: "Fetch issue details" | ||
| id: issue | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ inputs.issue-number }} | ||
| run: | | ||
| ISSUE_JSON=$(gh issue view "$ISSUE_NUMBER" \ | ||
| --repo phpstan/phpstan \ | ||
| --json title,body,url) | ||
|
|
||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
| TITLE=$(echo "$ISSUE_JSON" | jq -r '.title') | ||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
| URL=$(echo "$ISSUE_JSON" | jq -r '.url') | ||
| echo "title=$TITLE" >> "$GITHUB_OUTPUT" | ||
| echo "url=$URL" >> "$GITHUB_OUTPUT" | ||
| echo "$ISSUE_JSON" | jq -r '.body' > /tmp/issue-body.txt | ||
|
|
||
| - name: "Run Claude Code" | ||
| env: | ||
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | ||
| GH_TOKEN: ${{ secrets.PHPSTAN_BOT_FORK_TOKEN }} | ||
| run: | | ||
| git config user.name "phpstan-bot" | ||
Check failureCode scanning / octoscan Expression injection, "steps..outputs." is potentially untrusted. Error
Expression injection, "steps.**.outputs.**" is potentially untrusted.
|
||
| git config user.email "ondrej+phpstanbot@mirtes.cz" | ||
|
|
||
| claude --model claude-opus-4-6 \ | ||
| --dangerously-skip-permissions \ | ||
| -p "$(cat << 'PROMPT_EOF' | ||
| You are working on phpstan/phpstan-src, the source code of PHPStan - a PHP static analysis tool. | ||
|
|
||
| Your task is to fix the following GitHub issue from the phpstan/phpstan repository: | ||
| Issue phpstan/phpstan#${{ inputs.issue-number }}: ${{ steps.issue.outputs.title }} | ||
Check failureCode scanning / zizmor code injection via template expansion Error
code injection via template expansion
Check warningCode scanning / zizmor code injection via template expansion Warning
code injection via template expansion
Check warningCode scanning / zizmor code injection via template expansion Warning
code injection via template expansion
Check noticeCode scanning / zizmor code injection via template expansion Note
code injection via template expansion
|
||
| URL: ${{ steps.issue.outputs.url }} | ||
Check warningCode scanning / zizmor code injection via template expansion Warning
code injection via template expansion
Check noticeCode scanning / zizmor code injection via template expansion Note
code injection via template expansion
|
||
|
|
||
| Issue body is in the file /tmp/issue-body.txt — read it before proceeding. | ||
|
|
||
| ## Step 1: Write a regression test | ||
|
|
||
| Read .claude/skills/regression-test/SKILL.md for detailed guidance on writing regression tests for PHPStan bugs. | ||
|
|
||
| The issue body is already provided above — start from Step 2 of the skill (deciding test type). For Step 1 (gathering context), you only need to fetch the playground samples from any playground links found in the issue body. | ||
|
|
||
| Skip Steps 5-6 of the skill (reverting fix and committing) — those are not needed here. | ||
|
|
||
| The regression test should fail without the fix — verify this by running it before implementing the fix. | ||
|
|
||
| ## Step 2: Fix the bug | ||
|
|
||
| Implement the fix in the source code under src/. Common areas to look: | ||
| - src/Analyser/NodeScopeResolver.php - AST traversal and scope management | ||
| - src/Analyser/MutatingScope.php - Type tracking | ||
| - src/Analyser/TypeSpecifier.php - Type narrowing from conditions | ||
| - src/Type/ - Type system implementations | ||
| - src/Rules/ - Rule implementations | ||
| - src/Reflection/ - Reflection layer | ||
|
|
||
| Read CLAUDE.md for important guidelines about the codebase architecture and common patterns. | ||
|
|
||
| ## Step 3: Verify the fix | ||
|
|
||
| 1. Run the regression test to confirm it passes now | ||
| 2. Run the full test suite: make tests | ||
| 3. Run PHPStan self-analysis: make phpstan | ||
| 4. Fix any failures that come up | ||
| 5. Run make cs-fix to fix any coding standard violations | ||
| 6. Run make name-collision and fix violations - add different tests in unique namespaces. If the function and class declarations are exactly the same, you can reuse them across files instead of duplicating them. | ||
|
|
||
| Do not create a branch, push, or create a PR - this will be handled automatically. | ||
|
|
||
| ## Step 4: Write a summary | ||
|
|
||
| After completing the fix, write two files: | ||
|
|
||
| 1. /tmp/commit-message.txt - A concise commit message (first line: short summary under 72 chars, then a blank line, then a few bullet points describing key changes). Example: | ||
| Fix array_key_exists narrowing for template types | ||
|
|
||
| - Added handling for TemplateType in TypeSpecifier when processing array_key_exists | ||
| - New regression test in tests/PHPStan/Analyser/nsrt/bug-12345.php | ||
| - The root cause was that TypeSpecifier did not unwrap template bounds before narrowing | ||
|
|
||
| 2. /tmp/pr-description.md - A pull request description in this format: | ||
| ## Summary | ||
| Brief description of what the issue was about and what the fix does. | ||
|
|
||
| ## Changes | ||
| - Bullet points of specific code changes made | ||
| - Reference file paths where changes were made | ||
|
|
||
| ## Root cause | ||
| Explain why the bug happened and how the fix addresses it. | ||
|
|
||
| ## Test | ||
| Describe the regression test that was added. | ||
|
|
||
| Fixes phpstan/phpstan#${{ inputs.issue-number }} | ||
Check failureCode scanning / zizmor code injection via template expansion Error
code injection via template expansion
Check warningCode scanning / zizmor code injection via template expansion Warning
code injection via template expansion
|
||
|
|
||
| These files are critical - they will be used for the commit message and PR description. | ||
| PROMPT_EOF | ||
| )" | ||
|
|
||
| - name: "Read Claude's summary" | ||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
| id: claude-summary | ||
| env: | ||
| ISSUE_NUMBER: ${{ inputs.issue-number }} | ||
| run: | | ||
| if [ -f /tmp/commit-message.txt ]; then | ||
| delimiter="EOF_$(openssl rand -hex 16)" | ||
| { | ||
| echo "commit_message<<${delimiter}" | ||
| cat /tmp/commit-message.txt | ||
| echo "${delimiter}" | ||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
| } >> "$GITHUB_OUTPUT" | ||
| else | ||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
| echo "commit_message=Fix #$ISSUE_NUMBER" >> "$GITHUB_OUTPUT" | ||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
| fi | ||
|
|
||
| if [ -f /tmp/pr-description.md ]; then | ||
| delimiter="EOF_$(openssl rand -hex 16)" | ||
| { | ||
| echo "pr_body<<${delimiter}" | ||
| cat /tmp/pr-description.md | ||
| echo "${delimiter}" | ||
| } >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "pr_body=Fixes phpstan/phpstan#$ISSUE_NUMBER" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
Comment on lines
+1
to
+180
Check warningCode scanning / zizmor insufficient job-level concurrency limits Warning
insufficient job-level concurrency limits
|
||
|
|
||
| - name: "Create Pull Request" | ||
| id: create-pr | ||
| uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 | ||
| with: | ||
| branch-token: ${{ secrets.PHPSTAN_BOT_FORK_TOKEN }} | ||
| token: ${{ secrets.PHPSTAN_BOT_PR_TOKEN }} | ||
| push-to-fork: phpstan-bot/phpstan-src | ||
| branch-suffix: random | ||
| delete-branch: true | ||
| title: "Fix phpstan/phpstan#${{ inputs.issue-number }}: ${{ steps.issue.outputs.title }}" | ||
| body: ${{ steps.claude-summary.outputs.pr_body }} | ||
| committer: "phpstan-bot <ondrej+phpstanbot@mirtes.cz>" | ||
| commit-message: ${{ steps.claude-summary.outputs.commit_message }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| name: "Claude Random Easy Fixes (Scheduled)" | ||
|
|
||
| on: | ||
| schedule: | ||
| # Run every day, 4 times, once an hour at :15, from 2pm CET (13:00 UTC) to 5pm CET (16:00 UTC) | ||
| - cron: '15 13-16 * * *' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| trigger: | ||
Check noticeCode scanning / zizmor workflow or action definition without a name Note
workflow or action definition without a name
|
||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| actions: write | ||
Check warningCode scanning / zizmor permissions without explanatory comments Warning
permissions without explanatory comments
|
||
| steps: | ||
| - name: Harden the runner (Audit all outbound calls) | ||
| uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: Trigger Claude Random Easy Fixes | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: gh workflow run claude-random-easy-fixes.yml -f issue_count=5 --repo ${{ github.repository }} | ||
Check warningCode scanning / zizmor code injection via template expansion Warning
code injection via template expansion
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| name: "Claude Random Easy Fixes" | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| issue_count: | ||
| description: "Number of issues to pick and fix in parallel" | ||
| required: false | ||
| default: "1" | ||
| type: string | ||
|
|
||
| jobs: | ||
| pick-issues: | ||
| name: "Pick easy fix issues" | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
|
|
||
| outputs: | ||
| matrix: ${{ steps.pick-issues.outputs.matrix }} | ||
|
|
||
| permissions: | ||
| contents: read | ||
| issues: read | ||
Check warningCode scanning / zizmor permissions without explanatory comments Warning
permissions without explanatory comments
|
||
|
|
||
| steps: | ||
| - name: Harden the runner (Audit all outbound calls) | ||
| uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: "Pick random Easy fix issues" | ||
| id: pick-issues | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_COUNT: ${{ inputs.issue_count || '1' }} | ||
| run: | | ||
| # Look up milestone number for "Easy fixes" | ||
| MILESTONE_NUMBER=$(gh api "repos/phpstan/phpstan/milestones?per_page=100" \ | ||
| --jq '.[] | select(.title == "Easy fixes") | .number') | ||
|
|
||
| if [ -z "$MILESTONE_NUMBER" ]; then | ||
| echo "Could not find 'Easy fixes' milestone" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Fetch all open issues in the milestone using pagination | ||
| ISSUE_JSON=$(gh api --paginate \ | ||
| "repos/phpstan/phpstan/issues?state=open&milestone=${MILESTONE_NUMBER}&per_page=100" \ | ||
| --jq '[.[] | {number: .number, title: .title}]' \ | ||
| | jq -s 'add // []') | ||
|
|
||
| TOTAL=$(echo "$ISSUE_JSON" | jq 'length') | ||
| if [ "$TOTAL" -eq 0 ]; then | ||
| echo "No issues found in Easy fixes milestone" | ||
| exit 1 | ||
| fi | ||
|
|
||
| COUNT=$ISSUE_COUNT | ||
| if [ "$COUNT" -gt "$TOTAL" ]; then | ||
| COUNT=$TOTAL | ||
| fi | ||
|
|
||
| # Pick COUNT random unique issues | ||
| SELECTED=$(echo "$ISSUE_JSON" | python3 -c " | ||
| import json, sys, random | ||
| issues = json.load(sys.stdin) | ||
| random.shuffle(issues) | ||
| count = min(int('$COUNT'), len(issues)) | ||
| print(json.dumps(issues[:count])) | ||
| ") | ||
|
|
||
| echo "Selected $COUNT issue(s) for fixing" | ||
|
|
||
| for NUMBER in $(echo "$SELECTED" | jq -r '.[].number'); do | ||
| TITLE=$(echo "$SELECTED" | jq -r --argjson n "$NUMBER" '.[] | select(.number == $n) | .title') | ||
| echo "### Selected issue: #$NUMBER - $TITLE" >> "$GITHUB_STEP_SUMMARY" | ||
| done | ||
|
|
||
| echo "matrix=$(echo "$SELECTED" | jq -c '.')" >> "$GITHUB_OUTPUT" | ||
Check failureCode scanning / octoscan Write to "$GITHUB_OUTPUT" in a bash script. Error
Write to "$GITHUB_OUTPUT" in a bash script.
|
||
|
|
||
| easy-fix: | ||
| name: "Fix #${{ matrix.issue.number }}: ${{ matrix.issue.title }}" | ||
| needs: pick-issues | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| issue: ${{ fromJson(needs.pick-issues.outputs.matrix) }} | ||
| uses: ./.github/workflows/claude-fix-issue.yml | ||
Check warningCode scanning / zizmor secrets unconditionally inherited by called workflow Warning
secrets unconditionally inherited by called workflow
Check failureCode scanning / octoscan Use of local workflow "./.github/workflows/claude-fix-issue.yml" Error
Use of local workflow "./.github/workflows/claude-fix-issue.yml"
|
||
| with: | ||
| issue-number: ${{ matrix.issue.number }} | ||
| secrets: inherit | ||
Check warning
Code scanning / zizmor
permissions without explanatory comments Warning