Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"major": 1,
"minor": 5,
"minor": 6,
"patch": 0,
"prerelease": ""
}
35 changes: 25 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,16 +469,31 @@ TMI uses staticcheck for Go code quality analysis. The project has intentionally
- `test(integration): add database connection pooling tests`
- `deps: update Gin framework to v1.11.0`

### Automatic Versioning

TMI uses automatic semantic versioning (0.MINOR.PATCH) based on conventional commits:

- **Feature commits** (`feat:`): Post-commit hook increments MINOR version, resets PATCH to 0 (0.9.3 -> 0.10.0)
- **All other commits** (`fix:`, `refactor:`, etc.): Post-commit hook increments PATCH version (0.9.0 -> 0.9.1)
- **Version file**: `.version` (JSON) tracks current state
- **Script**: `scripts/update-version.sh --commit` (automatically called by post-commit hook)

Version updates are fully automated. All feature development occurs in dev/<semver>/<feature-name> branches or in feature/<feature-name> branches that are children of dev/<semver> branches; those branches are not auto-versioned so that new features don't bump the semantic version multiple times during development of a single feature or release. The main branch only gets direct commits for patching, security fixes, and merging of release branches.
### Versioning — currently MANUAL (see #627)

**Automatic versioning is disabled.** `scripts/hooks/post-commit` is an
explanatory no-op. It could not fire under the PR-only workflow: it exited early
unless `HEAD` was on `main` (commits are authored on `fix/*`/`dev/*` branches),
and the commit that lands on `main` comes from GitHub's squash-merge, where no
local hook runs. It had been silently doing nothing — `main` sat at 1.5.0 across
several `feat:` merges.

Until #627 lands, **bump versions by hand as part of the change**, and keep all
three in step (they are independent and have already drifted):

- `.version` (JSON) — the source of the server build version
- `api-schema/tmi-openapi.json` → `info.version`
- verify with `make build-server`, which prints the version it embedded

Intended scheme once automated: `feat:` → MINOR (reset PATCH), everything else →
PATCH. With squash-merge the PR title is the conventional-commit subject, so that
is the string to parse. `scripts/update-version.sh` still works when invoked
directly.

All feature development occurs in dev/<semver>/<feature-name> branches or in
feature/<feature-name> branches that are children of dev/<semver> branches. The
main branch only gets direct commits for patching, security fixes, and merging of
release branches.

## Custom Tools

Expand Down
37 changes: 35 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,31 @@ SERVER_PORT ?= 8080
# Default database backend for dev environment (postgres|oracle)
DB ?= postgres

# Default kube cluster target for dev environment (docker-desktop|k3s|kind)
CLUSTER ?= docker-desktop
# Kube cluster target for the dev environment (docker-desktop|k3s).
#
# DELIBERATELY NO DEFAULT. A wrong-cluster operation is silent and expensive:
# `make dev-up` used to default to docker-desktop, so running it while the
# server under test lived on k3s rebuilt and rolled a cluster nobody was
# looking at, leaving the real target stale — and `make dev-status` reported
# against a different cluster than the one just deployed. The destructive
# targets (dev-nuke, dev-down) make the same mistake unrecoverable.
#
# Every dev-* target guards on this via REQUIRE_CLUSTER.
CLUSTER ?=

# Fail with an actionable hint when a cluster-targeting target is invoked
# without CLUSTER. $@ is the target being run, so the hint is copy-pasteable.
define REQUIRE_CLUSTER
if [ -z "$(CLUSTER)" ]; then \
printf 'Error: CLUSTER is required for `make %s` — there is no default.\n\n' "$@" >&2; \
printf ' make %s CLUSTER=docker-desktop # local Docker Desktop Kubernetes\n' "$@" >&2; \
printf ' make %s CLUSTER=k3s # remote k3s cluster\n\n' "$@" >&2; \
printf 'Picking for you is how a deploy lands on the wrong cluster: the target\n' >&2; \
printf 'you are not watching gets rebuilt while the one under test stays stale.\n' >&2; \
printf 'Current kube context is %s (informational only — it does NOT set the target).\n' "$$(kubectl config current-context 2>/dev/null || echo unknown)" >&2; \
exit 2; \
fi
endef

# ============================================================================
# ATOMIC COMPONENTS - Infrastructure Management
Expand Down Expand Up @@ -330,33 +353,43 @@ tilt-down: ## Stop Tilt and restore the prod-shaped server
# ============================================================================

dev-up: ## Bring up the full dev environment (cluster + deploy). DB=postgres|oracle CLUSTER=docker-desktop|k3s
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --db $(DB) --cluster $(CLUSTER) up

dev-down: ## Tear down the dev environment; KEEP db data
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --db $(DB) --cluster $(CLUSTER) down

dev-restart: ## Rebuild the server image + roll the server pod (cluster + db untouched)
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --db $(DB) --cluster $(CLUSTER) restart

dev-reset: ## Soft known-state: redeploy the stack with fresh images; KEEP db data
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --db $(DB) --cluster $(CLUSTER) reset

dev-nuke: ## Hard known-state: destroy everything incl. db data + images, rebuild
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --db $(DB) --cluster $(CLUSTER) nuke

dev-status: ## dev environment status dashboard
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --cluster $(CLUSTER) status

dev-logs: ## Stream the tmi-server pod logs
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --cluster $(CLUSTER) logs

dev-deploy: ## (Re)apply manifests + rollout without recreating cluster/db
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --db $(DB) --cluster $(CLUSTER) deploy

dev-cluster-up: ## Switch to the cluster kube context (docker-desktop or k3s)
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --cluster $(CLUSTER) cluster up

dev-cluster-down: ## No-op for docker-desktop and k3s (clusters are not owned)
@$(REQUIRE_CLUSTER)
@uv run scripts/devenv.py --cluster $(CLUSTER) cluster down

# --- deprecated aliases (removable next release) ---
Expand Down
Loading
Loading