Skip to content

Commit 7347781

Browse files
n-rodriguezclaude
andcommitted
docs: add CLAUDE.md and expand README with usage and development
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1168987 commit 7347781

2 files changed

Lines changed: 152 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What this is
6+
7+
`squarectl` is a Crystal CLI that wraps `docker compose`, `docker swarm` (configs/secrets),
8+
and `kubectl`/`kompose`. It reads a single YAML config (`squarectl.yml` by default) describing
9+
one or more **environments** (development, staging, production, ...) and renders the right
10+
env vars, compose file lists, networks, SSL certs, and deploy artifacts before shelling out to
11+
the underlying tool. The user picks a **target** (`compose`, `swarm`, `kubernetes`) and an
12+
**environment**; squarectl assembles the command and `exec`s it.
13+
14+
## Toolchain & commands
15+
16+
The dev environment is managed by [mise](https://mise.jdx.dev) (`mise.toml`), which pins
17+
Crystal and defines all tasks. Run tasks with `mise <task>`:
18+
19+
- `mise dev:deps``shards install`
20+
- `mise dev:build` — compile a dev binary to `bin/squarectl`
21+
- `mise dev:spec` — run the test suite (`crystal spec`)
22+
- `mise dev:ameba` — static analysis (`bin/ameba`)
23+
- `mise dev:format``crystal tool format src/`
24+
- `mise release:build` / `mise release:static` — release binaries (static build runs via Docker Buildx / `docker-bake.hcl`)
25+
26+
Run a single spec file / example directly:
27+
```sh
28+
crystal spec spec/squarectl/squarectl/task_factory_spec.cr
29+
crystal spec spec/squarectl/squarectl/task_factory_spec.cr:42 # by line
30+
```
31+
32+
Tests use **spectator** (not Crystal's built-in spec DSL) — see `spec/spec_helper.cr`.
33+
`Spectator.reset` calls `Squarectl.reset_config!` after each example because config is held in
34+
class-level state on the `Squarectl` module (`@@config`, `@@environments`). Any test that loads
35+
config relies on that reset.
36+
37+
Note: on macOS, `mise dev:fix-shards-command` is a required workaround for a Crystal packaging
38+
bug (crystal-lang/crystal#16746) before `shards` works — CI runs it before installing deps.
39+
40+
## Request flow (the important architecture)
41+
42+
Understanding one command path explains all of them — every subcommand follows the same 4-layer
43+
pipeline. Example: `squarectl compose up staging`.
44+
45+
1. **`src/squarectl/cli/*.cr`** — Admiral command tree. `CLI` (`cli.cr`) registers top-level
46+
subcommands (`compose`, `swarm`, `configs`, `secrets`, `kube`, `info`, `completion`), each of
47+
which registers its own leaf commands. Every leaf `run` does the same three steps:
48+
`Squarectl.load_config(flags.config)``Squarectl.find_environment(env, TARGET)`
49+
`TaskFactory.build(...)` → hand off to a `Tasks::*` class. The `SQUARECTL_TARGET` constant on
50+
each command class ("compose"/"swarm"/"kubernetes") is what selects the target.
51+
52+
2. **`src/squarectl/task_factory.cr`** — the merge engine. Builds a `Task` by combining the
53+
selected environment with the special `"all"` environment (global defaults). Env vars, domains,
54+
compose files, networks, SSL certs, setup commands, configs, and secrets are each resolved by
55+
selecting entries whose `target:` matches (via `find_matching_target`, which honors `"all"`)
56+
and merging global-then-env. Heavy use of macros (`define_method_hash` / `define_method_array`)
57+
generates the per-attribute resolvers. Also derives `_DOMAIN`/`_SCHEME` vars from any `_URL`
58+
var (`decompose_urls`) and namespaces config/secret keys as `<app>-<envshort>__<key>`.
59+
60+
3. **`src/squarectl/tasks/*.cr`** — thin orchestration per target. Class methods like
61+
`Tasks::Compose.up` decide the sequence of side effects (e.g. `up` creates SSL certs + networks
62+
first, then execs; `clean` tears them down). These call methods mixed into `Task`.
63+
64+
4. **`src/squarectl/commands/*.cr`** — the actual command builders, mixed into `Task` (see the
65+
`include` list in `task.cr`). `build_docker_compose_command` assembles argv, splits user args
66+
into pre-args (before the action) vs post-args via the `PRE_ARGS_*` allowlists in
67+
`commands/compose.cr`, and handles compose v1 (`docker-compose`) vs v2 (`docker compose`).
68+
Everything ultimately runs through **`Executor`** (`executor.cr`): `run_command` (wait),
69+
`exec_command` (replace process), or `capture_output`. Set `SQUARECTL_DEBUG=true` to print the
70+
full command line + env instead of guessing what ran.
71+
72+
## Config model & conventions
73+
74+
- `src/squarectl/config/*.cr` are `YAML::Serializable` structs mapping the `squarectl.yml` schema
75+
(`SquarectlConfig``app`, `compose.version`, `environments[]`; each `SquarectlEnvironment` has
76+
`server`, `env_vars`, `networks`, `compose_files`, `domains`, `ssl_certificates`,
77+
`setup_commands`, `config_files`, `secret_files`).
78+
- Config is a **Crinja (Jinja) template** rendered with `ENV` before parsing — `Squarectl.load_config`
79+
runs `Crinja.render` first, so `{{ ENV.FOO }}` works in `squarectl.yml`.
80+
- Directory conventions relative to the project (`Squarectl.root_dir` = cwd):
81+
`squarectl/base.yml`, `squarectl/targets/<target>/{common,<env>}.yml`,
82+
`squarectl/targets/common/`, and `kubernetes/<env>/`. These base compose files are always
83+
prepended to the resolved compose file list (see `compose_file_*_for` in `squarectl_environment.cr`).
84+
- The environment named **`all`** is global defaults merged into every other environment. An entry
85+
with `target: all` (or a target array) applies across targets.
86+
- `development` environment is restricted to the `compose` target only (`find_environment` raises otherwise).
87+
- Runtime vars injected into every task: `SQUARECTL_CWD/APP/TARGET/ENV/ENV_SHORT` (see `Task#runtime_env_vars`).
88+
89+
## Conventions
90+
91+
- `ameba:disable` inline comments are used deliberately (e.g. for `not_nil!` and Admiral's
92+
`Lint/UselessAssign` on flag definitions) — keep them when editing those lines.
93+
- Commit messages follow Conventional Commits (`commitlint.config.js`): `feat:`, `fix:`, `build:`,
94+
`ci:`, etc.
95+
- crystalline (the Crystal LSP, in `mise.toml [tools]`) is for editors only and is disabled in CI
96+
via `MISE_DISABLE_TOOLS` because its macOS binary needs Homebrew LLVM.

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
[![GitHub Release](https://img.shields.io/github/v/release/jbox-web/squarectl)](https://github.com/jbox-web/squarectl/releases/latest)
66
[![Docker Image](https://img.shields.io/docker/v/nicoladmin/squarectl/latest?color=green&label=Docker%20Image&logo=docker)](https://hub.docker.com/r/nicoladmin/squarectl)
77

8+
`squarectl` is a command-line tool that unifies application deployment across
9+
**Docker Compose**, **Docker Swarm** and **Kubernetes** from a single configuration file.
10+
11+
From a `squarectl.yml` describing your application and its environments
12+
(`development`, `staging`, `production`, ...), squarectl assembles the right list of compose files,
13+
environment variables, networks, SSL certificates, configs and secrets, then runs the underlying
14+
command (`docker compose`, `docker stack`, `kubectl`, `kompose`).
15+
816
## Installation
917

1018
### Manual installation
@@ -20,3 +28,51 @@ Add this to your .bashrc
2028
```sh
2129
source <(squarectl completion bash)
2230
```
31+
32+
## Usage
33+
34+
Every command targets a **target** (`compose`, `swarm`, `kube`) and takes an **environment** as an
35+
argument. The configuration file defaults to `squarectl.yml` (use `--config`/`-c` to change it):
36+
37+
```sh
38+
# Docker Compose
39+
squarectl compose config staging # print the resolved compose configuration
40+
squarectl compose build staging # build the images
41+
squarectl compose up staging # create SSL certificates + networks, then start the stack
42+
squarectl compose down staging # stop the stack
43+
squarectl compose exec staging <svc> # run a command inside a service
44+
squarectl compose clean staging # stop everything and remove networks + certificates
45+
46+
# Docker Swarm
47+
squarectl swarm deploy production # docker stack deploy
48+
squarectl swarm destroy production # docker stack rm
49+
squarectl configs create production # manage Docker Swarm Configs
50+
squarectl secrets create production # manage Docker Swarm Secrets
51+
52+
# Kubernetes
53+
squarectl kube convert production -o out/ # convert the compose config to manifests (kompose)
54+
squarectl kube deploy production # kubectl apply
55+
56+
# Misc
57+
squarectl info compose staging # print the resolved configuration for a target/environment
58+
```
59+
60+
Arguments after the environment are passed through as-is to the underlying tool
61+
(e.g. `squarectl compose up staging --detach`). Export `SQUARECTL_DEBUG=true` to print the full
62+
command line and environment instead of running it blindly.
63+
64+
## Development
65+
66+
The project is written in [Crystal](https://crystal-lang.org) and the development environment is
67+
managed by [mise](https://mise.jdx.dev) (see `mise.toml`):
68+
69+
```sh
70+
mise dev:deps # install dependencies (shards install)
71+
mise dev:build # compile a development binary into bin/
72+
mise dev:spec # run the test suite
73+
mise dev:ameba # static code analysis
74+
mise dev:format # format the code
75+
```
76+
77+
Release binaries (static, multi-arch) are produced via `mise release:static`
78+
(Docker Buildx / `docker-bake.hcl`).

0 commit comments

Comments
 (0)