From c098b25616ae2a5617348b9f3ade2dfa2da3d996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=97=D0=B8=D0=BC=D0=B8=D0=BD?= Date: Fri, 15 May 2026 10:12:35 +0000 Subject: [PATCH] ci: re-tag on tag pipeline (saves ~5-7 min/release) --- .gitlab-ci.yml | 98 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0229b81..fac82a9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -304,15 +304,16 @@ build-docs: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" DOCKER_BUILDKIT: "1" - # Docker сборки только на main + tag. На feature-branch / MR pipeline'ах - # тратить ~2 мин × 5 services было бессмысленно — deploy происходит только - # после merge в main, MR валидируется тестами (maven-test/e2e). Экономия - # ~10 мин на каждый MR push. + # Docker сборки только на main. На tag pipeline вместо rebuild — `retag-*` + # jobs (см. .retag_base) которые pull'ят `:main-{parent-sha}` и tag'ают + # как `:v2-x-y-{sha}`. Same git SHA → same image content, нет смысла + # rebuild'ить дважды (раньше было ~5-7 min × 6 services × release). + # На feature-branch / MR pipeline'ах docker сборки тоже не запускаются — + # deploy происходит только после merge в main, MR валидируется тестами. # docker-docs переопределяет свой rules: блок (path-filter), этот rules: # затрагивает app/read-api/projection-writer/migrations/admin-ui. rules: - if: '$CI_COMMIT_BRANCH == "main"' - - if: '$CI_COMMIT_TAG' .publish_script: &publish_script | for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break; sleep 1; done @@ -434,16 +435,91 @@ docker-docs: script: - *publish_script rules: - # На main + tag собираем БЕЗ path-filter. Иначе resolve-tag emit'ит - # docs=main-, helm пытается pull этого тега, image отсутствует - # (docker-docs не запускался) → atomic rollback с context deadline - # exceeded. Layer cache при отсутствии docs/* changes делает rebuild - # ~30 sec — приемлемая цена за гарантию что image для tag существует. + # На main собираем БЕЗ path-filter (gives `:main-{sha}` image для каждого + # commit). На tag pipeline вместо rebuild — `retag-docs` (см. .retag_base). + # Layer cache при отсутствии docs/* changes делает rebuild ~30 sec — + # приемлемая цена за гарантию что `:main-{sha}` существует для retag. - if: '$CI_COMMIT_BRANCH == "main"' - - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' - if: '$CI_PIPELINE_SOURCE == "web"' 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 ─────────────────────────── # Single resolve-tag (always runs) → один UPSTREAM_IMAGE_TAG. Path-filter # работает на уровне docker-* jobs (backend skip если бэк не менялся,