@keinar/aac-cli 1.1.0 → 1.1.2
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 +53 -25
- package/dist/index.cjs +16 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,63 +1,91 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @keinar/aac-cli
|
|
2
2
|
|
|
3
|
-
> **Agnostic Automation Center CLI** —
|
|
3
|
+
> **Agnostic Automation Center CLI** — The deployment assistant that prepares and ships any test automation repository to the AAC platform, end-to-end.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/keinar/aac-cli/actions/workflows/release.yml)
|
|
6
|
-
[](https://www.npmjs.com/package/aac-cli)
|
|
6
|
+
[](https://www.npmjs.com/package/@keinar/aac-cli)
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx @keinar/aac-cli@latest init
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
> No installation required. This always runs the latest version.
|
|
7
15
|
|
|
8
16
|
## What It Does
|
|
9
17
|
|
|
10
|
-
|
|
18
|
+
`@keinar/aac-cli` handles the entire flow from raw test project to a deployed, platform-ready Docker image:
|
|
19
|
+
|
|
20
|
+
### 1. Generates Integration Files
|
|
11
21
|
|
|
12
22
|
| File | Purpose |
|
|
13
23
|
|---|---|
|
|
14
|
-
| `Dockerfile` | Builds your test suite image
|
|
15
|
-
| `entrypoint.sh` | Executed by the Worker
|
|
24
|
+
| `Dockerfile` | Builds your test suite image — no `ENTRYPOINT`/`CMD` (the AAC Worker injects it at runtime) |
|
|
25
|
+
| `entrypoint.sh` | Executed by the Worker: `/app/entrypoint.sh <folder>` |
|
|
16
26
|
| `.dockerignore` | Prevents secrets (`.env`, `.git`) and bloat (`node_modules`, `__pycache__`) from entering the image |
|
|
17
27
|
|
|
28
|
+
### 2. Detects Framework Versions
|
|
29
|
+
|
|
30
|
+
For **Playwright** projects, the CLI reads your `package.json`, extracts the `@playwright/test` version, and uses it to pin the exact Docker base image (`mcr.microsoft.com/playwright:v{version}-jammy`). No more mismatched browser binaries.
|
|
31
|
+
|
|
32
|
+
### 3. Automates Docker Deployment
|
|
33
|
+
|
|
34
|
+
After generating files, the CLI offers to handle the full deployment:
|
|
35
|
+
|
|
36
|
+
- **Docker Hub login** — interactive authentication via `docker login`
|
|
37
|
+
- **Project name detection** — reads from `package.json`, with manual override
|
|
38
|
+
- **Multi-platform build** — `linux/amd64` + `linux/arm64` via Docker Buildx, ensuring compatibility with any AAC Worker architecture
|
|
39
|
+
- **Push to registry** — ships the image directly to Docker Hub
|
|
40
|
+
|
|
18
41
|
### Supported Frameworks
|
|
19
42
|
|
|
20
|
-
- **Playwright** (TypeScript / Node.js)
|
|
43
|
+
- **Playwright** (TypeScript / Node.js) — auto-detects version
|
|
21
44
|
- **Pytest** (Python)
|
|
22
45
|
|
|
23
|
-
##
|
|
46
|
+
## Prerequisites
|
|
24
47
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
npx aac-cli init
|
|
28
|
-
```
|
|
48
|
+
- **Node.js 18+** — required to run the CLI
|
|
49
|
+
- **Docker Desktop** — must be running for the automated build & push features
|
|
29
50
|
|
|
30
51
|
## Installation (optional)
|
|
31
52
|
|
|
32
53
|
```bash
|
|
33
|
-
npm install -g aac-cli
|
|
54
|
+
npm install -g @keinar/aac-cli
|
|
34
55
|
```
|
|
35
56
|
|
|
36
57
|
## Usage
|
|
37
58
|
|
|
38
59
|
```bash
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
aac-cli init
|
|
60
|
+
# Run the full init + deploy flow
|
|
61
|
+
npx @keinar/aac-cli@latest init
|
|
42
62
|
|
|
43
63
|
# Check version
|
|
44
|
-
aac-cli --version
|
|
64
|
+
npx @keinar/aac-cli@latest --version
|
|
45
65
|
```
|
|
46
66
|
|
|
47
67
|
## How It Works
|
|
48
68
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
```
|
|
70
|
+
┌─────────────────────────────────────────────────┐
|
|
71
|
+
│ npx @keinar/aac-cli@latest init │
|
|
72
|
+
├─────────────────────────────────────────────────┤
|
|
73
|
+
│ 1. Select framework (Playwright / Pytest) │
|
|
74
|
+
│ 2. Auto-detect version from package.json │
|
|
75
|
+
│ 3. Generate Dockerfile + entrypoint.sh │
|
|
76
|
+
│ 4. (Optional) Docker login │
|
|
77
|
+
│ 5. (Optional) Buildx multi-platform build │
|
|
78
|
+
│ 6. (Optional) Push image to Docker Hub │
|
|
79
|
+
│ 7. Enter image name in the AAC Dashboard │
|
|
80
|
+
└─────────────────────────────────────────────────┘
|
|
81
|
+
```
|
|
54
82
|
|
|
55
83
|
## Development
|
|
56
84
|
|
|
57
85
|
```bash
|
|
58
86
|
npm install
|
|
59
87
|
npm run build
|
|
60
|
-
node dist/index.
|
|
88
|
+
node dist/index.cjs init
|
|
61
89
|
```
|
|
62
90
|
|
|
63
91
|
## Release
|
|
@@ -65,8 +93,8 @@ node dist/index.js init
|
|
|
65
93
|
Tag a new version to trigger the CI/CD pipeline:
|
|
66
94
|
|
|
67
95
|
```bash
|
|
68
|
-
git tag v1.
|
|
69
|
-
git push origin v1.
|
|
96
|
+
git tag v1.1.0
|
|
97
|
+
git push origin v1.1.0
|
|
70
98
|
```
|
|
71
99
|
|
|
72
100
|
The workflow will build with tsup, publish to npm, and create a GitHub release.
|
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
2
|
+
"use strict";var I=Object.create;var b=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var U=(t,n,o,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of Y(n))!j.call(t,i)&&i!==o&&b(t,i,{get:()=>n[i],enumerable:!(r=S(n,i))||r.enumerable});return t};var g=(t,n,o)=>(o=t!=null?I(_(t)):{},U(n||!t||!t.__esModule?b(o,"default",{value:t,enumerable:!0}):o,t));var N=require("commander"),s=g(require("@clack/prompts"),1),y=g(require("picocolors"),1);var f=require("fs/promises"),R=require("path"),c=g(require("@clack/prompts"),1),p=g(require("picocolors"),1);var w="1.50.0";function E(t){return`FROM mcr.microsoft.com/playwright:v${t}-jammy
|
|
3
3
|
|
|
4
4
|
WORKDIR /app
|
|
5
5
|
|
|
6
6
|
COPY package*.json ./
|
|
7
7
|
RUN npm ci
|
|
8
|
+
RUN npm install -g allure-commandline
|
|
8
9
|
|
|
9
10
|
COPY . .
|
|
10
11
|
|
|
11
12
|
RUN chmod +x /app/entrypoint.sh
|
|
12
|
-
`}var
|
|
13
|
+
`}var O=`#!/bin/sh
|
|
13
14
|
|
|
14
15
|
FOLDER=$1
|
|
15
16
|
|
|
@@ -18,13 +19,18 @@ if [ -f .env ]; then
|
|
|
18
19
|
rm .env
|
|
19
20
|
fi
|
|
20
21
|
|
|
22
|
+
echo "Running against BASE_URL: $BASE_URL"
|
|
23
|
+
|
|
21
24
|
if [ -z "$FOLDER" ] || [ "$FOLDER" = "all" ]; then
|
|
22
25
|
echo "Running ALL tests..."
|
|
23
|
-
|
|
26
|
+
npx playwright test
|
|
24
27
|
else
|
|
25
28
|
echo "Running tests in folder: $FOLDER"
|
|
26
|
-
|
|
29
|
+
npx playwright test "$FOLDER"
|
|
27
30
|
fi
|
|
31
|
+
|
|
32
|
+
echo "Generating Allure Report..."
|
|
33
|
+
npx allure generate allure-results --clean -o allure-report
|
|
28
34
|
`,P=`FROM python:3.11-slim
|
|
29
35
|
|
|
30
36
|
WORKDIR /app
|
|
@@ -56,9 +62,9 @@ fi
|
|
|
56
62
|
node_modules
|
|
57
63
|
__pycache__
|
|
58
64
|
.venv
|
|
59
|
-
`;async function
|
|
60
|
-
`)}async function
|
|
61
|
-
`),`${p.default.green("\u2705")} Next steps to connect your project to the AAC`)}var
|
|
62
|
-
Press Enter when you're ready to continue.`,l.default.yellow("Docker Hub Account Required")),await e.text({message:"Press Enter to continue...",defaultValue:"",placeholder:""}));let o=await e.text({message:"What is your Docker Hub username?",validate:u=>{if(!u.trim())return"Username is required."}});if(e.isCancel(o)){e.cancel("Deployment cancelled.");return}let r=await W(t),i;if(r){let u=await e.confirm({message:`Detected project name "${l.default.cyan(r)}". Use this for the image?`});if(e.isCancel(u)){e.cancel("Deployment cancelled.");return}if(u)i=r;else{let h=await e.text({message:"Enter the image name:",validate:
|
|
63
|
-
`),"You can build manually later");return}let k=e.spinner();try{k.start("Setting up Docker Buildx builder..."),(0,
|
|
64
|
-
${l.default.cyan(a)}`,l.default.green("\u2705 Deployment Complete"))}catch{e.log.error("Docker build failed. Check the output above for details.")}}var x=new
|
|
65
|
+
`;async function G(t){try{let n=await(0,f.readFile)((0,R.join)(t,"package.json"),"utf-8"),o=JSON.parse(n),r=o.devDependencies?.["@playwright/test"]??o.dependencies?.["@playwright/test"];return r?r.replace(/^[^\d]*/,"")||w:w}catch{return w}}async function B(t,n){let o=t==="playwright",r;if(o){let i=await G(n);c.log.info(`Detected Playwright version: ${p.default.cyan("v"+i)}`),r=E(i)}else r=P;return[{name:".dockerignore",content:$,mode:420},{name:"entrypoint.sh",content:o?O:C,mode:493},{name:"Dockerfile",content:r,mode:420}]}async function H(t){try{return await(0,f.stat)(t),!0}catch{return!1}}function q(t){return t.replace(/\r\n/g,`
|
|
66
|
+
`)}async function A(t,n){let o=await B(t,n),r=new Set;for(let a of o){let d=(0,R.join)(n,a.name);if(await H(d)){let m=await c.confirm({message:`File ${p.default.yellow(a.name)} already exists. Overwrite?`});c.isCancel(m)&&(c.cancel("Operation cancelled."),process.exit(0)),m||r.add(a.name)}}if(r.size===o.length){c.log.warn("All files were skipped. No changes were made.");return}let i=[];for(let a of o){if(r.has(a.name))continue;let d=(0,R.join)(n,a.name),m=q(a.content);await(0,f.writeFile)(d,m,{mode:a.mode}),i.push(a.name)}for(let a of i)c.log.success(`Created ${p.default.green(a)}`);c.note([`${p.default.bold("1.")} docker build -t your-username/my-automation-tests:latest .`,`${p.default.bold("2.")} docker push your-username/my-automation-tests:latest`,`${p.default.bold("3.")} Enter this image name in the AAC Dashboard.`].join(`
|
|
67
|
+
`),`${p.default.green("\u2705")} Next steps to connect your project to the AAC`)}var D=require("child_process"),F=require("fs/promises"),v=require("path"),e=g(require("@clack/prompts"),1),l=g(require("picocolors"),1);async function W(t){try{let n=await(0,F.readFile)((0,v.join)(t,"package.json"),"utf-8"),o=JSON.parse(n);return o.name?o.name.replace(/^@[^/]+\//,""):null}catch{return null}}async function L(t){let n=await e.confirm({message:"Do you have a Docker Hub account?"});if(e.isCancel(n)){e.cancel("Deployment cancelled.");return}n||(e.note(`Create a free account at ${l.default.cyan("https://hub.docker.com")}
|
|
68
|
+
Press Enter when you're ready to continue.`,l.default.yellow("Docker Hub Account Required")),await e.text({message:"Press Enter to continue...",defaultValue:"",placeholder:""}));let o=await e.text({message:"What is your Docker Hub username?",validate:u=>{if(!u.trim())return"Username is required."}});if(e.isCancel(o)){e.cancel("Deployment cancelled.");return}let r=await W(t),i;if(r){let u=await e.confirm({message:`Detected project name "${l.default.cyan(r)}". Use this for the image?`});if(e.isCancel(u)){e.cancel("Deployment cancelled.");return}if(u)i=r;else{let h=await e.text({message:"Enter the image name:",validate:T=>{if(!T.trim())return"Image name is required."}});if(e.isCancel(h)){e.cancel("Deployment cancelled.");return}i=h.trim()}}else{let u=await e.text({message:"Enter the image name:",validate:h=>{if(!h.trim())return"Image name is required."}});if(e.isCancel(u)){e.cancel("Deployment cancelled.");return}i=u.trim()}let a=`${o.trim()}/${i}:latest`,d=await e.confirm({message:"I need to log you into Docker. Send a login request?"});if(e.isCancel(d)){e.cancel("Deployment cancelled.");return}if(d){e.log.step("Opening Docker login...");try{(0,D.execSync)("docker login",{stdio:"inherit",cwd:t}),e.log.success("Docker login successful.")}catch{e.log.error("Docker login failed. Please try again manually.");return}}let m=await e.confirm({message:`Build multi-platform image ${l.default.cyan(a)} and push to Docker Hub?`});if(e.isCancel(m)||!m){e.log.warn("Build skipped."),e.note([`${l.default.bold("1.")} docker buildx create --name aac-builder --use`,`${l.default.bold("2.")} docker buildx build --platform linux/amd64,linux/arm64 -t ${a} --push .`].join(`
|
|
69
|
+
`),"You can build manually later");return}let k=e.spinner();try{k.start("Setting up Docker Buildx builder..."),(0,D.execSync)("docker buildx create --name aac-builder --use",{stdio:"pipe",cwd:t}),k.stop("Buildx builder ready.")}catch{k.stop("Using existing Buildx builder.")}e.log.step(`Building & pushing ${l.default.cyan(a)}...`);try{(0,D.execSync)(`docker buildx build --platform linux/amd64,linux/arm64 -t ${a} --push .`,{stdio:"inherit",cwd:t}),e.log.success(`Image ${l.default.green(a)} pushed successfully!`),e.note(`Go to the ${l.default.bold("AAC Dashboard")} and enter:
|
|
70
|
+
${l.default.cyan(a)}`,l.default.green("\u2705 Deployment Complete"))}catch{e.log.error("Docker build failed. Check the output above for details.")}}var x=new N.Command;x.name("aac-cli").description("Agnostic Automation Center CLI \u2014 Prepare any test automation repo for the AAC platform").version("1.1.0");x.command("init").description("Generate AAC integration files and optionally build & push your Docker image").action(async()=>{s.intro(y.default.bgCyan(y.default.black(" AAC CLI ")));let t=await s.select({message:"Select your automation project framework:",options:[{value:"playwright",label:"Playwright (TypeScript/Node.js)"},{value:"pytest",label:"Pytest (Python)"}]});s.isCancel(t)&&(s.cancel("Operation cancelled."),process.exit(0));let n=s.spinner();n.start("Generating AAC integration files..."),await new Promise(i=>setTimeout(i,300)),n.stop("Files ready.");let o=process.cwd();await A(t,o);let r=await s.confirm({message:"Do you want to build and push the image to Docker Hub right now?"});s.isCancel(r)&&(s.cancel("Operation cancelled."),process.exit(0)),r&&await L(o),s.outro(y.default.green("Done!")+" "+y.default.dim("Run `aac-cli init` again anytime."))});x.parse();
|