From 96ebe6ec8e899eea1827130343dbfa32bcb614e3 Mon Sep 17 00:00:00 2001 From: Jonas Alves Date: Wed, 28 Jan 2026 14:57:11 +0000 Subject: [PATCH 01/73] feat: implement ABSmartly CLI with markdown-based experiment management Unified Go CLI tool for ABSmartly platform management including: Core Features: - Experiment management (CRUD, start/stop, results, archive) - Feature flags, goals, segments, applications, environments, unit types - Resource management (teams, users, metrics, tags, roles, webhooks, API keys, permissions) - Expctld operations for internal experiment control (timestamps, tasks, notes, alerts) Markdown Templates: - Create experiments from markdown template files with --from-file flag - Update experiments via templates (partial updates with version control) - Generate templates with custom fields from API endpoint - Platform config integration for analysis defaults (alpha, power, intervals) Technical Stack: - Cobra + Viper for CLI framework - go-resty for HTTP client - Keyring for secure credential storage - Comprehensive test coverage (127 tests passing) Version Control: - Updates use timestamp-based versioning to prevent concurrent modifications - Fetches current experiment state and merges template changes - Returns "data outdated" error on version conflicts --- .gitignore | 38 + IMPLEMENTATION_PLAN.md | 1608 +++++++++++++++++++ Makefile | 55 + cmd/api/api.go | 23 + cmd/apikeys/apikeys.go | 213 +++ cmd/apps/apps.go | 86 + cmd/auth/auth.go | 252 +++ cmd/completion/completion.go | 58 + cmd/config/config.go | 364 +++++ cmd/doctor/doctor.go | 17 + cmd/envs/envs.go | 87 + cmd/experiments/experiments.go | 805 ++++++++++ cmd/flags/flags.go | 118 ++ cmd/generate/generate.go | 34 + cmd/goals/goals.go | 226 +++ cmd/goaltags/goaltags.go | 198 +++ cmd/metriccategories/metriccategories.go | 213 +++ cmd/metrics/metrics.go | 217 +++ cmd/metrictags/metrictags.go | 198 +++ cmd/open/open.go | 17 + cmd/permissions/permissions.go | 103 ++ cmd/roles/roles.go | 207 +++ cmd/root.go | 137 ++ cmd/segments/segments.go | 222 +++ cmd/setup/setup.go | 22 + cmd/tags/tags.go | 203 +++ cmd/teams/teams.go | 229 +++ cmd/units/units.go | 86 + cmd/users/users.go | 238 +++ cmd/version/version.go | 22 + cmd/webhooks/webhooks.go | 238 +++ go.mod | 47 + go.sum | 149 ++ internal/api/client.go | 1830 ++++++++++++++++++++++ internal/api/client_test.go | 1690 ++++++++++++++++++++ internal/api/expctld.go | 204 +++ internal/api/expctld_test.go | 190 +++ internal/api/types.go | 457 ++++++ internal/cmdutil/client.go | 100 ++ internal/config/config.go | 312 ++++ internal/config/config_test.go | 254 +++ internal/config/keyring.go | 37 + internal/output/output.go | 251 +++ internal/template/generator.go | 196 +++ internal/template/parser.go | 932 +++++++++++ internal/template/parser_test.go | 169 ++ main.go | 15 + pkg/version/version.go | 7 + pkg/version/version_test.go | 13 + 49 files changed, 13387 insertions(+) create mode 100644 .gitignore create mode 100644 IMPLEMENTATION_PLAN.md create mode 100644 Makefile create mode 100644 cmd/api/api.go create mode 100644 cmd/apikeys/apikeys.go create mode 100644 cmd/apps/apps.go create mode 100644 cmd/auth/auth.go create mode 100644 cmd/completion/completion.go create mode 100644 cmd/config/config.go create mode 100644 cmd/doctor/doctor.go create mode 100644 cmd/envs/envs.go create mode 100644 cmd/experiments/experiments.go create mode 100644 cmd/flags/flags.go create mode 100644 cmd/generate/generate.go create mode 100644 cmd/goals/goals.go create mode 100644 cmd/goaltags/goaltags.go create mode 100644 cmd/metriccategories/metriccategories.go create mode 100644 cmd/metrics/metrics.go create mode 100644 cmd/metrictags/metrictags.go create mode 100644 cmd/open/open.go create mode 100644 cmd/permissions/permissions.go create mode 100644 cmd/roles/roles.go create mode 100644 cmd/root.go create mode 100644 cmd/segments/segments.go create mode 100644 cmd/setup/setup.go create mode 100644 cmd/tags/tags.go create mode 100644 cmd/teams/teams.go create mode 100644 cmd/units/units.go create mode 100644 cmd/users/users.go create mode 100644 cmd/version/version.go create mode 100644 cmd/webhooks/webhooks.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/api/client.go create mode 100644 internal/api/client_test.go create mode 100644 internal/api/expctld.go create mode 100644 internal/api/expctld_test.go create mode 100644 internal/api/types.go create mode 100644 internal/cmdutil/client.go create mode 100644 internal/config/config.go create mode 100644 internal/config/config_test.go create mode 100644 internal/config/keyring.go create mode 100644 internal/output/output.go create mode 100644 internal/template/generator.go create mode 100644 internal/template/parser.go create mode 100644 internal/template/parser_test.go create mode 100644 main.go create mode 100644 pkg/version/version.go create mode 100644 pkg/version/version_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bddb83 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Binaries +absmartly +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Build output +dist/ +bin/ + +# Test binary +*.test + +# Coverage +coverage.out +coverage.html + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Go workspace +go.work + +# Debug +__debug_bin + +# Temporary +*.tmp +*.log diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md new file mode 100644 index 0000000..8eda3b2 --- /dev/null +++ b/IMPLEMENTATION_PLAN.md @@ -0,0 +1,1608 @@ +# ABSmartly CLI Implementation Plan + +**Project:** absmartly-cli +**Date:** January 24, 2026 +**Purpose:** Unified CLI combining experiment management, expctl operations, and markdown-based experiment creation + +--- + +## Table of Contents + +1. [Executive Summary](#executive-summary) +2. [Existing Tools Analysis](#existing-tools-analysis) +3. [Competitor Analysis](#competitor-analysis) +4. [Feature Specification](#feature-specification) +5. [Technical Architecture](#technical-architecture) +6. [Command Reference](#command-reference) +7. [Implementation Details](#implementation-details) +8. [Distribution Strategy](#distribution-strategy) +9. [Testing Strategy](#testing-strategy) + +--- + +## 1. Executive Summary + +### Project Goal + +Build a unified CLI tool for ABSmartly that consolidates: +1. **Experiment Management** - CRUD operations for experiments, flags, goals, segments +2. **expctl Operations** - Internal experiment control (update timestamps, delete tasks/notes/alerts) +3. **Markdown-based Experiment Creation** - Create experiments from `.md` template files + +### Technology Choice: **Go** + +**Rationale:** +- Single binary distribution (no runtime dependencies) +- Excellent cross-platform support +- Fast compilation and execution +- Used by LaunchDarkly (most comprehensive competitor CLI) +- Strong ecosystem for CLI building (Cobra, Viper) +- Easy to create goreleaser pipelines + +**Alternative Considered:** TypeScript (used by GrowthBook) +- Requires Node.js runtime +- More complex distribution +- Would be familiar to existing SDK users + +### What This CLI Replaces + +| Existing Tool | Functionality | New CLI Command | +|---------------|---------------|-----------------| +| `expctl` | Update experiment timestamps, delete tasks/notes/alerts | `absmartly experiments update-timestamps`, `absmartly experiments tasks delete-all` | +| `create_experiment` | Create experiments from markdown templates | `absmartly experiments create --from-file` | +| *(new)* | Standard CRUD operations | `absmartly experiments list/get/create/...` | + +### Success Metrics +- 100+ GitHub stars within 6 months +- Homebrew, npm, Docker distribution +- Shell completion for bash, zsh, fish, PowerShell +- Full API coverage for core ABSmartly features + +--- + +## 2. Existing Tools Analysis + +### 2.1 expctl + +**Location:** `~/git_tree/expctl` +**Language:** Python (Click framework) +**Purpose:** Internal experiment control operations + +**Authentication:** +- Token-only via `Authorization: Bearer {token}` +- Config file: `~/.expctl_rc` +- Connects to `expctld` service (internal controller) + +**Key Commands:** +```bash +expctl experiment --id get +expctl experiment --id update --set fieldName=value --null fieldName +expctl experiment --id task delete-all +expctl experiment --id note update --note-id --set createdAt= +expctl experiment --id note delete-all +expctl experiment --id recommended-action delete-all +expctl experiment --id alert delete-all +expctl experiment --id gst-analysis delete-all +``` + +**Config Format:** +```yaml +# ~/.expctl_rc +expctld: + endpoint: https://dev-1-ctl.absmartly.io/v1 + token: mysecrettoken + +# Or with profiles: +profile: production +profiles: + production: + expctld: + endpoint: https://ctl.absmartly.io/v1 + token: prodtoken + staging: + expctld: + endpoint: https://staging-ctl.absmartly.io/v1 + token: stagingtoken +``` + +### 2.2 create_experiment + +**Location:** `~/git_tree/create_experiment` +**Language:** Python (Click framework) +**Purpose:** Create complete experiments from markdown templates + +**Authentication:** +- Token-only via `Authorization: Api-Key {token}` +- Config file: `~/.create_experiment_rc` +- Connects to main ABSmartly API + +**Key Features:** +- Parse markdown template files with experiment configuration +- Support for variants with screenshots (uploaded via API) +- Custom field values (hypothesis, purpose, prediction, etc.) +- Metric configuration (primary, secondary, guardrail) +- *(Excluded from new CLI: Timeline/synthetic data generation)* + +**Config Format:** +```yaml +# ~/.create_experiment_rc +endpoint: https://api.absmartly.io/v1 +token: myapikey + +# Or with profiles: +profile: production +profiles: + production: + endpoint: https://api.absmartly.io/v1 + token: prodtoken +``` + +### 2.3 Authentication Summary + +Both existing tools use **hardcoded API tokens only**. The new CLI should support: + +1. **Token-based auth** (for CI/CD and automation) + - `Api-Key` header for main ABSmartly API + - `Bearer` token for expctld service + +2. **Optional: Browser-based OAuth** (for interactive use) + - Would require backend OAuth flow implementation + - Lower priority - tokens work fine for most use cases + +--- + +## 3. Competitor Analysis + +### 3.1 LaunchDarkly CLI (ldcli) + +**Repository:** https://github.com/launchdarkly/ldcli +**Stars:** 21 +**Language:** Go +**Distribution:** Homebrew, npm, Docker, GitHub Releases + +**Key Features:** +| Feature | Description | +|---------|-------------| +| `setup` | Guided onboarding - create flag, connect SDK, toggle | +| `login` | Browser-based authentication | +| `config` | Configuration management (set, unset, list) | +| `flags` | Flag CRUD operations | +| `members` | Team member management | +| Resource commands | Auto-generated from OpenAPI spec | + +**Code Structure:** +``` +ldcli/ +├── cmd/ +│ ├── analytics/ +│ ├── config/ +│ ├── dev_server/ +│ ├── flags/ +│ ├── login/ +│ ├── members/ +│ ├── resources/ +│ ├── sourcemaps/ +│ └── validators/ +├── internal/ +│ ├── analytics/ +│ ├── client/ +│ ├── config/ +│ ├── dev_server/ +│ ├── environments/ +│ ├── errors/ +│ ├── flags/ +│ ├── login/ +│ ├── members/ +│ ├── output/ +│ ├── projects/ +│ ├── quickstart/ +│ ├── resources/ +│ └── sdks/ +├── ld-openapi.json +├── main.go +├── go.mod +└── Makefile +``` + +**Configuration Options:** +- `access-token` - API authentication +- `analytics-opt-out` - Telemetry control +- `base-uri` - Custom API endpoint +- `environment` - Default environment +- `flag` - Default flag key +- `output` - JSON or plain text +- `project` - Default project + +**Reference Links:** +- Documentation: https://launchdarkly.com/docs/home/getting-started/ldcli +- GitHub: https://github.com/launchdarkly/ldcli +- npm: https://www.npmjs.com/package/@launchdarkly/ldcli +- Docker: https://hub.docker.com/r/launchdarkly/ldcli + +--- + +### 3.2 GrowthBook CLI + +**Repository:** https://github.com/growthbook/growthbook-cli +**Stars:** 6 +**Language:** TypeScript (oclif framework) +**Distribution:** npm + +**Key Features:** +| Command | Subcommands | Description | +|---------|-------------|-------------| +| `auth` | `login`, `logout` | Authentication management | +| `features` | `list`, `get`, `toggle`, `generate-types` | Feature flag operations | +| `experiments` | `list`, `get`, `results` | Experiment management | +| `metrics` | `list`, `get`, `create` | Metrics CRUD | +| `projects` | `list`, `get` | Project management | +| `datasources` | `list`, `get` | Data source operations | +| `dimensions` | `list`, `get` | Dimension management | +| `segments` | `list`, `get` | Segment operations | +| `savedgroups` | `list`, `get`, `create`, `update`, `delete` | Saved groups CRUD | +| `sdkconnections` | `list`, `get` | SDK connection management | +| `vcs` | `list`, `get` | Visual changeset operations | + +**Unique Features:** +- `features generate-types` - TypeScript type generation +- Profile support for multiple GrowthBook instances +- `experiments results` - View experiment results from CLI +- Pagination support (`--limit`, `--offset`) + +**Reference Links:** +- Documentation: https://docs.growthbook.io/tools/cli +- GitHub: https://github.com/growthbook/growthbook-cli +- npm: https://www.npmjs.com/package/growthbook-cli + +--- + +### 3.3 Feature Comparison Matrix + +| Feature | LaunchDarkly | GrowthBook | ABSmartly (Planned) | +|---------|--------------|------------|---------------------| +| **Authentication** | +| Login via browser | ✅ | ❌ | ❌ (token only) | +| API key config | ✅ | ✅ | ✅ | +| Multiple profiles | ❌ | ✅ | ✅ | +| **Flags/Features** | +| List flags | ✅ | ✅ | ✅ | +| Get flag details | ✅ | ✅ | ✅ | +| Create flag | ✅ | ❌ | ✅ | +| Update flag | ✅ | ❌ | ✅ | +| Delete flag | ✅ | ❌ | ✅ | +| Toggle flag | ✅ | ✅ | ✅ | +| **Experiments** | +| List experiments | ✅ | ✅ | ✅ | +| Get experiment | ✅ | ✅ | ✅ | +| Create experiment | ✅ | ❌ | ✅ | +| **Create from markdown** | ❌ | ❌ | ✅ | +| Start/Stop experiment | ❌ | ❌ | ✅ | +| View results | ❌ | ✅ | ✅ | +| **Internal Operations (from expctl)** | +| Update timestamps | ❌ | ❌ | ✅ | +| Delete tasks/notes | ❌ | ❌ | ✅ | +| Clear analyses | ❌ | ❌ | ✅ | +| **Developer Experience** | +| Guided setup | ✅ | ❌ | ✅ | +| Type generation | ❌ | ✅ | ✅ | +| Shell completion | ✅ | ✅ | ✅ | +| **Output** | +| JSON output | ✅ | ✅ | ✅ | +| Table output | ✅ | ✅ | ✅ | +| YAML output | ❌ | ❌ | ✅ | +| **Distribution** | +| Homebrew | ✅ | ❌ | ✅ | +| npm | ✅ | ✅ | ✅ | +| Docker | ✅ | ❌ | ✅ | +| GitHub Releases | ✅ | ✅ | ✅ | + +--- + +## 4. Feature Specification + +### 4.1 Core Commands + +#### Authentication (`auth`) +```bash +absmartly auth login --token # Store API token interactively +absmartly auth logout # Clear credentials +absmartly auth status # Show current auth status +``` + +#### Configuration (`config`) +```bash +absmartly config set # Set config value +absmartly config get # Get config value +absmartly config unset # Remove config value +absmartly config list # List all config +absmartly config init # Interactive config setup +absmartly config profiles list # List profiles +absmartly config profiles use # Switch profile +``` + +#### Experiments (`experiments`) + +**Standard CRUD (via main API):** +```bash +absmartly experiments list [flags] +absmartly experiments get +absmartly experiments create [flags] +absmartly experiments create --from-file # From markdown +absmartly experiments update [flags] +absmartly experiments delete +absmartly experiments start +absmartly experiments stop +absmartly experiments results [flags] +absmartly experiments archive +``` + +**Internal Operations (via expctld - from expctl):** +```bash +absmartly experiments update-timestamps --set startAt=