Skip to content

Commit 9f2fd59

Browse files
n-rodriguezclaude
andcommitted
docs: document the codebase with descriptive comments
Add class/module and method-level comments explaining the resolution pipeline (CLI -> TaskFactory -> Tasks -> Commands -> Executor), the config merge engine and its macros, directory conventions, and the config models. Keeps the existing :nodoc: markers since this is an application, not a library. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7347781 commit 9f2fd59

34 files changed

Lines changed: 215 additions & 1 deletion

src/admiral_patch.cr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Monkey-patch on Admiral's base command adding uniform handling for unknown
2+
# subcommands/flags: run the block, and on any `Admiral::Error` print the error
3+
# (only when arguments were actually given) followed by the help text and exit 1.
4+
# Every command's `run` wraps its `super` in this.
15
class Admiral::Command
26
def rescue_unknown_cmd(&)
37
begin

src/squarectl.cr

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,42 @@ require "./admiral_patch"
1919
# Load squarectl
2020
require "./squarectl/**"
2121

22+
# Top-level namespace and configuration holder.
23+
#
24+
# The parsed configuration is kept in class-level state (`@@config`,
25+
# `@@environments`, `@@environment_all`) so that any component can reach it via
26+
# `Squarectl.config` without threading it through. Because this state is global,
27+
# specs must call `reset_config!` between examples (see `spec/spec_helper.cr`).
2228
module Squarectl
2329
VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }}
2430
GIT_REF = {{ `git log -n 1 --format="%H" | head -c 8`.chomp.stringify }}
2531

2632
@@environment_all : Squarectl::Config::SquarectlEnvironment?
2733

34+
# Human-readable version string, e.g. `1.6.0 (7347781a)`.
2835
def self.version
2936
"#{VERSION} (#{GIT_REF})"
3037
end
3138

39+
# Reads the config file, renders it as a Crinja (Jinja) template with the
40+
# current process environment exposed as `ENV`, then parses the result as YAML.
41+
# This is why `{{ ENV.FOO }}` works inside `squarectl.yml`.
3242
def self.load_config(config_path)
3343
config_file = File.read(config_path)
3444
rendered = Crinja.render(config_file, {"ENV" => env_vars_to_hash})
3545
self.config = Squarectl::Config::SquarectlConfig.from_yaml(rendered)
3646
self.environments = config.environments
3747
end
3848

49+
# Clears the cached config so a fresh one can be loaded. Used by the test suite.
3950
def self.reset_config!
4051
@@config = nil
4152
@@environments = nil
4253
@@environment_all = nil
4354
end
4455

56+
# Snapshot of the process environment as a plain hash, injected into the
57+
# Crinja template context.
4558
def self.env_vars_to_hash
4659
hash = Hash(String, String).new
4760
ENV.each { |k, v| hash[k] = v }
@@ -64,10 +77,16 @@ module Squarectl
6477
@@environments || [] of Squarectl::Config::SquarectlEnvironment
6578
end
6679

80+
# The special `all` environment holding global defaults that `TaskFactory`
81+
# merges into every other environment. Returns `nil` when not defined.
6782
def self.environment_all
6883
@@environment_all ||= environments.not_nil!.find { |e| e.name == "all" } # ameba:disable Lint/NotNil
6984
end
7085

86+
# Resolves the environment selected on the command line for the given target.
87+
# Matching is substring-based (`name.includes?`), so `prod` matches `production`.
88+
# Raises on an unknown target/environment, and forbids any non-`compose` target
89+
# on the `development` environment.
7190
def self.find_environment(environment, target)
7291
raise "Target not found: #{target}" if !%w[compose swarm kubernetes].includes?(target)
7392
env = environments.not_nil!.find(&.name.includes?(environment)) # ameba:disable Lint/NotNil
@@ -76,6 +95,8 @@ module Squarectl
7695
env
7796
end
7897

98+
# Whether the config requests Compose v1 (`docker-compose`) instead of v2
99+
# (`docker compose`). Drives the command prefix in `Commands::Compose`.
79100
def self.compose_v1?
80101
config.compose["version"] == 1
81102
end
@@ -84,28 +105,40 @@ module Squarectl
84105
config.app
85106
end
86107

108+
# Project directory conventions, all relative to the current working directory:
109+
# root_dir/ # the project (cwd)
110+
# root_dir/kubernetes/<env>/ # generated Kubernetes manifests
111+
# root_dir/squarectl/ # data_dir: base.yml lives here
112+
# root_dir/squarectl/targets/ # per-target compose files (<target>/common.yml, <target>/<env>.yml)
113+
# root_dir/squarectl/targets/common/ # extra compose files referenced by config
87114
def self.root_dir
88115
Path.new(Dir.current)
89116
end
90117

118+
# :ditto:
91119
def self.kubernetes_dir
92120
root_dir.join("kubernetes")
93121
end
94122

123+
# :ditto:
95124
def self.data_dir
96125
root_dir.join("squarectl")
97126
end
98127

128+
# :ditto:
99129
def self.targets_dir
100130
data_dir.join("targets")
101131
end
102132

133+
# :ditto:
103134
def self.targets_common_dir
104135
targets_dir.join("common")
105136
end
106137
end
107138

