@automatify-au/cli 0.1.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 +389 -0
- package/dist/automatify.js +4011 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# @automatify-au/cli
|
|
2
|
+
|
|
3
|
+
Minimal Forge-first CLI for Automatify Jira TestOps.
|
|
4
|
+
|
|
5
|
+
Current product stance:
|
|
6
|
+
- Jira UI is the primary day-to-day surface for most users.
|
|
7
|
+
- The CLI is the primary admin and automation surface for setup, ingestion, diagnostics, reporting, and CI.
|
|
8
|
+
- POC audience: operators, CI, internal support, and customer admins running controlled setup/import flows.
|
|
9
|
+
- Future customer-admin packaging is expected before any broader distribution.
|
|
10
|
+
- Any future all-user CLI requires a different auth/onboarding model than the current project-scoped admin key transport.
|
|
11
|
+
|
|
12
|
+
## Architecture boundary (must hold)
|
|
13
|
+
- Thin client only.
|
|
14
|
+
- No separate backend.
|
|
15
|
+
- No duplicate domain/business logic in CLI.
|
|
16
|
+
- CLI commands must call shared Forge contracts (resolver/webtrigger paths) as they are introduced.
|
|
17
|
+
|
|
18
|
+
## MVP non-goals
|
|
19
|
+
- No separate backend.
|
|
20
|
+
- No duplicate domain/business logic in CLI.
|
|
21
|
+
- No replacement of Jira UI as a primary product surface.
|
|
22
|
+
- No backend-assisted/hybrid logic in this phase.
|
|
23
|
+
|
|
24
|
+
## Install and run
|
|
25
|
+
|
|
26
|
+
### From npm (published package)
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g @automatify-au/cli
|
|
29
|
+
automatify --help
|
|
30
|
+
automatify testops --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### From repository (development)
|
|
34
|
+
```bash
|
|
35
|
+
pnpm install
|
|
36
|
+
pnpm --filter @automatify-au/cli build
|
|
37
|
+
pnpm --filter @automatify-au/cli bundle
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This produces a single self-contained bundle at `dist/automatify.js` (≈125 KB) with `@automatify/shared-types` inlined. No runtime dependencies.
|
|
41
|
+
|
|
42
|
+
Run built CLI:
|
|
43
|
+
```bash
|
|
44
|
+
automatify testops --help # if linked globally (npm link)
|
|
45
|
+
node apps/cli/dist/automatify.js --help # direct node run
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Dev run (for local iteration):
|
|
49
|
+
```bash
|
|
50
|
+
pnpm --filter @automatify-au/cli run cli:dev -- --help
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Bundle and publish
|
|
54
|
+
```bash
|
|
55
|
+
cd apps/cli
|
|
56
|
+
npm test # optional but recommended local preflight
|
|
57
|
+
npm pack --dry-run # inspect final tarball contents
|
|
58
|
+
npm publish --dry-run --access public # simulate publish against npm
|
|
59
|
+
npm publish --access public # publish to npm
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Publish notes:
|
|
63
|
+
- `prepack` now rebuilds `dist/automatify.js` automatically, so `npm pack` and `npm publish` do not rely on a stale bundle.
|
|
64
|
+
- `prepublishOnly` runs the CLI test suite and then rebuilds the bundle before a real publish.
|
|
65
|
+
- Current package target is `@automatify-au/cli`; verify npm auth with `npm whoami` if needed before publishing.
|
|
66
|
+
|
|
67
|
+
## Required configuration
|
|
68
|
+
Minimum:
|
|
69
|
+
- `JIRA_BASE_URL`
|
|
70
|
+
- At least one of `JIRA_PROJECT_KEY` or `JIRA_ISSUE_KEY`
|
|
71
|
+
- `TESTOPS_FORGE_ENDPOINT` for commands that call Forge contracts (`doctor`, `ingest`, `run`, `sync`)
|
|
72
|
+
- `TESTOPS_FORGE_AUTH_TOKEN` from the one-time token shown in Forge `Operations -> CLI access`
|
|
73
|
+
|
|
74
|
+
Optional:
|
|
75
|
+
- `TESTOPS_FORGE_TIMEOUT_MS`
|
|
76
|
+
- `TESTOPS_FORGE_MAX_RETRIES`
|
|
77
|
+
- `TESTOPS_FORGE_RETRY_DELAY_MS`
|
|
78
|
+
- `TESTOPS_AUTH_MODE`, `JIRA_EMAIL`, `JIRA_API_TOKEN` (when auth mode requires)
|
|
79
|
+
|
|
80
|
+
## Command reference (MVP)
|
|
81
|
+
|
|
82
|
+
All TestOps commands are invoked as `automatify testops <command>`:
|
|
83
|
+
|
|
84
|
+
- `bdd`
|
|
85
|
+
- `automatify testops bdd scenarios show --id <SCENARIO_ID>`
|
|
86
|
+
- `cases`
|
|
87
|
+
- `automatify testops cases list`
|
|
88
|
+
- `automatify testops cases show --key <TEST_CASE_KEY>`
|
|
89
|
+
- `automatify testops cases bdd list --key <TEST_CASE_KEY>`
|
|
90
|
+
- `automatify testops cases runs list --key <TEST_CASE_KEY>`
|
|
91
|
+
- `config`
|
|
92
|
+
- `automatify testops config show`
|
|
93
|
+
- `automatify testops config validate`
|
|
94
|
+
- `ingest`
|
|
95
|
+
- `automatify testops ingest feature --file <path>` or `--stdin`
|
|
96
|
+
- `run`
|
|
97
|
+
- `automatify testops run upload --file <path>` or `--stdin`
|
|
98
|
+
- `runs`
|
|
99
|
+
- `automatify testops runs show --id <RUN_ID>`
|
|
100
|
+
- `suites`
|
|
101
|
+
- `automatify testops suites list`
|
|
102
|
+
- `automatify testops suites show --key <SUITE_KEY>`
|
|
103
|
+
- `automatify testops suites cases list --key <SUITE_KEY>`
|
|
104
|
+
- `doctor`
|
|
105
|
+
- `automatify testops doctor check`
|
|
106
|
+
- `automatify testops doctor check --json`
|
|
107
|
+
- `sync` (gated)
|
|
108
|
+
- enable with `TESTOPS_ENABLE_SYNC=1`
|
|
109
|
+
- `automatify testops sync status`
|
|
110
|
+
- `automatify testops sync reconcile --confirm RECONCILE`
|
|
111
|
+
|
|
112
|
+
## `automatify testops auto` (MVP)
|
|
113
|
+
Purpose:
|
|
114
|
+
- deterministic onboarding/import helper for local and CI workflows.
|
|
115
|
+
- thin orchestration only; domain logic stays in Forge contracts/services.
|
|
116
|
+
|
|
117
|
+
Supported commands:
|
|
118
|
+
- `automatify testops auto --dry-run`
|
|
119
|
+
- `automatify testops auto`
|
|
120
|
+
|
|
121
|
+
Required env/config for real upload mode:
|
|
122
|
+
- `JIRA_BASE_URL`
|
|
123
|
+
- `JIRA_PROJECT_KEY` (or `--project-key`)
|
|
124
|
+
- `TESTOPS_FORGE_ENDPOINT`
|
|
125
|
+
- `TESTOPS_FORGE_AUTH_TOKEN` for the repo-owned authenticated webtrigger transport
|
|
126
|
+
|
|
127
|
+
One-time Forge transport setup:
|
|
128
|
+
```bash
|
|
129
|
+
cd apps/forge
|
|
130
|
+
forge deploy
|
|
131
|
+
forge install --upgrade --site automatify-com-au.atlassian.net --product Jira -e development --confirm-scopes --non-interactive
|
|
132
|
+
forge webtrigger create --functionKey cli-transport-webtrigger --site automatify-com-au.atlassian.net --product Jira -e development
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Then open the Jira project page, go to `Operations -> CLI access`, create a CLI key, and copy the token immediately. It is shown once only.
|
|
136
|
+
|
|
137
|
+
Export the webtrigger URL and the one-time token for CLI use:
|
|
138
|
+
```bash
|
|
139
|
+
export TESTOPS_FORGE_ENDPOINT="<webtrigger-url>"
|
|
140
|
+
export TESTOPS_FORGE_AUTH_TOKEN="<one-time-token-from-forge-ui>"
|
|
141
|
+
export JIRA_BASE_URL="https://automatify-com-au.atlassian.net"
|
|
142
|
+
export JIRA_PROJECT_KEY="DEV"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Transport notes:
|
|
146
|
+
- Bearer auth is required for operator/CI use. Forge stores only the token hash plus metadata.
|
|
147
|
+
- Tokens are project-scoped, shown once at creation time, and can be revoked from the Forge UI.
|
|
148
|
+
- Expired or revoked tokens are rejected by the transport.
|
|
149
|
+
|
|
150
|
+
Scenario automation callback example:
|
|
151
|
+
```bash
|
|
152
|
+
curl -sS "$TESTOPS_FORGE_ENDPOINT" \
|
|
153
|
+
-H "authorization: Bearer $TESTOPS_FORGE_AUTH_TOKEN" \
|
|
154
|
+
-H "content-type: application/json" \
|
|
155
|
+
-d '{
|
|
156
|
+
"contract":"updateScenarioAutomationStatus",
|
|
157
|
+
"payload":{
|
|
158
|
+
"context":{"projectKey":"DEV"},
|
|
159
|
+
"scenarioId":"manual:checkout:guest-payment",
|
|
160
|
+
"status":"running",
|
|
161
|
+
"externalRunId":"gha-1024",
|
|
162
|
+
"externalRunUrl":"https://github.com/Automatify-Pty-Ltd/automatify-jira-testops/actions/runs/1024",
|
|
163
|
+
"responseStatus":202,
|
|
164
|
+
"responseSnippet":"workflow is running"
|
|
165
|
+
}
|
|
166
|
+
}' | jq
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
You can also resolve the target by `automationId` or `scenarioRef` instead of `scenarioId`.
|
|
170
|
+
|
|
171
|
+
GitHub Actions callback example:
|
|
172
|
+
```yaml
|
|
173
|
+
- name: Report scenario automation status to Forge
|
|
174
|
+
if: ${{ always() }}
|
|
175
|
+
env:
|
|
176
|
+
TESTOPS_FORGE_ENDPOINT: ${{ secrets.TESTOPS_FORGE_ENDPOINT }}
|
|
177
|
+
TESTOPS_FORGE_AUTH_TOKEN: ${{ secrets.TESTOPS_FORGE_AUTH_TOKEN }}
|
|
178
|
+
TESTOPS_PROJECT_KEY: DEV
|
|
179
|
+
TESTOPS_SCENARIO_REF: checkout.feature#3
|
|
180
|
+
TESTOPS_STATUS: ${{ job.status == 'success' && 'passed' || job.status == 'cancelled' && 'cancelled' || 'failed' }}
|
|
181
|
+
run: |
|
|
182
|
+
curl -sS "$TESTOPS_FORGE_ENDPOINT" \
|
|
183
|
+
-H "authorization: Bearer $TESTOPS_FORGE_AUTH_TOKEN" \
|
|
184
|
+
-H "content-type: application/json" \
|
|
185
|
+
-d "{
|
|
186
|
+
\"contract\":\"updateScenarioAutomationStatus\",
|
|
187
|
+
\"payload\":{
|
|
188
|
+
\"context\":{\"projectKey\":\"$TESTOPS_PROJECT_KEY\"},
|
|
189
|
+
\"scenarioRef\":\"$TESTOPS_SCENARIO_REF\",
|
|
190
|
+
\"status\":\"$TESTOPS_STATUS\",
|
|
191
|
+
\"externalRunId\":\"${GITHUB_RUN_ID}\",
|
|
192
|
+
\"externalRunUrl\":\"https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}\",
|
|
193
|
+
\"responseStatus\":200,
|
|
194
|
+
\"responseSnippet\":\"GitHub Actions callback from ${GITHUB_WORKFLOW}\"
|
|
195
|
+
}
|
|
196
|
+
}"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Azure DevOps callback example:
|
|
200
|
+
```yaml
|
|
201
|
+
- bash: |
|
|
202
|
+
set -euo pipefail
|
|
203
|
+
if [ "$(Agent.JobStatus)" = "Succeeded" ]; then
|
|
204
|
+
TESTOPS_STATUS="passed"
|
|
205
|
+
elif [ "$(Agent.JobStatus)" = "Canceled" ]; then
|
|
206
|
+
TESTOPS_STATUS="cancelled"
|
|
207
|
+
else
|
|
208
|
+
TESTOPS_STATUS="failed"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
curl -sS "$(TESTOPS_FORGE_ENDPOINT)" \
|
|
212
|
+
-H "authorization: Bearer $(TESTOPS_FORGE_AUTH_TOKEN)" \
|
|
213
|
+
-H "content-type: application/json" \
|
|
214
|
+
-d "{
|
|
215
|
+
\"contract\":\"updateScenarioAutomationStatus\",
|
|
216
|
+
\"payload\":{
|
|
217
|
+
\"context\":{\"projectKey\":\"DEV\"},
|
|
218
|
+
\"scenarioRef\":\"checkout.feature#3\",
|
|
219
|
+
\"status\":\"${TESTOPS_STATUS}\",
|
|
220
|
+
\"externalRunId\":\"$(Build.BuildId)\",
|
|
221
|
+
\"externalRunUrl\":\"$(System.CollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)\",
|
|
222
|
+
\"responseStatus\":200,
|
|
223
|
+
\"responseSnippet\":\"Azure DevOps callback from $(Build.DefinitionName)\"
|
|
224
|
+
}
|
|
225
|
+
}"
|
|
226
|
+
displayName: Report scenario automation status to Forge
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Hierarchy browse examples:
|
|
230
|
+
```bash
|
|
231
|
+
automatify testops cases list --project-key DEV
|
|
232
|
+
automatify testops cases show --project-key DEV --key TC-1 --json
|
|
233
|
+
automatify testops cases bdd list --project-key DEV --key TC-1 --json
|
|
234
|
+
automatify testops cases runs list --project-key DEV --key TC-1 --json
|
|
235
|
+
automatify testops bdd scenarios show --project-key DEV --id <SCENARIO_ID> --json
|
|
236
|
+
automatify testops runs show --project-key DEV --id <RUN_ID> --json
|
|
237
|
+
automatify testops suites list --project-key DEV --json
|
|
238
|
+
automatify testops suites cases list --project-key DEV --key TS-1
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Recommended hierarchy browse flow:
|
|
242
|
+
```bash
|
|
243
|
+
# 1. Find a case worth inspecting.
|
|
244
|
+
automatify testops cases list --project-key DEV
|
|
245
|
+
|
|
246
|
+
# 2. Inspect one case in detail.
|
|
247
|
+
automatify testops cases show --project-key DEV --key TC-145 --json
|
|
248
|
+
|
|
249
|
+
# 3. Inspect the BDD scenarios linked to that case.
|
|
250
|
+
automatify testops cases bdd list --project-key DEV --key TC-145 --json
|
|
251
|
+
|
|
252
|
+
# 4. Inspect the execution history linked to that case.
|
|
253
|
+
automatify testops cases runs list --project-key DEV --key TC-145 --json
|
|
254
|
+
|
|
255
|
+
# 5. Drill into one scenario or one run as needed.
|
|
256
|
+
automatify testops bdd scenarios show --project-key DEV --id <SCENARIO_ID> --json
|
|
257
|
+
automatify testops runs show --project-key DEV --id <RUN_ID> --json
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Coverage and readiness report via the Forge transport:
|
|
261
|
+
```bash
|
|
262
|
+
curl -sS "$TESTOPS_FORGE_ENDPOINT" \
|
|
263
|
+
-H "authorization: Bearer $TESTOPS_FORGE_AUTH_TOKEN" \
|
|
264
|
+
-H "content-type: application/json" \
|
|
265
|
+
-d '{"contract":"getCoverageReport","payload":{"context":{"projectKey":"DEV"}}}' | jq
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Deterministic dry-run preview (human):
|
|
269
|
+
```bash
|
|
270
|
+
pnpm --filter @automatify-au/cli build
|
|
271
|
+
automatify testops auto \
|
|
272
|
+
--dry-run \
|
|
273
|
+
--root apps/cli/test-fixtures/auto/execution-layout
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Deterministic dry-run preview (JSON for CI):
|
|
277
|
+
```bash
|
|
278
|
+
preview_json="$(automatify testops auto \
|
|
279
|
+
--dry-run \
|
|
280
|
+
--root apps/cli/test-fixtures/auto/execution-layout \
|
|
281
|
+
--output json)"
|
|
282
|
+
echo "$preview_json"
|
|
283
|
+
node -e 'const p=JSON.parse(process.argv[1]); if(!p.preview || !p.preview.mapping){process.exit(2)}' "$preview_json"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Real execution mode (Forge upload path):
|
|
287
|
+
```bash
|
|
288
|
+
automatify testops auto \
|
|
289
|
+
--root apps/cli/test-fixtures/auto/execution-layout \
|
|
290
|
+
--project-key DEV \
|
|
291
|
+
--force \
|
|
292
|
+
--output json
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Recommended CI sequence:
|
|
296
|
+
1. `automatify testops config validate`
|
|
297
|
+
2. `automatify testops doctor check --json`
|
|
298
|
+
3. `automatify testops auto --dry-run --output json ...`
|
|
299
|
+
4. `automatify testops auto --force --output json ...`
|
|
300
|
+
|
|
301
|
+
`automatify testops auto` MVP limits (explicit):
|
|
302
|
+
- detection scope is Playwright, pytest, cucumber/behave hints only.
|
|
303
|
+
- artifact scope is JUnit XML + Cucumber JSON + `.feature` files.
|
|
304
|
+
- mapping is deterministic MVP only (issue-key and supported exact-name matching).
|
|
305
|
+
- no AI-based matching, no backend-assisted matching, no storage surgery actions.
|
|
306
|
+
|
|
307
|
+
### `automatify testops auto` pilot adoption checklist
|
|
308
|
+
1. Run deterministic preview:
|
|
309
|
+
- `automatify testops auto --dry-run --output json --root <repo-root>`
|
|
310
|
+
2. Confirm preview is actionable:
|
|
311
|
+
- framework mode is not `unknown` unless expected,
|
|
312
|
+
- discovered artifacts count is non-zero for upload scenarios,
|
|
313
|
+
- unmatched diagnostics are reviewed.
|
|
314
|
+
3. Verify readiness gate:
|
|
315
|
+
- `automatify testops doctor check --json`
|
|
316
|
+
4. Run first real upload in controlled branch/commit:
|
|
317
|
+
- `automatify testops auto --force --output json --project-key <KEY> --root <repo-root>`
|
|
318
|
+
5. Record command result and warnings in pilot notes.
|
|
319
|
+
|
|
320
|
+
## Deterministic exit-code mapping
|
|
321
|
+
- `0` success
|
|
322
|
+
- `1` internal/runtime error
|
|
323
|
+
- `2` usage/argument errors
|
|
324
|
+
- `3` local validation errors
|
|
325
|
+
- `4` Forge service errors (`ok: false` payload)
|
|
326
|
+
- `5` Forge transport/connectivity errors
|
|
327
|
+
|
|
328
|
+
## CI usage examples
|
|
329
|
+
|
|
330
|
+
Doctor preflight with JSON parsing:
|
|
331
|
+
```bash
|
|
332
|
+
set -euo pipefail
|
|
333
|
+
pnpm --filter @automatify-au/cli build
|
|
334
|
+
export TESTOPS_FORGE_ENDPOINT="${TESTOPS_FORGE_ENDPOINT:?missing}"
|
|
335
|
+
export JIRA_BASE_URL="${JIRA_BASE_URL:?missing}"
|
|
336
|
+
export JIRA_PROJECT_KEY="${JIRA_PROJECT_KEY:?missing}"
|
|
337
|
+
|
|
338
|
+
doctor_json="$(automatify testops doctor check --json)"
|
|
339
|
+
echo "$doctor_json"
|
|
340
|
+
node -e 'const d=JSON.parse(process.argv[1]); if(!d.status){process.exit(2)}' "$doctor_json"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Feature ingest from file:
|
|
344
|
+
```bash
|
|
345
|
+
pnpm --filter @automatify-au/cli build
|
|
346
|
+
automatify testops ingest feature \
|
|
347
|
+
--file ./artifacts/checkout.feature \
|
|
348
|
+
--project-key DEV
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Run upload from file with CI-friendly branching:
|
|
352
|
+
```bash
|
|
353
|
+
set +e
|
|
354
|
+
pnpm --filter @automatify-au/cli build
|
|
355
|
+
automatify testops run upload \
|
|
356
|
+
--file ./artifacts/run.json \
|
|
357
|
+
--project-key DEV \
|
|
358
|
+
--json
|
|
359
|
+
code=$?
|
|
360
|
+
set -e
|
|
361
|
+
|
|
362
|
+
case "$code" in
|
|
363
|
+
0) echo "run upload succeeded" ;;
|
|
364
|
+
2|3) echo "usage/validation issue, fail fast" ; exit "$code" ;;
|
|
365
|
+
4) echo "Forge service rejected payload" ; exit "$code" ;;
|
|
366
|
+
5) echo "Forge connectivity issue, consider retry" ; exit "$code" ;;
|
|
367
|
+
*) echo "unexpected failure" ; exit "$code" ;;
|
|
368
|
+
esac
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Adoption checklist (MVP)
|
|
372
|
+
1. Build CLI:
|
|
373
|
+
- `pnpm --filter @automatify-au/cli build && pnpm --filter @automatify-au/cli bundle`
|
|
374
|
+
2. Validate config:
|
|
375
|
+
- `automatify testops config validate`
|
|
376
|
+
3. Run doctor preflight:
|
|
377
|
+
- `automatify testops doctor check --json`
|
|
378
|
+
4. Ingest one sample feature:
|
|
379
|
+
- `automatify testops ingest feature --file ./artifacts/checkout.feature --project-key DEV`
|
|
380
|
+
5. Upload one sample run:
|
|
381
|
+
- `automatify testops run upload --file ./artifacts/run.json --project-key DEV --json`
|
|
382
|
+
6. (Optional) Verify sync:
|
|
383
|
+
- `TESTOPS_ENABLE_SYNC=1 automatify testops sync status`
|
|
384
|
+
|
|
385
|
+
## Runbook integration
|
|
386
|
+
- Pilot onboarding/operator triage snippets:
|
|
387
|
+
- `PILOT_ONBOARDING.md`
|
|
388
|
+
- Release and rollback flow:
|
|
389
|
+
- `RELEASE_RUNBOOK.md`
|