@teak-dev/grove-cli
v1.5.1
Published
CLI for uploading Artillery + Playwright load test reports to a Grove instance
Readme
grove-cli
CLI for uploading Artillery load test reports to a Grove instance.
Requirements
Node.js 18+. The published package has no runtime npm dependencies (only Node built-ins).
Development
From scripts/grove-cli: npm install, npm run build (emits dist/), npm test. The grove-cli bin points at dist/cli.js.
Installation
npm install -g @teak-dev/grove-cliAuthentication
All uploads require a Grove API key. Generate one at /admin/api-keys in the Grove UI (admin role required). Keys are prefixed grv_ and are shown only once on creation.
Configuration
Interactive setup (local use)
grove-cli setupPrompts for your Grove URL and API key, then writes them to ~/.grove/config.json. Subsequent invocations pick this up automatically.
Environment variables (CI/CD)
Set these as pipeline secrets — never commit them:
| Variable | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| GROVE_URL | Base URL of your Grove instance |
| GROVE_API_KEY | Grove API key with grv_ prefix |
| RUN_NAME | Run display name or batch prefix (used when --name is omitted) |
| ADDITIONAL_TAGS | Comma-separated plain-string tags for Grove (max 20, max 50 chars each); same variable used in Buddy perf pipelines |
| GROVE_NOTES | Notes on the run when --notes is omitted |
| GROVE_RUN_CONFIG | JSON object merged into run_config (values coerced to strings) |
| BUDDY_API_TOKEN | Buddy personal access token (for auto run naming) |
Environment variables take precedence over the config file. CLI flags take precedence over both (--name / --tags / --notes override RUN_NAME / ADDITIONAL_TAGS / GROVE_NOTES).
Buddy CI/CD
Run name: precedence is --name → --meta name → RUN_NAME → Buddy API name (below) → filename stem.
When BUDDY_API_TOKEN is set and neither --name, --meta name, nor RUN_NAME is set, the CLI constructs the run name from the latest execution of the target pipeline:
Merge pull request #211 from org/feature/my-feature (main@540d161)Example pipeline step (single file):
grove-cli --file ./artillery-results/report.json --suite-id "$SUITE_UUID"playwright-tests Buddy perf pipelines use the env-driven subcommand (report discovery + suite map built in):
export GROVE_SSM_PREFIX_BASE=/protecht-platform
npx grove-cli upload-ci \
--ssm-params feature_flags,cache_enabled \
--ssm-region us-west-2Requires GROVE_UPLOAD=true, GROVE_URL, GROVE_API_KEY, and SCENARIO_NAME (or SCENARIO_PATH for dev). Suite UUID comes from GROVE_SUITE_ID or performance-scenarios/grove-suite-map.json.
With GROVE_SSM_PREFIX_BASE=/protecht-platform, TARGET selects the SSM folder: https://api.performance… → /protecht-platform/performance, https://api-2.performance… → /protecht-platform/performance-2.
With Buddy perf metadata (also picked up automatically when set in the environment):
export RUN_NAME="Nightly perf suite"
export ADDITIONAL_TAGS="perf,nightly,suite-next"
grove-cli --dir "$REPORT_DIR/$RUN_ID" --suite-id "$SUITE_UUID"Set these as pipeline variables pointing at the Artillery test pipeline (for API-based naming):
| Variable | Description |
| -------------------------- | ------------------------------------------- |
| BUDDY_TARGET_PROJECT | Project name of the Artillery test pipeline |
| BUDDY_TARGET_PIPELINE_ID | Pipeline ID of the Artillery test pipeline |
BUDDY_WORKSPACE_DOMAIN is a Buddy built-in and requires no configuration. Branch and SHA are read from the API response, so no additional built-ins are needed even when running from a different project.
When uploading from CI, Buddy-built variables such as RUN_ID, SCENARIO_NAME, SCENARIO_LABEL, and BUDDY_* are merged into run_config as string fields (alongside config from --meta and GROVE_RUN_CONFIG).
Usage
grove-cli --file ./results/report.json --name "Load test - main@abc1234"--name defaults to Buddy context (if available) then filename stem:
grove-cli --file ./results/load-homepage.json
# run name → "load-homepage"Options
| Flag | Description |
| --------------- | -------------------------------------------------------------------- |
| -f, --file | Path to Artillery JSON report (required) |
| -n, --name | Run name (defaults to Buddy context or filename stem) |
| --suite-id | UUID of the performance test suite to associate this run with |
| --tags | Comma-separated tags, e.g. smoke,main |
| --notes | Free-text notes attached to the run |
| --ran-at | ISO 8601 datetime override (default: firstMetricAt from report) |
| --meta | Path to a JSON metadata file (see Metadata files) |
| --url | Grove base URL (overrides env and config) |
| --key | API key (overrides env and config) |
| --dry-run | Parse and validate the report without uploading |
| --json | Output the created run record as JSON on success |
| -v, --version | Print version and exit |
| -h, --help | Show help and exit |
Metadata files
A metadata file is a JSON file that sets suite, tags, config, and notes for a run:
{
"suite_id": "uuid-of-suite",
"tags": ["smoke", "main"],
"notes": "Post-deploy smoke run",
"config": {
"target": "https://app.example.com",
"vus": 50
}
}Pass via --meta ./path/to/meta.json. CLI flags take precedence over values in the file.
How metrics are extracted
The CLI parses the Artillery { aggregate, intermediate[] } structure and extracts:
- total_requests —
aggregate.counters['http.requests'] - success_rate —
(requests - vusers.failed) / requests × 100 - peak_request_rate — max
http.request_rateacross aggregate and all intermediate periods - response_time — mean, p50, p95, p99, min, max from
http.response_timesummaries/histograms - session_length — mean, p95, p99 from
vusers.session_length(omitted if not present)
The ran_at timestamp defaults to aggregate.firstMetricAt from the report. Pass --ran-at to override.