108-
# Start the CLI
139+
# Start the CLI, unless we are running under the spec suite (which requires the
140+
# module without wanting the command dispatcher to fire). Any uncaught exception
141+
# is reported as a message and turned into a non-zero exit code.
109142
unless Crystal.env.test?
110143
begin
111144
Squarectl::CLI.run

src/squarectl/cli.cr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
module Squarectl
2+
# Root of the Admiral command tree and the program entry point.
3+
#
4+
# Each top-level subcommand (defined under `cli/`) registers its own leaf
5+
# commands. Every leaf follows the same shape: load the config, resolve the
6+
# environment for its target, build a `Task`, and hand off to a `Tasks::*`
7+
# class. `rescue_unknown_cmd` (see `admiral_patch.cr`) prints help instead of
8+
# crashing on an unknown subcommand.
9+
#
210
# :nodoc:
311
class CLI < Admiral::Command
412
define_version Squarectl.version

src/squarectl/cli/completion.cr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module Squarectl
22
class CLI < Admiral::Command
33
class Completion < Admiral::Command
4+
# Prints the embedded Bash completion script so it can be sourced, e.g.
5+
# `source <(squarectl completion bash)`.
46
class Bash < Admiral::Command
57
def run
68
file = Squarectl::ShellCompletion.get("bash.sh")

src/squarectl/commands/compose.cr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
module Squarectl
22
module Commands
3+
# Builds and runs `docker compose` (or `docker-compose` on v1) commands.
4+
# Mixed into `Task`; used directly by the `compose` target and reused by the
5+
# `kube` target to render the merged compose config before conversion.
36
module Compose
7+
# docker-compose global flags that must appear *before* the action verb.
8+
# `PRE_ARGS_BOOL` take no value; `PRE_ARGS_FLAGS` take a following value (or
9+
# `--flag=value`). Everything else is treated as a post-action argument.
410
PRE_ARGS_BOOL = [
511
"--all-resources",
612
"--compatibility",
713
"--dry-run",
814
]
915

16+
# :ditto:
1017
PRE_ARGS_FLAGS = [
1118
"--ansi",
1219
"--env-file",
@@ -31,12 +38,19 @@ module Squarectl
3138
@executor.exec_command(tuple[:cmd], args: tuple[:args], env: task_env_vars)
3239
end
3340

41+
# Assembles the full argv:
42+
# <compose> --project-name <name> --file ... <pre-args> <action> <post-args>
43+
# On v2 the command is `docker` with a `compose` prefix arg; on v1 it is
44+
# `docker-compose` with no prefix (dropped via `compact`).
3445
def build_docker_compose_command(action, args)
3546
cmd, prefix = Squarectl.compose_v1? ? {"docker-compose", nil} : {"docker", "compose"}
3647
pre_args, post_args = extract_docker_args(args)
3748
{cmd: cmd, args: [prefix, "--project-name", project_name, compose_files_args(prefix: "--file"), pre_args, action, post_args].compact.flatten}
3849
end
3950

51+
# Splits user-supplied args into those that belong before the action verb
52+
# (matched against `PRE_ARGS_BOOL`/`PRE_ARGS_FLAGS`, consuming a value for
53+
# the latter) and everything else, which goes after.
4054
def extract_docker_args(args)
4155
pre_args = [] of String
4256
post_args = [] of String

src/squarectl/commands/configs.cr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Squarectl
22
module Commands
3+
# Creates/removes Docker Swarm configs on the deploy server, piping each
4+
# source file into `docker config create` via stdin. Mixed into `Task`.
35
module Configs
46
def create_docker_configs(args)
57
deploy_configs.each do |key, file|

src/squarectl/commands/info.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module Squarectl
22
module Commands
3+
# Renders the fully resolved task (paths, env vars, files, certs, configs,
4+
# secrets) as YAML for the `info` command — the introspection view of what
5+
# squarectl would actually run. Mixed into `Task`.
36
module Info
47
def squarectl_environment
58
{

src/squarectl/commands/kompose.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module Squarectl
22
module Commands
3+
# Runs `kompose` to convert a Compose configuration into Kubernetes
4+
# manifests. `run_kompose_convert` feeds it the already-rendered compose
5+
# config via a tempfile. Mixed into `Task`.
36
module Kompose
47
def run_kompose_convert(config, args)
58
tempfile = File.tempfile("docker-compose", &.print(config))

src/squarectl/commands/kubectl.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module Squarectl
22
module Commands
3+
# Applies the generated Kubernetes manifests (`kubectl apply -f`) and runs
4+
# setup commands inside pods, resolving the pod name from the
5+
# kompose-generated `io.kompose.service` label. Mixed into `Task`.
36
module Kubectl
47
def run_kubectl_apply
58
args = ["apply", "-f", environment.kubernetes_dir.to_s]

src/squarectl/commands/networks.cr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Squarectl
22
module Commands
3+
# Creates/removes the external Docker networks declared for the task
4+
# (before `compose up`, torn down on `clean`). Mixed into `Task`.
35
module Networks
46
def create_docker_networks
57
compose_networks.each do |net|

0 commit comments

Comments
 (0)