Preskoči na sadržaj

Zašto dva artefakta — services.json vs ci-state.json

TL;DR

services.json je statički registar (commit-permanent, šta servis JESTE). ci-state.json je dinamički state (per-run, šta servis RADI upravo). Miješanje ove dvije uloge je najčešći drift pattern — drži ih odvojene.

Uloge

Artifact Kad se mijenja Ko čita Ko piše
services.json Nikad za vrijeme pipeline-a (commit-only) ci/service_manifest.py developer (commit)
ci-state.json Svaki verb (bump/seed/build/scan/deploy/notify) ci/pipeline_state.py business verbs

service_manifest.py je read-only za services.json — nijedan verb ne smije da piše u njega za vrijeme pipeline-a.

pipeline_state.py je read+write za ci-state.json — jedini dozvoljeni writer. Raw file writes iz verb-ova su zabranjeni.

Šta živi gdje

services.json (komitovan)

{
  "schema": "https://schemas.infopuls.app/services/v31.json",
  "environments": {
    "production": { "infisical_env": "prod" }
  },
  "services": {
    "api": {
      "path": "apps/api",
      "build": { "enabled": true, "kind": "docker", ... },
      "release": { "enabled": true, "scheme": "semver", ... },
      "deploy": { "enabled": true, "mode": "coolify", ... },
      "observability": { "sentry": { ... } }
    }
  }
}

Owner: developer. Lifecycle: commit, tag, release. Schema: ci/json/services.schema.json (hard-cut to v31).

ci-state.json (per-run, gitignored)

{
  "pipeline": {
    "deployment_type": "production",
    "release_commit": "abc123...",
    "release_mode": true,
    "head_commit": "def456..."
  },
  "services": {
    "api": {
      "version": "1.2.3",
      "image_tag": "1.2.3",
      "image": "infopuls/api:1.2.3",
      "build": { "status": "deployed", "duration_seconds": 245 },
      "deploy": { "status": "deployed", "task_definition_arn": "..." }
    }
  }
}

Owner: CI. Lifecycle: per-run, atomic write. Schema: ci/json/ci-state.schema.json (v10).

Tri invarianta (ne smije se kršiti)

  1. services.json je statički input; ci-state.json je dinamički output. Ne miješaj uloge.
  2. Tri selection liste znače različite stvari i ostaju odvojene:
  3. versioned_services — ko ima verziju
  4. build_services — ko se gradi ovaj run
  5. deploy_services — ko se deploy-uje ovaj run
  6. Schema i kod se mijenjaju zajedno. Promjena shape-a bez loader-a/recorder-a je drift.

Kada šta čitati

# services.json (kroz jedini loader)
from ci.service_manifest import load_manifest
manifest = load_manifest("services.json")
build_kind = manifest.services["api"].build.kind  # "docker"

# ci-state.json (kroz jedini reader)
from ci.pipeline_state import load_state
state = load_state("ci-state.json")
image_tag = state.services["api"].image_tag  # "1.2.3"

Nikad raw json.load(open("services.json")) u verb kodu.

Vidi i