|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +The Rootly CLI is a command-line interface for interacting with rootly.com, primarily focused on sending "pulses" (deployment notifications and tracking events) from the command line, CI environments, or shell scripts. It's written in Go and uses the Cobra framework for command structure. |
| 8 | + |
| 9 | +## Common Commands |
| 10 | + |
| 11 | +### Development |
| 12 | +```bash |
| 13 | +# Install dependencies |
| 14 | +go get all |
| 15 | + |
| 16 | +# Build the binary (outputs to ./bin/rootly) |
| 17 | +make build |
| 18 | + |
| 19 | +# Run tests |
| 20 | +make test |
| 21 | + |
| 22 | +# Run linters (requires golangci-lint, hadolint, goreleaser) |
| 23 | +make lint |
| 24 | + |
| 25 | +# Clean build artifacts |
| 26 | +make clean |
| 27 | +``` |
| 28 | + |
| 29 | +### Testing Individual Components |
| 30 | +```bash |
| 31 | +# Run tests for a specific package |
| 32 | +go test -count=1 -v ./pkg/api/... |
| 33 | +go test -count=1 -v ./pkg/commands/... |
| 34 | +go test -count=1 -v ./pkg/inputs/... |
| 35 | +``` |
| 36 | + |
| 37 | +### Docker |
| 38 | +```bash |
| 39 | +# Build Docker image |
| 40 | +make docker-build |
| 41 | + |
| 42 | +# Push Docker image |
| 43 | +make docker-push |
| 44 | +``` |
| 45 | + |
| 46 | +### Release |
| 47 | +```bash |
| 48 | +# Create and push a new version tag |
| 49 | +make release VERSION="v1.0.0" |
| 50 | +``` |
| 51 | + |
| 52 | +## Architecture |
| 53 | + |
| 54 | +### Package Structure |
| 55 | + |
| 56 | +- **cmd/rootly/** - Main entry point; initializes logging and executes root command |
| 57 | +- **pkg/commands/** - Cobra command definitions (`pulse`, `pulse-run`, root command) |
| 58 | +- **pkg/api/** - HTTP client logic for Rootly API, request building, and response parsing |
| 59 | +- **pkg/inputs/** - Input handling across three layers: |
| 60 | + - `flags/` - Cobra flag definitions |
| 61 | + - `env/` - Environment variable parsing |
| 62 | + - `parse/` - String parsing utilities (arrays, key-value pairs) |
| 63 | + - Main package unifies flag + env variable retrieval |
| 64 | +- **pkg/models/** - Data structures for pulses and API responses |
| 65 | +- **pkg/log/** - Custom logging with context-aware error handling |
| 66 | + |
| 67 | +### Input Processing Flow |
| 68 | + |
| 69 | +The CLI uses a unified input system that prioritizes flags over environment variables: |
| 70 | + |
| 71 | +1. **Flag Layer** (`pkg/inputs/flags/`): Defines all Cobra flags |
| 72 | +2. **Environment Layer** (`pkg/inputs/env/`): Provides fallback via `ROOTLY_*` env vars |
| 73 | +3. **Input Getter** (`pkg/inputs/get.go`): Unified retrieval that checks flags first, then env vars |
| 74 | +4. **Parsing Layer** (`pkg/inputs/parse/`): Converts strings to structured data (arrays, maps) |
| 75 | + |
| 76 | +Key pattern: `inputs.GetString(names.ApiKeyName, cmd, required)` checks flag `--api-key`, then falls back to `ROOTLY_API_KEY`. |
| 77 | + |
| 78 | +### Commands |
| 79 | + |
| 80 | +**`rootly pulse`** (`pkg/commands/pulse.go`) |
| 81 | +- Sends a pulse with provided metadata |
| 82 | +- Summary is required (taken from positional arguments or `ROOTLY_SUMMARY`) |
| 83 | +- Collects metadata: labels (key=value pairs), services, environments, source, refs |
| 84 | +- Timestamps: `StartedAt` captured at command start, `EndedAt` when pulse is sent |
| 85 | + |
| 86 | +**`rootly pulse-run`** (`pkg/commands/pulse_run.go`) |
| 87 | +- Wraps a shell command execution |
| 88 | +- Automatically adds `exit_status` label with the command's exit code |
| 89 | +- If no summary provided, uses the command itself as summary |
| 90 | +- Flow: Parse inputs → Run command → Add exit code to labels → Send pulse |
| 91 | + |
| 92 | +### API Integration |
| 93 | + |
| 94 | +- Uses generated client from `rootlyhq/rootly-go` package |
| 95 | +- Manual request construction in `pkg/api/request.go` using `oapi-codegen` |
| 96 | +- Authentication via Bearer token (API key) |
| 97 | +- Validates service/environment IDs in response and reports missing ones |
| 98 | + |
| 99 | +### Key-Value Parsing |
| 100 | + |
| 101 | +Labels and refs use format `key=value, key2=value2` (comma-separated, no spaces around `=`). |
| 102 | + |
| 103 | +Parser (`pkg/inputs/convert.go`): |
| 104 | +- Splits on commas, then on `=` |
| 105 | +- Converts keys to lowercase and replaces spaces with underscores |
| 106 | +- Validates format (exactly one `=` per item, non-empty values) |
| 107 | + |
| 108 | +Critical fix context: Recent fix addressed panic in key-value parsing for refs and labels when format was invalid (see commit 2c38ee2). |
| 109 | + |
| 110 | +## Version Management |
| 111 | + |
| 112 | +Current version is hardcoded in `pkg/commands/root.go:34`. Update this file when releasing new versions. |
| 113 | + |
| 114 | +The CLI checks for updates on `--version` flag using the `gleich/release` package. |
| 115 | + |
| 116 | +## CI/CD |
| 117 | + |
| 118 | +GitHub Actions workflows (`.github/workflows/`): |
| 119 | +- `build.yml` - Build verification |
| 120 | +- `lint.yml` - Linting checks |
| 121 | +- `test.yml` - Test execution |
| 122 | +- `release.yml` - Automated releases via GoReleaser |
| 123 | + |
| 124 | +All flags support environment variables: replace hyphens with underscores, uppercase, and prefix with `ROOTLY_`. |
| 125 | + |
| 126 | +## Testing Notes |
| 127 | + |
| 128 | +- Tests use `testify` assertions |
| 129 | +- Example test locations: |
| 130 | + - API conversion tests: `pkg/api/convert_test.go` |
| 131 | + - Request tests: `pkg/api/request_test.go` |
| 132 | + - Parsing tests: `pkg/inputs/parse/array_test.go` |
| 133 | + - Logging tests: `pkg/log/format_test.go` |
0 commit comments