Merge branch 'ci/retag-on-tag-pipeline' into 'main'

ci: re-tag on tag pipeline (saves ~5-7 min/release)

See merge request 2-6/2-6-4/terravault/ordinis!205
This commit is contained in:
Александр Зимин
2026-05-15 10:12:35 +00:00
+87 -11
View File
@@ -304,15 +304,16 @@ build-docs:
DOCKER_HOST: tcp://docker:2375 DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
DOCKER_BUILDKIT: "1" DOCKER_BUILDKIT: "1"
# Docker сборки только на main + tag. На feature-branch / MR pipeline'ах # Docker сборки только на main. На tag pipeline вместо rebuild — `retag-*`
# тратить ~2 мин × 5 services было бессмысленно — deploy происходит только # jobs (см. .retag_base) которые pull'ят `:main-{parent-sha}` и tag'ают
# после merge в main, MR валидируется тестами (maven-test/e2e). Экономия # как `:v2-x-y-{sha}`. Same git SHA → same image content, нет смысла
# ~10 мин на каждый MR push. # rebuild'ить дважды (раньше было ~5-7 min × 6 services × release).
# На feature-branch / MR pipeline'ах docker сборки тоже не запускаются —
# deploy происходит только после merge в main, MR валидируется тестами.
# docker-docs переопределяет свой rules: блок (path-filter), этот rules: # docker-docs переопределяет свой rules: блок (path-filter), этот rules:
# затрагивает app/read-api/projection-writer/migrations/admin-ui. # затрагивает app/read-api/projection-writer/migrations/admin-ui.
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG'
.publish_script: &publish_script | .publish_script: &publish_script |
for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break; sleep 1; done for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break; sleep 1; done
@@ -434,16 +435,91 @@ docker-docs:
script: script:
- *publish_script - *publish_script
rules: rules:
# На main + tag собираем БЕЗ path-filter. Иначе resolve-tag emit'ит # На main собираем БЕЗ path-filter (gives `:main-{sha}` image для каждого
# docs=main-<sha>, helm пытается pull этого тега, image отсутствует # commit). На tag pipeline вместо rebuild — `retag-docs` (см. .retag_base).
# (docker-docs не запускался) → atomic rollback с context deadline # Layer cache при отсутствии docs/* changes делает rebuild ~30 sec —
# exceeded. Layer cache при отсутствии docs/* changes делает rebuild # приемлемая цена за гарантию что `:main-{sha}` существует для retag.
# ~30 sec — приемлемая цена за гарантию что image для tag существует.
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/'
- if: '$CI_PIPELINE_SOURCE == "web"' - if: '$CI_PIPELINE_SOURCE == "web"'
when: manual when: manual
# ─── RETAG ON TAG PIPELINE ────────────────────
# Tag pipeline pull'ит `:main-{parent-sha}` (built на main pipeline предыдущего
# commit) и tag'ает как `:v2-x-y-{sha}` + `:latest` + `:$CI_COMMIT_REF_SLUG`.
# Сохраняет ~5-7 min × 6 services × release vs full rebuild — same git SHA →
# same image, deterministic.
#
# Parent SHA recovery: semantic-release создаёт chore commit с [skip ci]
# (нет main pipeline для него). Tag указывает на chore commit. `git log
# HEAD~1` → parent commit = original main commit что триггерил build.
# `:main-{parent-sha}` гарантированно существует в registry.
#
# GIT_DEPTH=10 — нужно walk back до parent commit (default depth=20 хватит).
.retag_base:
stage: publish
image: repo.nstart.cloud/nstart/docker-cli-buildx:1.0.0
services:
- name: repo.nstart.cloud/library/docker:29.1.2-dind
alias: docker
command: ["--tls=false"]
resource_group: docker-builds-v2
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
GIT_DEPTH: "10"
rules:
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/'
script:
- for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break; sleep 1; done
- echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY" -u "$REGISTRY_USER" --password-stdin
- IMG="$REGISTRY/$IMAGE_REPO/$SVC"
- PARENT_SHA=$(git log -1 --format=%h HEAD~1)
- SRC="$IMG:main-$PARENT_SHA"
- echo "Re-tag $SRC → $IMG:$IMAGE_TAG (+ :latest, :$CI_COMMIT_REF_SLUG)"
- docker pull "$SRC"
- docker tag "$SRC" "$IMG:$IMAGE_TAG"
- docker tag "$SRC" "$IMG:latest"
- docker tag "$SRC" "$IMG:$CI_COMMIT_REF_SLUG"
- docker push "$IMG:$IMAGE_TAG"
- docker push "$IMG:latest"
- docker push "$IMG:$CI_COMMIT_REF_SLUG"
retag-app:
extends: .retag_base
needs: []
variables:
SVC: ordinis-app
retag-read-api:
extends: .retag_base
needs: []
variables:
SVC: ordinis-read-api
retag-projection-writer:
extends: .retag_base
needs: []
variables:
SVC: ordinis-projection-writer
retag-migrations:
extends: .retag_base
needs: []
variables:
SVC: ordinis-migrations
retag-admin-ui:
extends: .retag_base
needs: []
variables:
SVC: ordinis-admin-ui
retag-docs:
extends: .retag_base
needs: []
variables:
SVC: ordinis-docs
# ─── TRIGGER DEPLOY ─────────────────────────── # ─── TRIGGER DEPLOY ───────────────────────────
# Single resolve-tag (always runs) → один UPSTREAM_IMAGE_TAG. Path-filter # Single resolve-tag (always runs) → один UPSTREAM_IMAGE_TAG. Path-filter
# работает на уровне docker-* jobs (backend skip если бэк не менялся, # работает на уровне docker-* jobs (backend skip если бэк не менялся,