-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaction.yml
More file actions
490 lines (461 loc) · 25 KB
/
action.yml
File metadata and controls
490 lines (461 loc) · 25 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
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
name: Lark — propose and create tests
description: Propose end-to-end Lark tests for each pull request diff, and create them on demand when a maintainer comments `/create-workflows`.
author: getlark
inputs:
anthropic-api-key:
description: Anthropic API key used by claude-code-action to draft test proposals. Pass via secrets.ANTHROPIC_API_KEY so GitHub masks it in logs.
required: true
lark-api-base-url:
description: Base URL for the Lark API. Override to point at staging; production customers should leave the default.
required: false
default: https://api.getlark.ai
claude-model:
description: Claude model passed to claude-code-action via --model. Defaults to sonnet; override to e.g. opus for higher-fidelity proposals.
required: false
default: sonnet
runs:
using: composite
steps:
- name: Mask anthropic-api-key
shell: bash
env:
ANTHROPIC_API_KEY: ${{ inputs.anthropic-api-key }}
run: |
if [ -n "$ANTHROPIC_API_KEY" ]; then
echo "::add-mask::$ANTHROPIC_API_KEY"
fi
- name: Resolve event mode
id: pr
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
PR_FROM_PR: ${{ github.event.pull_request.number }}
PR_FROM_ISSUE: ${{ github.event.issue.number }}
ISSUE_IS_PR: ${{ github.event.issue.pull_request != null }}
run: |
# Map the triggering event to one of: propose, create, skip.
# `propose` runs on PR open/reopen; `create` runs on a PR comment
# (issue_comment with a pull_request payload). Everything else is
# a no-op so the action is safe to wire to broader triggers.
if [ "$EVENT_NAME" = "pull_request" ]; then
echo "number=$PR_FROM_PR" >> "$GITHUB_OUTPUT"
echo "mode=propose" >> "$GITHUB_OUTPUT"
elif [ "$EVENT_NAME" = "issue_comment" ] && [ "$ISSUE_IS_PR" = "true" ]; then
echo "number=$PR_FROM_ISSUE" >> "$GITHUB_OUTPUT"
echo "mode=create" >> "$GITHUB_OUTPUT"
else
echo "mode=skip" >> "$GITHUB_OUTPUT"
fi
- name: Parse /create-workflows command
id: parse
if: steps.pr.outputs.mode == 'create'
shell: bash
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
# The first non-blank line of the comment must start with
# `/create-workflows`. Optional trailing tokens are 1-based
# proposal indices, e.g. `/create-workflows 1 3`. Anything else
# makes this a no-op so the action ignores unrelated comments.
first_line=$(printf '%s' "$COMMENT_BODY" | awk 'NF{print; exit}')
if ! printf '%s' "$first_line" | grep -Eq '^/create-workflows([[:space:]]|$)'; then
echo "should-run=false" >> "$GITHUB_OUTPUT"
echo "selection=" >> "$GITHUB_OUTPUT"
exit 0
fi
selection=$(printf '%s' "$first_line" | sed -E 's@^/create-workflows[[:space:]]*@@')
# Validate any tokens are positive integers; reject otherwise so we
# don't silently drop a typo'd index.
if [ -n "$selection" ]; then
for tok in $selection; do
if ! printf '%s' "$tok" | grep -Eq '^[1-9][0-9]*$'; then
echo "Invalid selection token: $tok"
echo "should-run=false" >> "$GITHUB_OUTPUT"
echo "selection=" >> "$GITHUB_OUTPUT"
exit 0
fi
done
fi
echo "should-run=true" >> "$GITHUB_OUTPUT"
echo "selection=$selection" >> "$GITHUB_OUTPUT"
- name: Authorize commenter
id: authorize
if: steps.pr.outputs.mode == 'create' && steps.parse.outputs.should-run == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
COMMENTER: ${{ github.event.comment.user.login }}
COMMENT_ID: ${{ github.event.comment.id }}
run: |
permission=$(gh api "repos/$REPO/collaborators/$COMMENTER/permission" --jq .permission 2>/dev/null || echo "none")
case "$permission" in
admin|maintain|write)
echo "authorized=true" >> "$GITHUB_OUTPUT"
;;
*)
echo "Commenter $COMMENTER has '$permission' permission — refusing to create workflows."
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=-1 >/dev/null || true
echo "authorized=false" >> "$GITHUB_OUTPUT"
;;
esac
- name: Compute proceed flag
id: proceed
shell: bash
env:
MODE: ${{ steps.pr.outputs.mode }}
SHOULD_RUN: ${{ steps.parse.outputs.should-run }}
AUTHORIZED: ${{ steps.authorize.outputs.authorized }}
run: |
# Single boolean the rest of the action gates on. Keeps the per-step
# `if:` expressions short and avoids drifting conditions when new
# gating reasons get added later.
if [ "$MODE" = "propose" ]; then
echo "go=true" >> "$GITHUB_OUTPUT"
elif [ "$MODE" = "create" ] && [ "$SHOULD_RUN" = "true" ] && [ "$AUTHORIZED" = "true" ]; then
echo "go=true" >> "$GITHUB_OUTPUT"
else
echo "go=false" >> "$GITHUB_OUTPUT"
fi
- name: Check ANTHROPIC_API_KEY is configured
id: check-anthropic-key
if: steps.proceed.outputs.go == 'true'
shell: bash
env:
ANTHROPIC_API_KEY: ${{ inputs.anthropic-api-key }}
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
REPO: ${{ github.repository }}
MODE: ${{ steps.pr.outputs.mode }}
COMMENT_ID: ${{ github.event.comment.id }}
run: |
if [ -z "$ANTHROPIC_API_KEY" ]; then
if [ "$MODE" = "propose" ]; then
gh pr comment "$PR_NUMBER" --repo "$REPO" --body $'**Lark setup needed**\n\nThis repo has the Lark test-proposal workflow installed, but the `ANTHROPIC_API_KEY` repo secret is not set. Add it under **Settings → Secrets and variables → Actions** to enable test proposals on future PRs.\n\nThis run was a no-op.'
elif [ "$MODE" = "create" ] && [ -n "$COMMENT_ID" ]; then
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=-1 >/dev/null || true
fi
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
- name: Ensure Lark labels exist
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'propose' && steps.check-anthropic-key.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
run: |
# --force makes `gh label create` idempotent: creates the label if
# missing, updates color/description if it already exists.
gh label create "lark:proposing-tests" --repo "$REPO" --color "FBCA04" --description "Lark is drafting test proposals for this PR" --force
gh label create "lark:tests-proposed" --repo "$REPO" --color "0E8A16" --description "Lark has proposed end-to-end tests for this PR" --force
gh label create "lark:test-proposal-failed" --repo "$REPO" --color "B60205" --description "Lark failed to propose tests for this PR" --force
- name: Mark PR as in-progress
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'propose' && steps.check-anthropic-key.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
REPO: ${{ github.repository }}
LARK_PROPOSING_LABEL: lark:proposing-tests
LARK_PROPOSED_LABEL: lark:tests-proposed
LARK_FAILED_LABEL: lark:test-proposal-failed
run: |
# Strip terminal labels from any prior run so the PR reflects only
# this run's state. `gh pr edit` accepts a single comma-separated
# --remove-label flag.
gh pr edit "$PR_NUMBER" --repo "$REPO" \
--remove-label "$LARK_PROPOSED_LABEL,$LARK_FAILED_LABEL" \
--add-label "$LARK_PROPOSING_LABEL" || true
- name: Checkout repo
if: steps.proceed.outputs.go == 'true' && steps.check-anthropic-key.outputs.skip != 'true'
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Fetch latest proposals marker
id: proposals
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'create' && steps.check-anthropic-key.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
SELECTION: ${{ steps.parse.outputs.selection }}
COMMENT_ID: ${{ github.event.comment.id }}
run: |
# Find the most recent PR comment authored by the GitHub Actions
# bot whose first line is the `<!-- lark-test-proposals: ... -->`
# marker. Walk from newest to oldest so re-runs pick up the most
# recent set of proposals.
marker_line=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" --paginate \
--jq '[.[] | select(.user.login=="github-actions[bot]")
| select((.body // "") | test("^<!-- lark-test-proposals: "))]
| last
| .body
| split("\n")[0]' || true)
if [ -z "$marker_line" ] || [ "$marker_line" = "null" ]; then
echo "No proposals marker comment found on PR #$PR_NUMBER."
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=confused >/dev/null || true
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Strip the `<!-- lark-test-proposals: ` prefix and ` -->` suffix.
json=$(printf '%s' "$marker_line" | sed -E 's@^<!-- lark-test-proposals: (.*) -->$@\1@')
if [ -z "$json" ] || ! printf '%s' "$json" | jq -e 'type == "array"' >/dev/null 2>&1; then
echo "Proposals marker did not contain a valid JSON array."
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=confused >/dev/null || true
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi
printf '%s' "$json" > proposals.json
if [ -n "$SELECTION" ]; then
# Filter by 1-based indices. Reject out-of-range selections so the
# user notices a typo instead of silently creating the wrong set.
total=$(jq 'length' proposals.json)
for idx in $SELECTION; do
if [ "$idx" -lt 1 ] || [ "$idx" -gt "$total" ]; then
echo "Selection index $idx is out of range (1..$total)."
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=-1 >/dev/null || true
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi
done
# Convert 1-based selection list to a jq filter on 0-based indices.
indices=$(printf '%s\n' $SELECTION | awk '{print $1 - 1}' | jq -s '.')
jq --argjson idx "$indices" '[ .[ $idx[] ] ]' proposals.json > proposals.filtered.json
mv proposals.filtered.json proposals.json
fi
count=$(jq 'length' proposals.json)
echo "Selected $count proposal(s)."
echo "found=true" >> "$GITHUB_OUTPUT"
echo "count=$count" >> "$GITHUB_OUTPUT"
- name: Mint OIDC token for Lark
if: steps.proceed.outputs.go == 'true' && steps.check-anthropic-key.outputs.skip != 'true' && (steps.pr.outputs.mode == 'propose' || steps.proposals.outputs.found == 'true')
id: oidc
uses: actions/github-script@v8
with:
script: |
const token = await core.getIDToken('getlark');
core.setSecret(token);
core.setOutput('token', token);
- name: Exchange OIDC token for Lark API token
if: steps.proceed.outputs.go == 'true' && steps.check-anthropic-key.outputs.skip != 'true' && (steps.pr.outputs.mode == 'propose' || steps.proposals.outputs.found == 'true')
id: exchange
shell: bash
env:
OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
LARK_API_BASE_URL: ${{ inputs.lark-api-base-url }}
run: |
response=$(curl -sS -X POST "$LARK_API_BASE_URL/integrations/github/ci/exchange-oidc" \
-H "Content-Type: application/json" \
-d "{\"oidc_token\":\"$OIDC_TOKEN\",\"pr_number\":$PR_NUMBER}")
lark_token=$(echo "$response" | jq -r '.lark_token')
if [ -z "$lark_token" ] || [ "$lark_token" = "null" ]; then
echo "OIDC exchange failed: $response"
exit 1
fi
echo "::add-mask::$lark_token"
echo "lark_token=$lark_token" >> "$GITHUB_OUTPUT"
- name: Write Lark MCP config
if: steps.proceed.outputs.go == 'true' && steps.check-anthropic-key.outputs.skip != 'true' && (steps.pr.outputs.mode == 'propose' || steps.proposals.outputs.found == 'true')
shell: bash
env:
LARK_TOKEN: ${{ steps.exchange.outputs.lark_token }}
LARK_API_BASE_URL: ${{ inputs.lark-api-base-url }}
MCP_CONFIG_PATH: ${{ runner.temp }}/lark-mcp.json
run: |
# Build the MCP config with jq -n so the bearer is never interpolated
# into a heredoc / shell history. The file lives under runner.temp
# (cleaned up by the runner) rather than the checkout to keep the
# token out of any artifact that might surface workspace files.
jq -n \
--arg url "$LARK_API_BASE_URL/mcp" \
--arg auth "Bearer $LARK_TOKEN" \
'{mcpServers: {lark: {type: "http", url: $url, headers: {Authorization: $auth}}}}' \
> "$MCP_CONFIG_PATH"
- name: Run Claude Code to propose tests
id: claude-propose
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'propose' && steps.check-anthropic-key.outputs.skip != 'true'
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ inputs.anthropic-api-key }}
# Pass the workflow's GITHUB_TOKEN so claude-code-action skips its
# OIDC → Claude GitHub App token exchange. We don't need that path:
# all GitHub-side work (labels, PR comment) is handled by our own
# composite steps, and requiring customers to install the Claude
# GitHub App on every repo would be a significant adoption hurdle.
github_token: ${{ github.token }}
claude_args: |
--max-turns 60
--model ${{ inputs.claude-model }}
--permission-mode acceptEdits
--mcp-config ${{ runner.temp }}/lark-mcp.json
--allowedTools "mcp__lark__list_workflows,mcp__lark__retrieve_workflow,mcp__lark__list_workflow_groups,mcp__lark__list_workflow_executions,mcp__lark__retrieve_workflow_execution,mcp__lark__get_execution_logs,mcp__lark__list_workflow_generations,mcp__lark__retrieve_workflow_generation,mcp__lark__get_generation_workflow_logs,mcp__lark__list_workflow_repairs,mcp__lark__retrieve_workflow_repair,mcp__lark__get_repair_workflow_logs,mcp__lark__list_workflow_summarizations,mcp__lark__retrieve_workflow_summarization,mcp__lark__get_summarization_workflow_logs,mcp__lark__list_secret_contexts,mcp__lark__get_secret_context"
show_full_output: ${{ runner.debug == '1' }}
prompt: |
You are running inside a GitHub Action to suggest end-to-end tests
for a customer's pull request. Read the diff in this checkout
(use `git diff origin/${{ github.event.pull_request.base.ref }}...HEAD`),
inspect the customer's existing Lark workflows via the `lark` MCP
server, and propose net-new tests that exercise behavior introduced
by the diff.
Discover existing coverage with the `lark` MCP tools rather than
listing everything blindly. Start with `mcp__lark__list_workflows`
and pass the `search` query with terms drawn from the diff (file
names, route paths, function or component names) to surface
near-duplicates. Use `mcp__lark__retrieve_workflow` to inspect a
candidate's `target` and `steps` before deciding it duplicates the
diff's behavior. Optionally call `mcp__lark__list_workflow_groups`
to see how tests are organized, and `mcp__lark__list_secret_contexts`
if a proposed test would require credentials.
Every proposal needs a concrete target (URL, API endpoint, CLI
binary, script path, etc.) plus ordered action steps in plain
prose. Do not pad thin diffs with invented steps — return fewer,
sharper proposals.
The target can be any software surface — web/mobile UI, HTTP
or GraphQL API, CLI binary, shell script, data pipeline,
background job, or a mixed flow that spans several. Pick the
surface where the diff's effect is directly observable from
outside the system under test: rendered UI state, response
payload or status, files written, queue or DB rows produced,
stdout, exit code, etc. If the diff's effect is only visible
on an internal hop the chosen target cannot see — a
server-to-server header, an internal log line or metric, a
private method's behavior — drop the proposal. Lark proposes
tests, not smoke checks.
Every proposal must include at least one assertion that would
produce a different result with the diff applied vs reverted,
and state it explicitly in the steps. The assertion must be
unconditional — "do X, then verify Y" — not "if Y appears,
check it." This applies regardless of surface: a UI test
asserts a specific rendered element or state, a CLI test
asserts specific stdout or exit code, a pipeline test asserts
specific output rows or files. If you cannot articulate such
an assertion from the chosen target, skip the proposal.
Output a JSON array of `{title, description, target, steps}` to
`proposals.json` in the workspace root. Do not propose tests that
duplicate existing workflows.
Do not propose tests for Lark itself or for CI plumbing. Skip any
test whose subject is the Lark GitHub Action, the
`.github/workflows/lark.yml` workflow, the `getlark/lark-*` action,
GitHub Actions trigger semantics, or other CI/CD configuration.
Lark proposes tests for the customer's product, not for its own
installation. If the PR only touches CI config and there is no
customer-facing behavior to cover, return `[]`.
- name: Run Claude Code to create workflows
id: claude-create
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'create' && steps.check-anthropic-key.outputs.skip != 'true' && steps.proposals.outputs.found == 'true'
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ inputs.anthropic-api-key }}
github_token: ${{ github.token }}
claude_args: |
--max-turns 60
--model ${{ inputs.claude-model }}
--permission-mode acceptEdits
--mcp-config ${{ runner.temp }}/lark-mcp.json
--allowedTools "mcp__lark__create_workflow,mcp__lark__list_workflow_groups,mcp__lark__list_secret_contexts,mcp__lark__get_secret_context"
show_full_output: ${{ runner.debug == '1' }}
prompt: |
You are running inside a GitHub Action to materialize Lark test
workflows from previously-proposed tests. A maintainer has
approved a subset of proposals via a PR comment.
Read `proposals.json` in the workspace root. It is a JSON array
of `{title, description, target, steps}` entries — exactly the
proposals the user asked to create. If the file is missing,
empty, or `[]`, write `[]` to `created.json` and exit
immediately. Do NOT invent or add proposals beyond what is in
the file.
For each proposal, call `mcp__lark__create_workflow` to create
the workflow on Lark.
- Use the proposal's `title` as the workflow `name`.
- Build the workflow `description` by concatenating the proposal's
`target` and `steps` so the Lark generation pipeline has the
full target plus ordered actions.
- If a proposal looks like it needs a secret context or a group,
verify the name first with `mcp__lark__list_secret_contexts`
or `mcp__lark__list_workflow_groups`. If the named context or
group doesn't exist, omit the optional field rather than
failing the create call.
After all create calls finish, write `created.json` to the
workspace root: a JSON array of `{title, id, status, url}`
where `url` is `https://dashboard.getlark.ai/workflows/<id>`.
Include only successfully-created workflows. If a single
create call fails, continue with the rest and omit the
failed one from `created.json`.
- name: Post proposals comment + swap labels
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'propose' && steps.check-anthropic-key.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
REPO: ${{ github.repository }}
LARK_PROPOSING_LABEL: lark:proposing-tests
LARK_PROPOSED_LABEL: lark:tests-proposed
run: |
# Treat missing/empty file, an empty JSON array, or non-array/invalid
# JSON all as "no proposals" — Claude's natural no-op output is `[]`,
# and a cosmetic misfire shouldn't post a broken comment or mislabel
# the PR as having proposals.
if [ ! -s proposals.json ] || ! jq -e 'type == "array" and length > 0' proposals.json >/dev/null 2>&1; then
# Stay silent when there's nothing worth proposing — a "no proposals"
# comment on every quiet PR is noise. Just clear the in-progress label.
gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$LARK_PROPOSING_LABEL" || true
else
marker=$(printf '<!-- lark-test-proposals: %s -->' "$(jq -c . proposals.json)")
body=$(jq -r 'to_entries | map("**\(.key + 1).** \(.value.title)\n\n\(.value.description)") | join("\n\n---\n\n")' proposals.json)
gh pr comment "$PR_NUMBER" --repo "$REPO" --body "$marker"$'\n\n## Proposed Lark tests\n\n'"$body"$'\n\nReply with `/create-workflows` to materialize all, or `/create-workflows 1 3` to pick specific proposals.'
gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$LARK_PROPOSING_LABEL" --add-label "$LARK_PROPOSED_LABEL" || true
fi
- name: Reply with created workflows
if: steps.proceed.outputs.go == 'true' && steps.pr.outputs.mode == 'create' && steps.check-anthropic-key.outputs.skip != 'true' && steps.proposals.outputs.found == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
REPO: ${{ github.repository }}
COMMENT_ID: ${{ github.event.comment.id }}
run: |
if [ ! -s created.json ] || ! jq -e 'type == "array" and length > 0' created.json >/dev/null 2>&1; then
gh pr comment "$PR_NUMBER" --repo "$REPO" --body $'Lark could not create any workflows from the selected proposals. Check the action logs for details.'
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=-1 >/dev/null || true
exit 0
fi
body=$(jq -r 'map("- **\(.title)** — [\(.id)](\(.url))") | join("\n")' created.json)
gh pr comment "$PR_NUMBER" --repo "$REPO" --body $'## Created Lark workflows\n\n'"$body"
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=+1 >/dev/null || true
- name: Mark failure on error
if: failure() && steps.proceed.outputs.go == 'true' && steps.check-anthropic-key.outputs.skip != 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
REPO: ${{ github.repository }}
MODE: ${{ steps.pr.outputs.mode }}
COMMENT_ID: ${{ github.event.comment.id }}
LARK_PROPOSING_LABEL: lark:proposing-tests
LARK_FAILED_LABEL: lark:test-proposal-failed
run: |
if [ "$MODE" = "propose" ]; then
gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label "$LARK_PROPOSING_LABEL" --add-label "$LARK_FAILED_LABEL" || true
elif [ "$MODE" = "create" ] && [ -n "$COMMENT_ID" ]; then
gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" \
-H "Accept: application/vnd.github+json" \
-f content=-1 >/dev/null || true
fi