qaify-playwright-reporter 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/ai-env.d.ts +2 -0
- package/dist/ai-env.js +16 -3
- package/dist/analyze.d.ts +2 -0
- package/dist/analyze.js +1 -0
- package/dist/cli.js +23 -22
- package/package.json +1 -1
- package/templates/auto-fix.yml +12 -10
- package/templates/qa.yml +9 -6
- package/templates/qaify-audit.yml +9 -7
- package/templates/qaify-fix.yml +11 -9
package/README.md
CHANGED
|
@@ -66,7 +66,8 @@ Nama bin lama `playwright-reporter` tetap tersedia sebagai alias.
|
|
|
66
66
|
Backend tidak memanggil AI (`QA_AI_MODE=actions`, default). Kegagalan yang tidak dikenali aturan diantrekan, lalu job `analyze` di [`qa.yml`](../.github/workflows/qa.yml) menjalankan Claude Code dengan langganan kamu:
|
|
67
67
|
|
|
68
68
|
1. Di komputer yang sudah login Claude Code: `claude setup-token` → salin token (berlaku 1 tahun).
|
|
69
|
-
2. Simpan
|
|
69
|
+
2. Simpan token itu **sekali** di Qaify → Setelan → Agen AI → "Token langganan Claude", lalu di setiap repo nyalakan "Pakai setelan Agen AI akun saya" (Otomatisasi & AI). Aplikasi audit memakai akun pembuatnya. Workflow ≥ 0.11 mengambilnya lewat `qaify ai-env --oauth` hanya saat tugas berjalan, jadi secret per repo tidak perlu.
|
|
70
|
+
Cara lama tetap jalan: secret `CLAUDE_CODE_OAUTH_TOKEN` di repo yang diuji. Bila keduanya ada, token dari Qaify yang dipakai.
|
|
70
71
|
3. Opsional: variable `QA_FACTORY_AI_MODEL` (default `sonnet`; `opus` lebih teliti tapi lebih cepat menghabiskan kuota).
|
|
71
72
|
|
|
72
73
|
`claude -p` dijalankan di folder kosong dengan semua tool dimatikan, menerima antrean lewat stdin, dan mengembalikan JSON sesuai schema. `ai-submit --finalize` menerapkan hasilnya; kegagalan yang tidak terjawab (login gagal, kuota habis, timeout, PR dari fork tanpa secret) menjadi "belum jelas".
|
package/dist/ai-env.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface AiEnvOptions {
|
|
|
15
15
|
githubRunId?: number;
|
|
16
16
|
envFile: string;
|
|
17
17
|
errorOut?: string;
|
|
18
|
+
/** workflow memuat env file SETELAH membuang secret repo → token langganan Claude dari Qaify boleh diterima */
|
|
19
|
+
oauth?: boolean;
|
|
18
20
|
url?: string;
|
|
19
21
|
token?: string;
|
|
20
22
|
fetch?: typeof fetch;
|
package/dist/ai-env.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// `qaify ai-env`: tepat sebelum langkah AI, tanya Qaify mesin + model + kredensial agen untuk tugas ini.
|
|
2
2
|
// langganan (default / backend lama) → engine=claude_code, tanpa env file (secret CLAUDE_CODE_OAUTH_TOKEN dipakai)
|
|
3
|
+
// langganan + token disimpan di Qaify → (hanya dengan --oauth) env file berisi CLAUDE_CODE_OAUTH_TOKEN akun,
|
|
4
|
+
// menggantikan secret per repo; step Claude membuang secret lalu memuatnya
|
|
3
5
|
// Claude Code + API key Anthropic → env file berisi ANTHROPIC_API_KEY (step Claude memuatnya & membuang secret OAuth)
|
|
4
6
|
// Qaify Agent (OpenAI-compatible) → env file berisi QAIFY_AI_*; dibaca & dihapus `qaify agent`, tidak masuk env bash
|
|
5
7
|
// agen tidak bisa dipakai (key dihapus / budget habis) → engine=none + hasil gagal berbentuk claude.json di --error-out
|
|
@@ -9,6 +11,7 @@ import { dirname } from 'node:path';
|
|
|
9
11
|
/** Id model yang aman masuk ke --model / output step (cermin AgentSettings::MODEL_PATTERN backend). */
|
|
10
12
|
export const MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/@+-]{0,99}$/;
|
|
11
13
|
const ENV_NAME = /^(ANTHROPIC_[A-Z_]+|QAIFY_AI_[A-Z_]+)$/;
|
|
14
|
+
const OAUTH_NAME = 'CLAUDE_CODE_OAUTH_TOKEN';
|
|
12
15
|
const SECRET_NAME = /(KEY|TOKEN|SECRET)/;
|
|
13
16
|
const SUBSCRIPTION = { engine: 'claude_code', auth: 'subscription', model: null, provider: null, hasKey: false, error: null };
|
|
14
17
|
export async function aiEnv(options) {
|
|
@@ -26,7 +29,12 @@ export async function aiEnv(options) {
|
|
|
26
29
|
res = await (options.fetch ?? fetch)(`${url}/api/ingest/ai-env`, {
|
|
27
30
|
method: 'POST',
|
|
28
31
|
headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
29
|
-
body: JSON.stringify({
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
kind: options.kind,
|
|
34
|
+
...(options.id ? { id: Number(options.id) } : {}),
|
|
35
|
+
...(options.githubRunId ? { github_run_id: options.githubRunId } : {}),
|
|
36
|
+
...(options.oauth ? { oauth: true } : {}),
|
|
37
|
+
}),
|
|
30
38
|
signal: AbortSignal.timeout(30_000),
|
|
31
39
|
});
|
|
32
40
|
}
|
|
@@ -51,7 +59,8 @@ export async function aiEnv(options) {
|
|
|
51
59
|
}
|
|
52
60
|
const env = {};
|
|
53
61
|
for (const [name, value] of Object.entries((data?.env ?? {}))) {
|
|
54
|
-
|
|
62
|
+
const allowed = ENV_NAME.test(name) || (options.oauth === true && name === OAUTH_NAME);
|
|
63
|
+
if (!allowed || typeof value !== 'string' || !value)
|
|
55
64
|
continue;
|
|
56
65
|
if (SECRET_NAME.test(name))
|
|
57
66
|
mask(value);
|
|
@@ -67,7 +76,11 @@ export async function aiEnv(options) {
|
|
|
67
76
|
await writeFile(options.envFile, Object.entries(env).map(([k, v]) => `${k}=${shellQuote(v)}\n`).join(''), { mode: 0o600 });
|
|
68
77
|
await chmod(options.envFile, 0o600).catch(() => { });
|
|
69
78
|
}
|
|
70
|
-
const label = engine === 'qaify_agent'
|
|
79
|
+
const label = engine === 'qaify_agent'
|
|
80
|
+
? `Qaify Agent (${data?.provider ?? 'API key'})`
|
|
81
|
+
: env[OAUTH_NAME] ? 'Claude Code (langganan, token dari Qaify)'
|
|
82
|
+
: hasKey ? 'Claude Code (API key Anthropic)'
|
|
83
|
+
: 'Claude Code (langganan, secret repo)';
|
|
71
84
|
log(`qa-factory: agen AI ${label}${model ? `, model ${model}` : ''}`);
|
|
72
85
|
return { engine, auth: data?.auth === 'key' ? 'key' : 'subscription', model, provider: data?.provider ?? null, hasKey, error: null };
|
|
73
86
|
}
|
package/dist/analyze.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface CliArgs {
|
|
|
32
32
|
id: string | undefined;
|
|
33
33
|
envFile: string | undefined;
|
|
34
34
|
errorOut: string | undefined;
|
|
35
|
+
/** ai-env: workflow ≥ 0.11 menerima token langganan Claude dari Qaify (bukan secret repo) */
|
|
36
|
+
oauth: boolean;
|
|
35
37
|
promptFile: string | undefined;
|
|
36
38
|
instructionsFile: string | undefined;
|
|
37
39
|
schemaFile: string | undefined;
|
package/dist/analyze.js
CHANGED
|
@@ -60,6 +60,7 @@ export function parseArgs(argv) {
|
|
|
60
60
|
id: value('id'),
|
|
61
61
|
envFile: value('env-file'),
|
|
62
62
|
errorOut: value('error-out'),
|
|
63
|
+
oauth: rest.includes('--oauth'),
|
|
63
64
|
promptFile: value('prompt-file'),
|
|
64
65
|
instructionsFile: value('instructions-file'),
|
|
65
66
|
schemaFile: value('schema-file'),
|
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
// qaify autofix-schema --out schema.json --instructions instructions.txt
|
|
25
25
|
// qaify autofix-submit --fix <id> --results claude.json --patch changes.patch --dir <folder kosong>
|
|
26
26
|
// Agen AI pilihan user (Setelan → Agen AI di Qaify), sebelum langkah AI di semua workflow:
|
|
27
|
-
// qaify ai-env --kind <analyze|audit|audit_fix|fix> [--id <id>] --env-file <file> [--error-out claude.json]
|
|
27
|
+
// qaify ai-env --kind <analyze|audit|audit_fix|fix> [--id <id>] --env-file <file> [--error-out claude.json] [--oauth]
|
|
28
28
|
// qaify agent --env-file <file> --schema-file schema.json --out claude.json --prompt-file <f>
|
|
29
29
|
// [--instructions-file <f>] [--input-file <f>] [--tools read,list,grep,write,edit,bash] [--max-turns 80] [--mcp-config mcp.json]
|
|
30
30
|
import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
@@ -39,27 +39,27 @@ import { init, initRunner, NEXT_STEPS, RUNNER_NEXT_STEPS } from './init.js';
|
|
|
39
39
|
import { check } from './check.js';
|
|
40
40
|
import { aiEnv } from './ai-env.js';
|
|
41
41
|
import { agentCommand } from './agent/command.js';
|
|
42
|
-
const USAGE = `Pemakaian:
|
|
43
|
-
qaify init [--force]
|
|
44
|
-
qaify check
|
|
45
|
-
qaify analyze --conclusion <${CONCLUSIONS.join('|')}>
|
|
46
|
-
qaify ai-queue --out <file>
|
|
47
|
-
qaify ai-schema --out <file-schema> [--instructions <file>]
|
|
48
|
-
qaify ai-submit --results <file> [--finalize]
|
|
49
|
-
qaify init-runner [--force]
|
|
50
|
-
qaify audit-context --audit <id> --dir <folder>
|
|
51
|
-
qaify audit-schema (--out <file-schema> [--instructions <file>] | --prompt)
|
|
52
|
-
qaify audit-static --dir <folder> --out <file>
|
|
53
|
-
qaify audit-submit --audit <id> --results <file> --evidence <folder> --context <file>
|
|
54
|
-
qaify fix-context --fix <id> --dir <folder>
|
|
55
|
-
qaify fix-schema --out <file-schema> [--instructions <file>]
|
|
56
|
-
qaify fix-deps --dir <folder>
|
|
57
|
-
qaify fix-diff --dir <folder> --out <folder>
|
|
58
|
-
qaify fix-submit --fix <id> --results <file> --patch <file> --dir <folder>
|
|
59
|
-
qaify autofix-context --fix <id> --dir <folder>
|
|
60
|
-
qaify autofix-schema --out <file-schema> [--instructions <file>]
|
|
61
|
-
qaify autofix-submit --fix <id> --results <file> --patch <file> --dir <folder>
|
|
62
|
-
qaify ai-env --kind <analyze|audit|audit_fix|fix> [--id <id>] --env-file <file> [--error-out <file>]
|
|
42
|
+
const USAGE = `Pemakaian:
|
|
43
|
+
qaify init [--force]
|
|
44
|
+
qaify check
|
|
45
|
+
qaify analyze --conclusion <${CONCLUSIONS.join('|')}>
|
|
46
|
+
qaify ai-queue --out <file>
|
|
47
|
+
qaify ai-schema --out <file-schema> [--instructions <file>]
|
|
48
|
+
qaify ai-submit --results <file> [--finalize]
|
|
49
|
+
qaify init-runner [--force]
|
|
50
|
+
qaify audit-context --audit <id> --dir <folder>
|
|
51
|
+
qaify audit-schema (--out <file-schema> [--instructions <file>] | --prompt)
|
|
52
|
+
qaify audit-static --dir <folder> --out <file>
|
|
53
|
+
qaify audit-submit --audit <id> --results <file> --evidence <folder> --context <file>
|
|
54
|
+
qaify fix-context --fix <id> --dir <folder>
|
|
55
|
+
qaify fix-schema --out <file-schema> [--instructions <file>]
|
|
56
|
+
qaify fix-deps --dir <folder>
|
|
57
|
+
qaify fix-diff --dir <folder> --out <folder>
|
|
58
|
+
qaify fix-submit --fix <id> --results <file> --patch <file> --dir <folder>
|
|
59
|
+
qaify autofix-context --fix <id> --dir <folder>
|
|
60
|
+
qaify autofix-schema --out <file-schema> [--instructions <file>]
|
|
61
|
+
qaify autofix-submit --fix <id> --results <file> --patch <file> --dir <folder>
|
|
62
|
+
qaify ai-env --kind <analyze|audit|audit_fix|fix> [--id <id>] --env-file <file> [--error-out <file>] [--oauth]
|
|
63
63
|
qaify agent --env-file <file> --schema-file <file> --out <file> --prompt-file <file> [--instructions-file <file>] [--input-file <file>] [--tools <daftar>] [--max-turns <n>] [--mcp-config <file>]`;
|
|
64
64
|
const args = parseArgs(process.argv.slice(2));
|
|
65
65
|
const client = createClient();
|
|
@@ -289,6 +289,7 @@ switch (args.command) {
|
|
|
289
289
|
githubRunId: run.github_run_id || undefined,
|
|
290
290
|
envFile: args.envFile,
|
|
291
291
|
errorOut: args.errorOut,
|
|
292
|
+
oauth: args.oauth,
|
|
292
293
|
});
|
|
293
294
|
await writeOutputs({ engine: result.engine, model: result.model ?? '', has_key: String(result.hasKey), provider: result.provider ?? '' });
|
|
294
295
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qaify-playwright-reporter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Reporter Playwright untuk QA Factory (Qaify): kirim hasil test dan artefak ke /api/ingest, tanpa pernah menggagalkan test.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ahmdkenz",
|
package/templates/auto-fix.yml
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
# Butuh di repo ini (sama dengan qa.yml):
|
|
5
5
|
# secret QA_FACTORY_TOKEN token reporter repo ini
|
|
6
6
|
# variable QA_FACTORY_URL URL API Qaify
|
|
7
|
-
# secret CLAUDE_CODE_OAUTH_TOKEN langganan Claude Pro/Max Anda (`claude setup-token`); tidak perlu bila
|
|
8
|
-
#
|
|
9
|
-
# "pakai setelan Agen AI akun
|
|
7
|
+
# secret CLAUDE_CODE_OAUTH_TOKEN opsional: langganan Claude Pro/Max Anda (`claude setup-token`); tidak perlu bila
|
|
8
|
+
# token itu disimpan sekali di Qaify (Setelan → Agen AI) atau agen "Perbaikan test"
|
|
9
|
+
# memakai API key — keduanya butuh admin repo memilih "pakai setelan Agen AI akun
|
|
10
|
+
# saya" di Otomatisasi & AI
|
|
10
11
|
# GitHub App Qaify butuh izin Actions, Contents, dan Pull requests: Read and write di repo ini.
|
|
11
12
|
# Job "fix" menjalankan agen tanpa token push; job "submit" (VM bersih) meng-clone ulang, menerapkan patch, lalu push.
|
|
12
13
|
# Nama file harus tetap auto-fix.yml.
|
|
@@ -56,7 +57,7 @@ jobs:
|
|
|
56
57
|
tools: composer
|
|
57
58
|
|
|
58
59
|
- name: Pasang Qaify CLI
|
|
59
|
-
run: npm install -g qaify-playwright-reporter@0.
|
|
60
|
+
run: npm install -g qaify-playwright-reporter@0.11
|
|
60
61
|
|
|
61
62
|
# token clone sekali pakai (read-only, hanya repo ini) dicabut sebelum agen berjalan
|
|
62
63
|
- name: Ambil kegagalan & clone repo
|
|
@@ -87,7 +88,7 @@ jobs:
|
|
|
87
88
|
QA_FACTORY_TOKEN: ${{ secrets.QA_FACTORY_TOKEN }}
|
|
88
89
|
run: |
|
|
89
90
|
qaify ai-env --kind fix --id "${{ inputs.fix_attempt_id }}" \
|
|
90
|
-
--env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$WORK/.qaify/claude.json"
|
|
91
|
+
--env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$WORK/.qaify/claude.json" --oauth
|
|
91
92
|
|
|
92
93
|
# hanya kredensial AI (secret langganan / API key Anthropic dari Qaify); tidak ada token Qaify maupun token push
|
|
93
94
|
- name: Perbaiki dengan Claude Code
|
|
@@ -102,15 +103,16 @@ jobs:
|
|
|
102
103
|
run: |
|
|
103
104
|
# tanpa secret langganan dan tanpa API key: Claude Code pasti "Not logged in"; catat penyebabnya, jangan dipasang
|
|
104
105
|
if [ ! -f "$RUNNER_TEMP/qaify-ai.env" ] && [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
|
105
|
-
echo '::error::Secret CLAUDE_CODE_OAUTH_TOKEN kosong di repo ini dan engineer tidak memakai API key. Jalankan "claude setup-token" lalu isi secret-nya, atau
|
|
106
|
-
printf '%s' '{"type":"result","subtype":"error_qaify","is_error":true,"error_code":"ai_not_logged_in","result":"Not logged in (
|
|
106
|
+
echo '::error::Secret CLAUDE_CODE_OAUTH_TOKEN kosong di repo ini dan engineer tidak memakai API key. Jalankan "claude setup-token" lalu isi secret-nya, atau simpan token itu sekali di Qaify (Setelan, Agen AI) agar berlaku untuk semua repo, atau pakai API key di sana.'
|
|
107
|
+
printf '%s' '{"type":"result","subtype":"error_qaify","is_error":true,"error_code":"ai_not_logged_in","result":"Not logged in (token langganan Claude kosong: tidak ada di Qaify maupun secret repo)"}' > ../.qaify/claude.json
|
|
107
108
|
exit 1
|
|
108
109
|
fi
|
|
109
110
|
npm install -g @anthropic-ai/claude-code
|
|
110
|
-
# API key Anthropic dari Qaify menggantikan
|
|
111
|
+
# API key Anthropic / token langganan Claude dari Qaify (Setelan → Agen AI) menggantikan secret repo
|
|
111
112
|
if [ -f "$RUNNER_TEMP/qaify-ai.env" ]; then
|
|
113
|
+
unset CLAUDE_CODE_OAUTH_TOKEN
|
|
112
114
|
set -a; . "$RUNNER_TEMP/qaify-ai.env"; set +a
|
|
113
|
-
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
115
|
+
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
114
116
|
fi
|
|
115
117
|
claude -p "$(cat ../.qaify/prompt.txt)" \
|
|
116
118
|
--model "$MODEL" \
|
|
@@ -160,7 +162,7 @@ jobs:
|
|
|
160
162
|
- uses: actions/setup-node@v4
|
|
161
163
|
with: { node-version: 22 }
|
|
162
164
|
- name: Pasang Qaify CLI
|
|
163
|
-
run: npm install -g qaify-playwright-reporter@0.
|
|
165
|
+
run: npm install -g qaify-playwright-reporter@0.11
|
|
164
166
|
- uses: actions/download-artifact@v4
|
|
165
167
|
continue-on-error: true
|
|
166
168
|
with:
|
package/templates/qa.yml
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
# secret QA_FACTORY_TOKEN token reporter dari Pengaturan → Token Reporter
|
|
4
4
|
# variable QA_FACTORY_URL URL API QA Factory
|
|
5
5
|
# secret CLAUDE_CODE_OAUTH_TOKEN opsional, analisis AI dengan langganan Claude Pro/Max Anda (`claude setup-token`);
|
|
6
|
-
#
|
|
6
|
+
# tidak perlu bila token itu disimpan sekali di Qaify → Setelan → Agen AI (atau
|
|
7
|
+
# pakai API key di sana) dan admin repo memilih "pakai setelan Agen AI akun saya"
|
|
7
8
|
# variable QA_FACTORY_AI_MODEL opsional, default sonnet (langganan tanpa model dari Qaify)
|
|
8
9
|
# dan devDependency qaify-playwright-reporter (sudah terpasang bila Anda menjalankan `npx qaify init`).
|
|
9
10
|
# Nama file harus tetap qa.yml.
|
|
@@ -34,8 +35,9 @@ jobs:
|
|
|
34
35
|
|
|
35
36
|
# Status final run & analisis kegagalan. Tetap jalan walau test gagal / di-cancel.
|
|
36
37
|
# Analisis AI memakai langganan Claude Pro/Max Anda lewat Claude Code (QA Factory tidak memanggil AI):
|
|
37
|
-
# claude setup-token → simpan
|
|
38
|
-
# kegagalan tetap diklasifikasi aturan / "belum jelas". Kuota langganan dipakai
|
|
38
|
+
# claude setup-token → simpan sekali di Qaify (Setelan → Agen AI) atau sebagai secret CLAUDE_CODE_OAUTH_TOKEN.
|
|
39
|
+
# Tanpa token (mis. PR dari fork) kegagalan tetap diklasifikasi aturan / "belum jelas". Kuota langganan dipakai
|
|
40
|
+
# bersama pemakaian pribadi.
|
|
39
41
|
analyze:
|
|
40
42
|
needs: test
|
|
41
43
|
if: always()
|
|
@@ -68,7 +70,7 @@ jobs:
|
|
|
68
70
|
id: ai
|
|
69
71
|
if: steps.queue.outputs.count != '0'
|
|
70
72
|
continue-on-error: true
|
|
71
|
-
run: npx qaify ai-env --kind analyze --env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$RUNNER_TEMP/qaf/claude.json"
|
|
73
|
+
run: npx qaify ai-env --kind analyze --env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$RUNNER_TEMP/qaf/claude.json" --oauth
|
|
72
74
|
|
|
73
75
|
# folder kosong: .claude/ dan .mcp.json milik repo tidak ikut termuat; semua tool dimatikan
|
|
74
76
|
- name: Analisis dengan Claude Code
|
|
@@ -83,10 +85,11 @@ jobs:
|
|
|
83
85
|
MODEL: ${{ steps.ai.outputs.model || vars.QA_FACTORY_AI_MODEL || 'sonnet' }}
|
|
84
86
|
run: |
|
|
85
87
|
npm install -g @anthropic-ai/claude-code
|
|
86
|
-
# API key Anthropic dari Qaify menggantikan
|
|
88
|
+
# API key Anthropic / token langganan Claude dari Qaify (Setelan → Agen AI) menggantikan secret repo
|
|
87
89
|
if [ -f "$RUNNER_TEMP/qaify-ai.env" ]; then
|
|
90
|
+
unset CLAUDE_CODE_OAUTH_TOKEN
|
|
88
91
|
set -a; . "$RUNNER_TEMP/qaify-ai.env"; set +a
|
|
89
|
-
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
92
|
+
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
90
93
|
fi
|
|
91
94
|
claude -p "Analisis setiap kegagalan test pada input JSON." \
|
|
92
95
|
--model "$MODEL" \
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
# secret QA_FACTORY_TOKEN token reporter repo runner (Pengaturan → Token Reporter)
|
|
5
5
|
# variable QA_FACTORY_URL URL API Qaify
|
|
6
6
|
# secret CLAUDE_CODE_OAUTH_TOKEN opsional: agen yang memakai langganan Claude Pro/Max (`claude setup-token`);
|
|
7
|
-
# tidak perlu bila
|
|
7
|
+
# tidak perlu bila token itu sudah disimpan sekali di Qaify (Setelan → Agen AI,
|
|
8
|
+
# berlaku untuk semua repo) atau semua agen memakai API key
|
|
8
9
|
# variable QA_FACTORY_AUDIT_MODE opsional, `static` / `claude`; hanya dipakai bila Qaify tidak mengirim mode
|
|
9
10
|
# variable QA_FACTORY_AI_MODEL opsional, default sonnet (langganan tanpa model dari Qaify)
|
|
10
11
|
# variable QA_FACTORY_MCP_VERSION opsional, versi @playwright/mcp (default latest)
|
|
@@ -61,7 +62,7 @@ jobs:
|
|
|
61
62
|
tools: composer
|
|
62
63
|
|
|
63
64
|
- name: Pasang Qaify CLI
|
|
64
|
-
run: npm install -g qaify-playwright-reporter@0.
|
|
65
|
+
run: npm install -g qaify-playwright-reporter@0.11 playwright-core@1
|
|
65
66
|
|
|
66
67
|
# token clone sekali pakai (read-only, hanya repo FE + BE) dicabut sebelum auditor berjalan
|
|
67
68
|
- name: Ambil konteks & clone repo FE + BE
|
|
@@ -81,7 +82,7 @@ jobs:
|
|
|
81
82
|
QA_FACTORY_TOKEN: ${{ secrets.QA_FACTORY_TOKEN }}
|
|
82
83
|
run: |
|
|
83
84
|
qaify ai-env --kind audit --id "${{ inputs.audit_id }}" \
|
|
84
|
-
--env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$WORK/.qaify/claude.json"
|
|
85
|
+
--env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$WORK/.qaify/claude.json" --oauth
|
|
85
86
|
|
|
86
87
|
# pilihan Qaify → variable QA_FACTORY_AUDIT_MODE → claude bila secret ada; AI tanpa langganan / API key → static
|
|
87
88
|
- name: Tentukan mode audit
|
|
@@ -92,7 +93,7 @@ jobs:
|
|
|
92
93
|
HAS_KEY: ${{ steps.ai.outputs.has_key }}
|
|
93
94
|
ENGINE: ${{ steps.ai.outputs.engine || 'claude_code' }}
|
|
94
95
|
run: |
|
|
95
|
-
mode="${REQUESTED:-$([ "$HAS_CLAUDE" = true ] && echo claude || echo static)}"
|
|
96
|
+
mode="${REQUESTED:-$([ "$HAS_CLAUDE" = true ] || [ "$HAS_KEY" = true ] && echo claude || echo static)}"
|
|
96
97
|
if [ "$mode" != static ] && [ "$mode" != claude ]; then
|
|
97
98
|
echo "::warning::Mode audit tidak dikenal ($mode); memakai static."
|
|
98
99
|
mode=static
|
|
@@ -101,7 +102,7 @@ jobs:
|
|
|
101
102
|
# hasil gagal + penyebabnya sudah ditulis step "Pilih agen AI"
|
|
102
103
|
mode=failed
|
|
103
104
|
elif [ "$mode" = claude ] && [ "$HAS_CLAUDE" != true ] && [ "$HAS_KEY" != true ]; then
|
|
104
|
-
echo "::warning::Mode AI diminta tetapi secret CLAUDE_CODE_OAUTH_TOKEN
|
|
105
|
+
echo "::warning::Mode AI diminta tetapi token langganan Claude kosong (tidak disimpan di Qaify, Setelan → Agen AI, maupun secret CLAUDE_CODE_OAUTH_TOKEN repo) dan agen Auditor tidak memakai API key; audit dijalankan tanpa AI."
|
|
105
106
|
mode=static
|
|
106
107
|
fi
|
|
107
108
|
echo "qa-factory: mode audit $mode ($ENGINE)"
|
|
@@ -137,10 +138,11 @@ jobs:
|
|
|
137
138
|
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
138
139
|
MODEL: ${{ steps.ai.outputs.model || vars.QA_FACTORY_AI_MODEL || 'sonnet' }}
|
|
139
140
|
run: |
|
|
140
|
-
# API key Anthropic dari Qaify menggantikan
|
|
141
|
+
# API key Anthropic / token langganan Claude dari Qaify (Setelan → Agen AI) menggantikan secret repo
|
|
141
142
|
if [ -f "$RUNNER_TEMP/qaify-ai.env" ]; then
|
|
143
|
+
unset CLAUDE_CODE_OAUTH_TOKEN
|
|
142
144
|
set -a; . "$RUNNER_TEMP/qaify-ai.env"; set +a
|
|
143
|
-
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
145
|
+
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
144
146
|
fi
|
|
145
147
|
claude -p "$(cat .qaify/prompt.txt)" \
|
|
146
148
|
--model "$MODEL" \
|
package/templates/qaify-fix.yml
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
# Butuh di repo runner ini (sama dengan qaify-audit.yml):
|
|
4
4
|
# secret QA_FACTORY_TOKEN token reporter repo runner
|
|
5
5
|
# variable QA_FACTORY_URL URL API Qaify
|
|
6
|
-
# secret CLAUDE_CODE_OAUTH_TOKEN langganan Claude Pro/Max Anda (`claude setup-token`)
|
|
7
|
-
# memakai langganan
|
|
6
|
+
# secret CLAUDE_CODE_OAUTH_TOKEN opsional: langganan Claude Pro/Max Anda (`claude setup-token`) untuk engineer yang
|
|
7
|
+
# memakai langganan; tidak perlu bila token itu sudah disimpan sekali di Qaify
|
|
8
|
+
# (Setelan → Agen AI, berlaku untuk semua repo) atau semua engineer memakai API key
|
|
8
9
|
# GitHub App Qaify butuh izin Contents: Read and write dan Pull requests: Read and write di repo FE/BE.
|
|
9
10
|
# Engineer (Nanda / Fajar / Pak Yoga) dipilih Qaify per temuan menurut kompleksitas atau pilihan Anda; mesin, model,
|
|
10
11
|
# dan API key-nya dari Setelan → Agen AI (Claude Code dengan langganan / API key Anthropic, atau Qaify Agent dengan
|
|
@@ -59,7 +60,7 @@ jobs:
|
|
|
59
60
|
tools: composer
|
|
60
61
|
|
|
61
62
|
- name: Pasang Qaify CLI
|
|
62
|
-
run: npm install -g qaify-playwright-reporter@0.
|
|
63
|
+
run: npm install -g qaify-playwright-reporter@0.11
|
|
63
64
|
|
|
64
65
|
# token clone sekali pakai (read-only, hanya repo target) dicabut sebelum agen berjalan
|
|
65
66
|
- name: Ambil temuan & clone repo target
|
|
@@ -88,7 +89,7 @@ jobs:
|
|
|
88
89
|
QA_FACTORY_TOKEN: ${{ secrets.QA_FACTORY_TOKEN }}
|
|
89
90
|
run: |
|
|
90
91
|
qaify ai-env --kind audit_fix --id "${{ inputs.fix_id }}" \
|
|
91
|
-
--env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$WORK/.qaify/claude.json"
|
|
92
|
+
--env-file "$RUNNER_TEMP/qaify-ai.env" --error-out "$WORK/.qaify/claude.json" --oauth
|
|
92
93
|
|
|
93
94
|
# hanya kredensial AI (secret langganan / API key Anthropic dari Qaify); tidak ada token Qaify maupun token push
|
|
94
95
|
- name: Perbaiki dengan Claude Code
|
|
@@ -102,15 +103,16 @@ jobs:
|
|
|
102
103
|
run: |
|
|
103
104
|
# tanpa secret langganan dan tanpa API key: Claude Code pasti "Not logged in"; catat penyebabnya, jangan dipasang
|
|
104
105
|
if [ ! -f "$RUNNER_TEMP/qaify-ai.env" ] && [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
|
105
|
-
echo '::error::Secret CLAUDE_CODE_OAUTH_TOKEN kosong di repo runner ini dan engineer tidak memakai API key. Jalankan "claude setup-token" lalu isi secret-nya, atau
|
|
106
|
-
printf '%s' '{"type":"result","subtype":"error_qaify","is_error":true,"error_code":"ai_not_logged_in","result":"Not logged in (
|
|
106
|
+
echo '::error::Secret CLAUDE_CODE_OAUTH_TOKEN kosong di repo runner ini dan engineer tidak memakai API key. Jalankan "claude setup-token" lalu isi secret-nya, atau simpan token itu sekali di Qaify (Setelan, Agen AI) agar berlaku untuk semua repo, atau pakai API key di sana.'
|
|
107
|
+
printf '%s' '{"type":"result","subtype":"error_qaify","is_error":true,"error_code":"ai_not_logged_in","result":"Not logged in (token langganan Claude kosong: tidak ada di Qaify maupun secret repo)"}' > ../.qaify/claude.json
|
|
107
108
|
exit 1
|
|
108
109
|
fi
|
|
109
110
|
npm install -g @anthropic-ai/claude-code
|
|
110
|
-
# API key Anthropic dari Qaify menggantikan
|
|
111
|
+
# API key Anthropic / token langganan Claude dari Qaify (Setelan → Agen AI) menggantikan secret repo
|
|
111
112
|
if [ -f "$RUNNER_TEMP/qaify-ai.env" ]; then
|
|
113
|
+
unset CLAUDE_CODE_OAUTH_TOKEN
|
|
112
114
|
set -a; . "$RUNNER_TEMP/qaify-ai.env"; set +a
|
|
113
|
-
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
115
|
+
rm -f "$RUNNER_TEMP/qaify-ai.env"
|
|
114
116
|
fi
|
|
115
117
|
claude -p "$(cat ../.qaify/prompt.txt)" \
|
|
116
118
|
--model "$MODEL" \
|
|
@@ -158,7 +160,7 @@ jobs:
|
|
|
158
160
|
- uses: actions/setup-node@v4
|
|
159
161
|
with: { node-version: 22 }
|
|
160
162
|
- name: Pasang Qaify CLI
|
|
161
|
-
run: npm install -g qaify-playwright-reporter@0.
|
|
163
|
+
run: npm install -g qaify-playwright-reporter@0.11
|
|
162
164
|
- uses: actions/download-artifact@v4
|
|
163
165
|
continue-on-error: true
|
|
164
166
|
with:
|