-
Notifications
You must be signed in to change notification settings - Fork 0
430 lines (360 loc) · 17.4 KB
/
resource-request.yml
File metadata and controls
430 lines (360 loc) · 17.4 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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
name: Resource Request Generator
on:
issues:
types: [labeled]
jobs:
# ── Job 1: Research + generate resource code ──────────────────────────────
generate-resource:
if: github.event.label.name == 'New resource request'
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
outputs:
branch-name: ${{ steps.create-branch.outputs.branch-name }}
resource-name: ${{ steps.extract-info.outputs.resource-name }}
steps:
- name: Post processing comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: [
'## 🚧 Processing Resource Request',
'',
'Thanks for the request! We\'re on it — your resource is being automatically built and tested.',
'',
'Expected timeline: the resource will be built, tested, and merged within ~1 week.',
'',
'We\'ll post another update here once it\'s ready for review.',
].join('\n')
})
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Use Node.js 24
uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: 'npm'
- run: npm ci
- name: Extract resource name from issue title
id: extract-info
run: |
TITLE="${{ github.event.issue.title }}"
# Strip "New resource request:" prefix (case-insensitive), then slugify
RESOURCE_NAME=$(echo "$TITLE" \
| sed 's/^[Nn]ew [Rr]esource [Rr]equest:* *//g' \
| tr '[:upper:]' '[:lower:]' \
| sed 's/[^a-z0-9]/-/g' \
| sed 's/--*/-/g' \
| sed 's/^-//' \
| sed 's/-$//')
echo "resource-name=$RESOURCE_NAME" >> $GITHUB_OUTPUT
echo "Extracted resource name: $RESOURCE_NAME"
- name: Set branch name output
id: create-branch
run: |
BRANCH="resource-request/${{ steps.extract-info.outputs.resource-name }}"
echo "branch-name=$BRANCH" >> $GITHUB_OUTPUT
- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Generate resource with Claude (research + implement)
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
claude_args: "--allowedTools Bash,Read,Edit,Write,WebSearch,WebFetch --max-turns 60"
prompt: |
You are implementing a new Codify resource requested by the community.
Issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }}
Issue details:
${{ github.event.issue.body }}
Resource slug: ${{ steps.extract-info.outputs.resource-name }}
═══════════════════════════════════════
## PHASE 1: RESEARCH
═══════════════════════════════════════
Use WebSearch and WebFetch to thoroughly research this tool. If those tools
are unavailable, use bash curl to fetch pages.
Research must cover:
- Official installation method for macOS (homebrew preferred if available)
- Official installation method for Linux (apt/snap/manual/script)
- Any dependencies or prerequisites
- Key CLI commands and configuration options users would manage declaratively
- Common use cases — identify if sub-resources or stateful parameters make sense
(e.g. homebrew manages packages via formulae/casks stateful params;
asdf manages plugins and versions as sub-resources)
- Default values for any configuration settings
Write your complete research to /tmp/research-notes.md before proceeding.
═══════════════════════════════════════
## PHASE 2: IMPLEMENTATION
═══════════════════════════════════════
Read /tmp/research-notes.md, then read CLAUDE.md in the repo root. Follow
every convention described in CLAUDE.md — it is the authoritative guide.
Implement the complete resource:
1. Create src/resources/<category>/<resource-slug>/ containing:
- Resource class (TypeScript) extending Resource<Config>
- Use Zod schema (not JSON Schema) — types are inferred automatically
- Implement getSettings(), refresh(), create(), modify(), destroy()
- Add defaultConfig and exampleConfigs following CLAUDE.md spec exactly
- Use Utils from @codifycli/plugin-core (not local utils) for OS detection
and package installation
- Never hardcode brew/apt commands — use Utils.installViaPkgMgr()
2. Register the new resource in src/index.ts (import + add to Plugin.create array)
3. Write an integration test in test/<category>/<resource-slug>.test.ts
- Follow the PluginTester.fullTest() pattern from other test files
- Include validateApply, testModify (where applicable), and validateDestroy
4. Write documentation in docs/resources/<resource-slug>/
- Match the structure of existing resource docs
5. Verify TypeScript is clean:
Run: npx tsx --noEmit src/index.ts
Fix all TypeScript errors before finishing.
Do NOT run any git commands — the workflow handles committing.
- name: Restore git remote auth
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git
- name: Commit and push generated code
id: auto-commit
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "feat: Add ${{ steps.extract-info.outputs.resource-name }} resource (auto-generated from issue #${{ github.event.issue.number }})"
branch: resource-request/${{ steps.extract-info.outputs.resource-name }}
create_branch: true
- name: Fail if no changes were generated
if: steps.auto-commit.outputs.changes_detected == 'false'
run: |
echo "No changes were generated — failing the workflow."
exit 1
- name: Open pull request
if: steps.auto-commit.outputs.changes_detected == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr create \
--title "feat: Add ${{ steps.extract-info.outputs.resource-name }} resource" \
--body "Closes #${{ github.event.issue.number }}
Auto-generated resource from issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }}
> ⚠️ This PR was generated by AI. Please review carefully before merging." \
--base main \
--head resource-request/${{ steps.extract-info.outputs.resource-name }}
# ── Job 2: Integration tests on Linux ────────────────────────────────────
test-linux:
needs: generate-resource
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.generate-resource.outputs.branch-name }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Use Node.js 24
uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: 'npm'
- run: npm ci
- name: Enable linger (Linux)
run: loginctl enable-linger $(whoami)
- name: Cleanup
run: npx tsx scripts/cleanup-github-actions.ts || true
- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Find generated test files
id: find-tests
run: |
TEST_FILES=$(git diff --name-only origin/main...HEAD -- 'test/**/*.test.ts' | tr '\n' ' ')
echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT
echo "Test files: $TEST_FILES"
- name: Run Linux tests
id: run-tests
run: |
TEST_FILES="${{ steps.find-tests.outputs.test-files }}"
if [ -z "$TEST_FILES" ]; then
echo "No new test files found — skipping."
echo "passed=true" >> $GITHUB_OUTPUT
exit 0
fi
if npm run test -- $TEST_FILES --no-file-parallelism --disable-console-intercept; then
echo "passed=true" >> $GITHUB_OUTPUT
else
echo "passed=false" >> $GITHUB_OUTPUT
fi
- name: Fix failing Linux tests with Claude
if: steps.run-tests.outputs.passed == 'false'
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
claude_args: "--allowedTools Bash,Read,Edit,Write --max-turns 30"
prompt: |
The integration tests for the newly generated resource failed on Linux (ubuntu-latest).
Test files: ${{ steps.find-tests.outputs.test-files }}
Steps:
1. Run the failing tests to see exact errors:
npm run test -- ${{ steps.find-tests.outputs.test-files }} --no-file-parallelism --disable-console-intercept
2. Read the error output and identify the root cause
3. Fix the resource implementation and/or test code
4. Re-run the tests to confirm they pass now
Common Linux-specific issues:
- Wrong shell commands for Linux (should not use macOS-only tools)
- Missing loginctl / systemd setup for service-based tools
- Incorrect file paths (/home/runner vs /Users/runner)
- Package not available via apt — may need alternative install method
- Missing Utils.isLinux() guards where macOS-only code runs
Do NOT run git commands.
- name: Restore git remote auth
if: steps.run-tests.outputs.passed == 'false'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git
- name: Commit Linux fixes
if: steps.run-tests.outputs.passed == 'false'
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "fix: Linux test fixes for ${{ needs.generate-resource.outputs.resource-name }} resource"
branch: ${{ needs.generate-resource.outputs.branch-name }}
# ── Job 3: Integration tests on macOS (after Linux to avoid conflicts) ───
test-macos:
needs: [generate-resource, test-linux]
runs-on: macos-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.generate-resource.outputs.branch-name }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Use Node.js 24
uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: 'npm'
- run: npm ci
- run: npx tsx scripts/cleanup-github-actions.ts || true
- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Find generated test files
id: find-tests
run: |
TEST_FILES=$(git diff --name-only origin/main...HEAD -- 'test/**/*.test.ts' | tr '\n' ' ')
echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT
echo "Test files: $TEST_FILES"
- name: Run macOS tests
id: run-tests
env:
CI: "true"
TEST_FILES: ${{ steps.find-tests.outputs.test-files }}
shell: zsh {0}
run: |
sudo chsh -s $(which zsh) $USER
touch ~/.zshrc
unset JAVA_HOME
export SHELL=/bin/zsh
export PATH=/Users/runner/.local/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/opt/curl/bin:/usr/local/bin:/usr/local/sbin:/Users/runner/bin:/usr/bin:/bin:/usr/sbin:/sbin
if [ -z "$TEST_FILES" ]; then
echo "No new test files found — skipping."
echo "passed=true" >> $GITHUB_OUTPUT
exit 0
fi
# ${=TEST_FILES} enables zsh word-splitting on the space-separated list
if npm run test -- ${=TEST_FILES} --no-file-parallelism --disable-console-intercept; then
echo "passed=true" >> $GITHUB_OUTPUT
else
echo "passed=false" >> $GITHUB_OUTPUT
fi
- name: Fix failing macOS tests with Claude
if: steps.run-tests.outputs.passed == 'false'
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
claude_args: "--allowedTools Bash,Read,Edit,Write --max-turns 30"
prompt: |
The integration tests for the newly generated resource failed on macOS (macos-latest).
Test files: ${{ steps.find-tests.outputs.test-files }}
Steps:
1. Run the failing tests to see exact errors:
npm run test -- ${{ steps.find-tests.outputs.test-files }} --no-file-parallelism --disable-console-intercept
2. Read the error output and identify the root cause
3. Fix the resource implementation and/or test code
4. Re-run the tests to confirm they pass now
Common macOS-specific issues:
- Homebrew path differences (/opt/homebrew on Apple Silicon vs /usr/local on Intel)
- Case-insensitive filesystem — use .toLowerCase() when comparing paths
- zsh vs bash differences in shell RC file locations (~/.zshrc vs ~/.bashrc)
- macOS-only tools (e.g. launchctl, defaults, plutil) used without isMacOS() guard
- Missing Utils.isMacOS() checks where Linux-only code would run
Do NOT run git commands.
- name: Restore git remote auth
if: steps.run-tests.outputs.passed == 'false'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git
- name: Commit macOS fixes
if: steps.run-tests.outputs.passed == 'false'
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "fix: macOS test fixes for ${{ needs.generate-resource.outputs.resource-name }} resource"
branch: ${{ needs.generate-resource.outputs.branch-name }}
# ── Job 4: Label issue and post summary comment ───────────────────────────
label-awaiting-review:
needs: [generate-resource, test-linux, test-macos]
if: always() && needs.generate-resource.result == 'success'
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Add "Awaiting Human Review" label
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['Awaiting Human Review']
})
- name: Post summary comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const branch = '${{ needs.generate-resource.outputs.branch-name }}';
const linuxResult = '${{ needs.test-linux.result }}';
const macosResult = '${{ needs.test-macos.result }}';
const statusEmoji = (r) => r === 'success' ? '✅' : r === 'failure' ? '❌' : '⚠️';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: [
'## Resource Generation Complete',
'',
'The resource has been automatically generated and is awaiting human review.',
'',
`**Branch:** \`${branch}\``,
'',
'**Automated test results:**',
`- Linux: ${statusEmoji(linuxResult)} ${linuxResult}`,
`- macOS: ${statusEmoji(macosResult)} ${macosResult}`,
'',
'The Codify team will review the generated code, run additional QA, and merge when ready.',
].join('\n')
})