forked from phpstan/phpstan-src
-
Notifications
You must be signed in to change notification settings - Fork 0
211 lines (169 loc) · 7.43 KB
/
claude-fix-issue.yml
File metadata and controls
211 lines (169 loc) · 7.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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: write
pull-requests: write
issues: write
jobs:
fix:
name: "Fix #${{ inputs.issue-number }}"
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 60
steps:
- name: "Checkout"
uses: actions/checkout@v4
with:
repository: phpstan/phpstan-src
ref: "2.1.x"
fetch-depth: 0
token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.4"
ini-file: development
extensions: mbstring
- uses: "ramsey/composer-install@v3"
- name: "Install Claude Code"
run: npm install -g @anthropic-ai/claude-code
- name: "Fetch issue details"
id: issue
env:
GH_TOKEN: ${{ secrets.PHPSTAN_BOT_TOKEN }}
ISSUE_NUMBER: ${{ inputs.issue-number }}
run: |
ISSUE_JSON=$(gh issue view "$ISSUE_NUMBER" \
--repo phpstan/phpstan \
--json title,body,url)
TITLE=$(echo "$ISSUE_JSON" | jq -r '.title')
URL=$(echo "$ISSUE_JSON" | jq -r '.url')
BODY=$(echo "$ISSUE_JSON" | jq -r '.body')
echo "title=$TITLE" >> "$GITHUB_OUTPUT"
echo "url=$URL" >> "$GITHUB_OUTPUT"
{
echo "body<<BODY_EOF"
echo "$BODY"
echo "BODY_EOF"
} >> "$GITHUB_OUTPUT"
- name: "Build prompt"
env:
ISSUE_NUMBER: ${{ inputs.issue-number }}
ISSUE_TITLE: ${{ steps.issue.outputs.title }}
ISSUE_URL: ${{ steps.issue.outputs.url }}
ISSUE_BODY: ${{ steps.issue.outputs.body }}
run: |
python3 << 'PYEOF'
import os
n = os.environ["ISSUE_NUMBER"]
title = os.environ["ISSUE_TITLE"]
url = os.environ["ISSUE_URL"]
body = os.environ["ISSUE_BODY"]
prompt = f"""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 #{n}: {title}
URL: {url}
Issue body:
{body}
## 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#{n}
These files are critical - they will be used for the commit message and PR description.
"""
with open("/tmp/claude-prompt.txt", "w") as f:
f.write(prompt)
PYEOF
- name: "Run Claude Code"
env:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
GH_TOKEN: ${{ secrets.PHPSTAN_BOT_TOKEN }}
run: |
git config user.name "phpstan-bot"
git config user.email "ondrej+phpstanbot@mirtes.cz"
claude -p \
--model claude-opus-4-6 \
--dangerously-skip-permissions \
"$(cat /tmp/claude-prompt.txt)"
- name: "Read Claude's summary"
id: claude-summary
env:
ISSUE_NUMBER: ${{ inputs.issue-number }}
run: |
if [ -f /tmp/commit-message.txt ]; then
{
echo "commit_message<<COMMIT_MSG_EOF"
cat /tmp/commit-message.txt
echo "COMMIT_MSG_EOF"
} >> "$GITHUB_OUTPUT"
else
echo "commit_message=Fix #$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
fi
if [ -f /tmp/pr-description.md ]; then
{
echo "pr_body<<PR_BODY_EOF"
cat /tmp/pr-description.md
echo "PR_BODY_EOF"
} >> "$GITHUB_OUTPUT"
else
echo "pr_body=Fixes phpstan/phpstan#$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
fi
- name: "Create Pull Request"
id: create-pr
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
branch-suffix: random
delete-branch: true
title: "Fix #${{ 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 }}