# GitLab Releases with CalVer Auto-Versioning **Date**: 2026-03-07 **Status**: Approved ## Summary Replace MinIO binary distribution with GitLab Generic Package Registry + Releases. Every push to `main` that touches code auto-creates a CalVer tag, compiles, uploads binaries as GitLab generic packages, creates a GitLab Release, and deploys. MinIO retains sccache, training data, and model checkpoints (not release artifacts). ## Versioning **Scheme**: CalVer `vYYYY.MM.N` where N auto-increments per month. Examples: `v2026.03.1`, `v2026.03.2`, `v2026.04.1` **Increment logic**: Query GitLab tags API for latest `vYYYY.MM.*`, parse N, increment. If no tag exists for current month, start at 1. **Cargo.toml**: Workspace `version` stays at `1.0.0` (Cargo version != release version). Runtime version comes from `FOXHUNT_BUILD_VERSION` env var baked at compile time via `option_env!()` in `common/src/build_info.rs` (existing design from 2026-03-04). ## Branching Model Trunk-based. No develop/release branches. ``` feature/* --merge--> main --auto--> tag vYYYY.MM.N -> compile -> release -> deploy ``` ## Pipeline Changes (ci-pipeline-template.yaml) ### Current DAG ``` detect-changes -> [compile-services | compile-training | build-web-dashboard] -> deploy-services ``` ### New DAG ``` detect-changes -> create-tag (if code changed) | +---------+---------+ | | compile-services compile-training | | +---------+---------+ | upload-release -> deploy-services ``` Non-code changes (docker images, dashboard) remain unchanged and don't create tags. ### New template: create-tag - Runs on `platform` node (lightweight) - Uses GitLab API via deploy token with `api` scope - Computes version: `YYYY.MM` from date, queries `GET /api/v4/projects/:id/repository/tags?search=vYYYY.MM` - Increments N, creates tag via `POST /api/v4/projects/:id/repository/tags` - Outputs the tag name for downstream steps ### Modified: compile-services / compile-training - `FOXHUNT_BUILD_VERSION` = tag from create-tag step (was `YYYY.MM.argo`) - Upload destination changes from MinIO to GitLab Generic Package Registry: ``` PUT /api/v4/projects/:id/packages/generic/foxhunt-services// PUT /api/v4/projects/:id/packages/generic/foxhunt-training// ``` - Removes rclone + MinIO credentials for binary upload - Adds `GITLAB_API_TOKEN` from secret ### New template: upload-release - Creates GitLab Release via `POST /api/v4/projects/:id/releases` - Attaches package links as release assets - Auto-generates release notes from commits since last tag: `GET /api/v4/projects/:id/repository/changelog?version=` - Runs after both compile steps complete ### Modified: deploy-services - Sets `FOXHUNT_RELEASE` annotation on deployments to trigger rollout - initContainers now know which version to fetch ## Service Deployment Changes (infra/k8s/services/*.yaml) ### initContainer: fetch-binary Before (MinIO): ```yaml - name: fetch-binary args: - | rclone copyto ":s3:foxhunt-binaries/services/trading-service" "/binaries/trading-service" \ --s3-provider=Minio --s3-endpoint=http://minio.foxhunt.svc.cluster.local:9000 ... env: - name: MINIO_ACCESS_KEY ... - name: MINIO_SECRET_KEY ... ``` After (GitLab Generic Packages): ```yaml - name: fetch-binary args: - | set -e curl -fSL -o /binaries/trading-service \ --header "DEPLOY-TOKEN: ${GITLAB_DEPLOY_TOKEN}" \ "${GITLAB_API}/projects/1/packages/generic/foxhunt-services/${FOXHUNT_RELEASE}/trading-service" chmod +x /binaries/trading-service env: - name: GITLAB_DEPLOY_TOKEN valueFrom: secretKeyRef: name: gitlab-deploy-token key: token - name: GITLAB_API value: "http://gitlab-webservice-default.foxhunt.svc.cluster.local:8181/api/v4" - name: FOXHUNT_RELEASE value: "v2026.03.1" # Updated by deploy-services step ``` ### Training job-template.yaml Same pattern: replace rclone/MinIO with curl/GitLab for binary fetch. Training data sync stays on MinIO (not a release artifact). ## Secrets ### New - `gitlab-deploy-token`: GitLab deploy token with `read_package_registry` scope (for service pods) - `gitlab-api-token`: GitLab PAT or deploy token with `api` scope (for CI tag/release creation) ### Removed from binary path - `minio-credentials` no longer needed in service deployments or compile upload steps - MinIO credentials remain for: sccache, training data sync, model checkpoints ## Rollback ```bash # Roll back to previous release kubectl -n foxhunt set env deployment/trading-service FOXHUNT_RELEASE=v2026.03.1 kubectl -n foxhunt rollout restart deployment/trading-service ``` All previous binaries remain available in GitLab's package registry indefinitely. ## What stays on MinIO | Bucket | Purpose | Change | |--------|---------|--------| | foxhunt-sccache | Rust build cache | No change | | foxhunt-training-data | DBN market data | No change | | foxhunt-training-results | Training outputs | No change | | foxhunt-models | Model checkpoints | No change | | foxhunt-binaries | **Service/training binaries** | **Decommission after migration** | ## Migration 1. Deploy new CI pipeline with dual-write (MinIO + GitLab) for one release 2. Switch service initContainers to GitLab fetch 3. Verify all services boot correctly 4. Remove MinIO binary upload from CI 5. Delete `foxhunt-binaries` bucket contents (keep bucket for sccache) ## Files Changed ### New files - `crates/common/src/build_info.rs` — version function (from 2026-03-04 design) ### Modified files - `infra/k8s/argo/ci-pipeline-template.yaml` — new create-tag + upload-release templates, modified compile steps - `infra/k8s/services/*.yaml` (8 files) — initContainer fetch from GitLab - `infra/k8s/training/job-template.yaml` — binary fetch from GitLab - `infra/k8s/secrets/` — new gitlab-deploy-token, gitlab-api-token - `crates/common/src/lib.rs` — re-export build_info