Skip to content

chore(ci): migrate GitHub Actions CI to GitLab CI#2543

Draft
universal-itengineer wants to merge 60 commits into
mainfrom
chore/ci/add-gitlab-ci
Draft

chore(ci): migrate GitHub Actions CI to GitLab CI#2543
universal-itengineer wants to merge 60 commits into
mainfrom
chore/ci/add-gitlab-ci

Conversation

@universal-itengineer

@universal-itengineer universal-itengineer commented Jun 25, 2026

Copy link
Copy Markdown
Member

Description

Migrate the repository CI from GitHub Actions to GitLab CI, following the
approved migration plan in
tmp/ai-summary/gitlab-ci-migration-plan.md.
The root .gitlab-ci.yml is now a thin include-only entrypoint; the real
pipeline lives in .gitlab/ci/**.

What is added

  • .gitlab/ci/ structure: defaults.yml, workflow.yml, stages.yml,
    includes.yml, variables.yml, changelog-sections.txt.
  • .gitlab/ci/jobs/ — job definitions porting the GitHub workflows:
    • build-dev.yml, build-prod.yml, deploy-dev.yml, deploy-prod.yml,
      precache.yml, cleanup.yml.
    • lint-validate.yml (shellcheck, yaml, helm-templates, gens-files,
      gitlab-ci, go), lint-dmt.yml.
    • test.yml, test-scripts-js.yml, test-scripts-python.yml,
      test-d8v-cli.yml.
    • gitleaks.yml, cve-scan.yml (per-MR + daily + manual), svace.yml.
    • auto-assign-author.yml, check-changelog.yml, check-milestone.yml,
      changelog.yml, translate-changelog.yml, backport.yml,
      manual-tools.yml (mrs:summary), release-channels.yml, info.yml.
  • .gitlab/ci/templates/ — reusable hidden templates grouped into
    base/ (build, deploy, info, dual_registry_login), dev/
    (dev, dev_tags, dev_vars, main, release), release/
    (prod_always, prod_manual, prod_vars).
  • .gitlab/ci/scripts/bash/ — shell helpers backing the jobs:
    auto-assign-author.sh, backport.sh, changelog-milestone.sh,
    check-changelog-entry.sh, check-milestone.sh, check-runner-tools.sh,
    gitlab-ci-lint.sh, notify-release-loop.sh, set-vars.sh,
    setup-mr-settings.sh, and lib/api.sh (shared GitLab API helper).
  • .gitlab/ci/scripts/python/changelog_collect.py,
    check_changelog_entry.py.
  • .gitlab/scripts/js/mrs_notifier.mjs (GitLab counterpart of
    prs_notifier.mjs) + mrs_notifier.test.mjs (node:test smoke test) +
    package.json.
  • Runner tag deckhouse is used everywhere; the runner is a shell executor,
    so jobs call check-runner-tools.sh in before_script instead of relying
    on image:.

What is changed

  • Root .gitlab-ci.yml reduced to include: .gitlab/ci/includes.yml.
  • Prod build/deploy: MODULE_EDITION is set per edition via parallel:matrix
    (CE for ce, EE for ee/se-plus/fe); se-plus edition added to the
    build/deploy matrices — matching the GitHub release workflows.
  • release-channels.yml adds a manual Run pipeline flow (prod:* jobs)
    mirroring release_module_release-channels.yml: requirements check, build
    and deploy per edition, version verification matrix, GitLab release
    creation, and Loop notification. The pipeline must run on the tag
    (RELEASE_TAG == CI_COMMIT_TAG, enforced by prod:print-vars).
  • test jobs use a needs: DAG so they run in parallel with lint instead
    of waiting for the whole lint stage.
  • Manual changelog/backport jobs are allow_failure: true so an unplayed
    manual job does not block MR pipelines.
  • svace:set-vars is gated so its MODULES_MODULE_TAG dotenv no longer leaks
    into MR build jobs.
  • lint:shellcheck runs inside a koalaman/shellcheck-alpine:v0.11.0
    container; bash and python helper scripts are scanned.
  • Taskfile.yaml / Taskfile.init.yaml: gohooks task name fix and
    GOTOOLCHAIN=auto so the runner Go toolchain auto-downloads the version
    required by go.mod.
  • images/vm-route-forge: bpf2go regenerated for cilium/ebpf v0.17.1 using
    clang-14 inside a docker image (generated artifacts committed).

What is intentionally NOT migrated (first iteration)

  • e2e workflows (.github/workflows/e2e-*) — out of scope.
  • Reactive slash-commands / webhook listener — GitLab cannot start
    pipelines on MR comments or label changes natively. Manual + scheduled jobs
    cover the same surface; a webhook-listener is tracked as a follow-up.

Why do we need it, and what problem does it solve?

This is preparation for migrating development of the
deckhouse/virtualization module to GitLab. The real CI previously lived in
.github/workflows/; this PR ports it to GitLab CI so the pipeline keeps
working once the repository moves.

What is the expected result?

  1. A push to an MR branch triggers lint:*, test:*, build_dev,
    cve:scan:mr, gitleaks, auto-assign-author, check:milestone,
    check:changelog.
  2. A merge to main/release-* triggers build_dev + deploy_to_dev and
    translate:changelog.
  3. A tag push triggers build_prod / deploy_to_prod_*.
  4. Manual pipelines: backport (TARGET_BRANCH=release-X.Y),
    changelog:milestone (MILESTONE_TITLE=...), mrs:summary,
    prod:* release-channel dispatch (run on the tag with
    RELEASE_TAG/RELEASE_CHANNEL/EDITION_*).
  5. Schedules: cve:scan:daily, svace:*, gitleaks:full:scheduled,
    precache, changelog:*, mrs:summary, cleanup.
  6. task lint / task validation:* green locally; GitLab CI lint green on
    the MR pipeline.

Checklist

  • The code is covered by unit tests.
    • mrs_notifier.test.mjs smoke test added; python scripts covered by
      py_compile smoke check.
  • e2e tests passed.
  • Documentation updated according to the changes.
    • .gitlab/README.md migration log removed; required CI/CD variables are
      documented in the migration plan
      tmp/ai-summary/gitlab-ci-migration-plan.md §4 / §11.13.
  • Changes were tested in the Kubernetes cluster manually.
    • Validated on virt-test: gohooks task name, GOTOOLCHAIN=auto,
      svace tag isolation, shellcheck green via docker image v0.11.0,
      bash/python script split.

Changelog entries

section: ci
type: feature
summary: "Migrate repository CI from GitHub Actions to GitLab CI with full parity: build/deploy (dev/prod, all editions incl. se-plus), lint, tests, secrets/CVE/Svace scanning, changelog/backport automation, MR auto-assign, and manual release-channel dispatch."
impact_level: low

@universal-itengineer universal-itengineer self-assigned this Jun 25, 2026
@universal-itengineer universal-itengineer changed the title Chore/ci/add gitlab ci chore(ci): migrate GitHub Actions CI to GitLab CI Jun 25, 2026
@universal-itengineer universal-itengineer added this to the v1.10.0 milestone Jun 26, 2026
Comment thread .gitlab/ci/templates/dev/main.yml Outdated
Comment thread .gitlab/ci/workflow.yml Outdated
- .prod_vars
rules:
# https://regex101.com/r/lToOvi/1
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the difference between prod_manual.yml and prod_always.yml? they're identical if you remove comments. why do we have such a distinction?

Comment on lines +27 to +31
.dual_registry_login:
variables:
DEV_MODULES_REGISTRY: "${DEV_REGISTRY}"
DEV_MODULES_REGISTRY_LOGIN: "${DEV_MODULES_REGISTRY_LOGIN}"
DEV_MODULES_REGISTRY_PASSWORD: "${DEV_MODULES_REGISTRY_PASSWORD}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we have .dual_registry_login job that logins exclusively into dev registry? this is misleading. why can't we have use both prod and dev templates in one job?

Comment on lines +16 to +22
# Upstream `.build` carries two `rules:` that fire on ANY branch or tag
# push (`if: $CI_COMMIT_BRANCH`, `if: $CI_COMMIT_TAG`). GitLab CI merges
# rules from all `extends:` parents with the parent's rules evaluated
# first, so the upstream rules always win. That regresses behavior for
# jobs like build_dev_tags, build_main, build_prod which need to gate on
# specific branch / tag patterns provided by .dev / .dev_tags / .main /
# .prod_always.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to consult SSDLC on this matter, maybe they can suggest a workaround / different job structure. Same with deploy.yml.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
- auto-assign-author: run on every MR event instead of gating on
  changes to the job's own files, so the MR author is actually
  auto-assigned when no assignee is set (the script is idempotent and
  skips when an assignee already exists)
- workflow: skip redundant branch pipelines when an open MR exists
  (CI_OPEN_MERGE_REQUESTS guard) to avoid duplicate branch + MR pipelines
- lint-validate: drop unused RUN_ON_CHANGE matrix var from check:gens-files
  and fold vm-route-forge into the single COMPONENT matrix

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
test:hooks job ran 'task hooks:test' which does not exist (the task is
gohooks:test), matching the migration plan and Taskfile.

lint/test:virtualization-controller jobs failed at 'task virtualization-controller:init'
because runner go (1.25.9, GOTOOLCHAIN=go1.25.9) is older than go.mod's
'go 1.25.11'. Add global GOTOOLCHAIN=auto so the host toolchain
auto-downloads the version required by go.mod, mirroring actions/setup-go@v5.
GitLab CI variables override runner environment variables.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
build_dev pushed tag 'chore_ci_add-gitlab-ci-svace' instead of mr<iid>
because svace:set-vars ran on every MR (no rules) and emitted a dotenv
MODULES_MODULE_TAG=<branch>-svace, and build_dev had no needs: so GitLab's
legacy artifact inheritance loaded that dotenv and overrode .dev's
mr${CI_MERGE_REQUEST_IID} tag.

Add needs: [] to build_dev/build_dev_tags/build_main to opt into DAG mode
with no artifact downloads (their tag/registry vars come from their own
templates). Gate svace:set-vars to the same SVACE_PIPELINE_ENABLED /
schedule / web contexts as svace:build so it no longer runs on ordinary
MR pipelines.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
lint:shellcheck failed on the shell executor because shellcheck is not
preinstalled on the runner host, and check-runner-tools.sh hard-required it.

Add .gitlab/ci/scripts/install-shellcheck.sh which downloads the official
koalaman/shellcheck pre-compiled static binary from GitHub Releases into
~/.local/bin when shellcheck is missing (no-op when already on PATH). This
is distro-agnostic — works on both apt- and rpm-based runners without root.

lint:shellcheck before_script drops shellcheck from the check-runner-tools
guard and runs install-shellcheck.sh instead, so 'task lint:shellcheck' in
script: finds it on PATH (the shell executor shares one bash session between
before_script and script).

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
install-shellcheck.sh failed with HTTP 404: the release asset is named
shellcheck-<version>.linux.<arch>.tar.xz but the URL was missing the
.tar.xz suffix. The inner tarball directory is also shellcheck-<version>
(no arch suffix), so the previous --strip-components path was wrong too.

Append .tar.xz to the URL and extract into a temp dir, then locate the
binary via 'find -name shellcheck' instead of hard-coding the inner
directory name. Verified: curl returns 200, tar extracts the binary.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
task lint:shellcheck runs shellcheck inside the
koalaman/shellcheck-alpine Docker image (Taskfile.yaml), not via a
host-installed binary, so install-shellcheck.sh was dead code — the
v0.11.0 binary it installed was never used.

Remove install-shellcheck.sh and have lint:shellcheck before_script check
for docker instead. The job already ran successfully via the docker image;
this just stops installing an unused binary on every run.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The lint:shellcheck task only scanned a hardcoded list of 5 paths and
missed .gitlab/ci/scripts entirely, and produced no output when clean,
so a passing job looked like nothing was checked.

Collect files via 'find .gitlab/ci/scripts -type f -name *.sh' (whole
tree, recursive) plus the existing explicit list, and log the file count,
the file list, and a 'no issues found' footer. Use find instead of **
glob so it works under plain sh (task default shell, no globstar).

Fix SC1091 in the 5 scripts that source lib/api.sh by making the
'# shellcheck source=' directives repo-root-relative so shellcheck follows
them. Suppress SC2154 for CI_* / GITLAB_API_TOKEN (runtime-injected by the
GitLab Runner) with a file-level disable + explanation.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
v0.11.0 is the latest stable ShellCheck release (2025-08-04), available as
the koalaman/shellcheck-alpine:v0.11.0 Docker Hub tag. Pin the version tag
for reproducibility.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The .gitlab/ci/scripts directory mixed .sh and .py files together. Split
into language-specific subfolders:

  .gitlab/ci/scripts/bash/    .sh wrappers + lib/api.sh
  .gitlab/ci/scripts/python/  .py scripts

Update all references: job/template YAML invocations, the shellcheck source=
directives, the wrapper -> python path resolution (/../python/),
and the README tree.

Taskfile lint:shellcheck now points directly at .gitlab/ci/scripts/bash/
(and bash/lib/) instead of scanning the whole scripts tree with find, since
the bash scripts live in their own folder now.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…o lint:go

Fixes two failing GitLab CI jobs and restores the lost "lint all Go
modules" step from the GitHub Actions migration:

- lint:helm-templates: install helm v3 and jq as portable prebuilt
  binaries in before_script (arch-aware, no sudo) instead of relying on
  the runner host; require docker/git/curl/python3 for kubeconform.sh.
  HELM_VERSION=3.16.3 and JQ_VERSION=1.7.1 added to variables.yml.
  kubeconform.sh itself is untouched.

- lint:go: new job in lint-validate.yml, direct migration of the GH
  lint_go job from dev_module_build.yml. Installs the pinned prebuilt
  golangci-lint v${GOLANGCI_LINT_VERSION} via install.sh (fixes the
  flaky install.sh-latest checksum failure) and runs golangci-lint run
  in every directory shipping a .golangci.yaml, pruning the same
  upstream modules as GH (images/cdi-cloner/cloner-startup,
  images/dvcr-artifact, test/performance/shatal).

- Remove the redundant single-dir lint:virtualization-controller job
  from test.yml (now covered by lint:go).

- Taskfile.init.yaml: bump golangci-lint install from v1.64.8 to v2.11.1
  via the v2 module path, aligning with GOLANGCI_LINT_VERSION and the
  v2-format .golangci.yaml configs in every subproject.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Three matrix legs of check:gens-files failed on the GitLab shell runner:

- virtualization-artifact: go generate needs the moq binary. "go install
  tool" puts it in $(go env GOPATH)/bin, which the shell runner does not
  add to PATH (GitHub setup-go@v5 did this automatically). Export PATH
  with GOPATH/bin so //go:generate moq resolves.

- vm-route-forge: bpf2go (go tool github.com/cilium/ebpf/cmd/bpf2go)
  shells out to clang and llvm-strip, which are absent on the runner.
  Install the same apt packages as the GH workflow dev_validation.yaml
  (llvm, linux-headers, clang, libbpf-dev, uuid-runtime, gcc-multilib),
  guarded by command presence checks and sudo -n to fail fast instead of
  hanging on a password prompt.

- api: "task generate" is defined in api/Taskfile.dist.yaml, not the
  root Taskfile, so it must run from inside api/ (mirrors the GH job
  which does cd ./api first). Run it as cd api && go install tool &&
  task generate.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The vm-route-forge leg of check:gens-files needs clang, llvm-strip and
the libbpf/kernel headers to run bpf2go (go tool
github.com/cilium/ebpf/cmd/bpf2go). The GitLab shell runner runs as the
gitlab-runner user, which has no passwordless sudo, so the apt-get
install used by the GitHub workflow fails with "sudo: a password is
required".

Run the generation inside the public ghcr.io/cilium/ebpf-builder image
instead, bind-mounting the repo at /src. The image ships clang-22,
llvm-strip-22, libbpf-dev and linux headers. Point bpf2go at the
versioned binaries via BPF2GO_CC/BPF2GO_STRIP (the image has no bare
clang/llvm-strip), and add -I/usr/include/x86_64-linux-gnu via
BPF2GO_CFLAGS so <asm/ptrace.h> resolves (the image symlinks
/usr/include/asm to asm-generic, which lacks ptrace.h).

Added docker to check-runner-tools for the check:gens-files matrix job,
since the vm-route-forge leg now requires it.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…-* branches

Add a release-* branch rule (CI_COMMIT_BRANCH =~ /^release-/) to the four
lint jobs that previously only had a 'main' rule:
  lint:yaml, lint:helm-templates, check:gens-files, lint:gitlab-ci.

This makes lint coverage on release-branch pipelines consistent with main
and with no-cyrillic/doc-changes/shellcheck/go, which already ran on
release-* branches. rules:changes semantics on branch pushes are
identical to main (compares against the previous SHA on the branch), so
mirroring the main rule is safe.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The deckhouse shell runner host has no node/npm installed, so the job
failed at check-runner-tools.sh. Run npm install + npm test inside the
official node:${NODE_VERSION} image via docker run, mirroring how
check:gens-files runs the vm-route-forge leg in a container. The repo is
bind-mounted at /src.

Add NODE_VERSION=24 to variables.yml, matching the GH workflow
test_scripts_js env.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…ollution

test:scripts:js ran 'docker run node:24 ... npm install' as root (default
uid). node_modules/ and package-lock.json were created root-owned in the
shared shell-executor workspace and not cleaned between jobs. The next
checkout (git clean/checkout) in gitleaks:diff could not remove them
('Permission denied'), failing 'Getting source from Git repository'
before the gitleaks script ever ran, so gitleaks.json was never produced
('no matching files' / 'Job failed: exit status 1').

Run npm under the host runner-user uid/gid (-u $(id -u):$(id -g)) with
HOME=/tmp and --cache /tmp/.npm so generated files are runner-user owned
and git can clean them on the next checkout.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…lution

Previous fix (-u runner-user) still left node_modules/package-lock.json in
the shared shell-executor workspace. The real issue is deeper: root-owned
leftovers from pre-fix runs already on the runner cannot be removed by
runner-user, so git clean on the NEXT job's 'Getting source from Git
repository' step fails with 'Permission denied' and breaks unrelated jobs
(show_dev_manifest, test:build:d8v-cli, gitleaks:diff, ...) before their
script runs.

Mount the repo READ-ONLY and copy the JS sources to an ephemeral tmpdir
inside the container where npm install/npm test run. node_modules and
package-lock.json now never touch the workspace at all, so no job can be
broken by leftover files regardless of who owned them.

One-time manual cleanup of existing root-owned leftovers on runner
H61TLxhnT is still required (sudo rm -rf .../virt-test/.gitlab/scripts/js/
{node_modules,package-lock.json}); no CI-only fix can remove root-owned
files because the checkout that would run before any cleanup script
already fails on them.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Collapse the five separate deploy_prod_alpha..rock_solid stages into one
deploy_prod stage and make the per-channel prod deploys independent
when:manual jobs (each needs:[build_prod] only) instead of a forced
alpha->beta->ea->stable->rock-solid promotion chain. This matches GitHub
release_module_release-channels.yml channel-pick semantics and removes a
carried-over artifact of the old root .gitlab-ci.yml.

The web Run-pipeline prod:deploy:* jobs (release-channels.yml) move from
the prod_deploy stage to the same deploy_prod stage, unifying both prod
deploy flows under one stage.

Drop the dead gitleaks stage (every active gitleaks job runs in scan).
The disabled upstream gitleaks_* override jobs get stage:scan so nothing
references the removed stage at config-parse time.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…deploy

The "local" prefix was uninformative and conceptually clashed with
`include: local:`. These are base templates meant to be extended by the
concrete build/deploy jobs, so `.base_build` / `.base_deploy` state intent.

Renames the two anchors (templates/build.yml, templates/deploy.yml) and all
20 `extends:` references across build-dev, build-prod, precache, svace,
release-channels, deploy-dev, deploy-prod, plus comments and includes.yml.
No behavior change: the single `build` stage stays (dev and release builds
are already separated by rules, never co-run in one pipeline).

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Regroup .gitlab/ci/templates by the two global processes plus shared base:
  base/    build.yml deploy.yml dual_registry_login.yml info.yml
  dev/     dev.yml dev_tags.yml main.yml release.yml dev_vars.yml
  release/ prod_always.yml prod_manual.yml prod_vars.yml

Only include: local: paths in includes.yml change. Anchor names are
unchanged (.base_build, .dev, .prod_vars, ...), so no job extends: edits
are needed. No rules/stage/behavior change.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Remove the migration-progress README that tracked the GitLab CI migration.
It was the source of TODO comments scattered across CI files; the migration
log now lives in the migration plan (tmp/ai-summary/gitlab-ci-migration-plan.md).

Clean up every reference to .gitlab/README.md in:
- .gitlab-ci.yml
- .gitlab/ci/variables.yml
- .gitlab/ci/templates/dev/dev_vars.yml
- .gitlab/ci/jobs/changelog.yml
- .gitlab/ci/jobs/manual-tools.yml
- .gitlab/ci/jobs/lint-dmt.yml
- .gitlab/ci/jobs/svace.yml

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Remove internal tracker issue IDs scattered in comments across
.gitlab/ci files so they do not leak into the public PR. No behavior change.

Affected files:
- .gitlab/ci/stages.yml
- .gitlab/ci/includes.yml
- .gitlab/ci/templates/release/prod_manual.yml
- .gitlab/ci/jobs/deploy-prod.yml
- .gitlab/ci/jobs/gitleaks.yml

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The GitHub test_scripts_{js,python} jobs ran full unit suites, but the
GitLab migration had degraded them to a JS smoke test and a Python
py_compile check (m9e.5.16). The original GH *.test.js / charts_test.py
all live under e2e/ (out of migration scope); the migrated scripts
(mrs_notifier.mjs, changelog_collect.py, check_changelog_entry.py) never
had upstream tests, so port = write real unit tests for them.

Python (.gitlab/ci/scripts/python/tests/, 44 tests, stdlib unittest):
- check_changelog_entry: block regex, parse_block, load_allowed_sections,
  validate_block (section/type/summary/impact_level rules incl. :low pin
  and the feature/fix-only ALLOWED_TYPES guard from 5.4).
- changelog_collect: next_link, parse_changes_block, has_label,
  group_entries, yaml_summary_scalar quoting, render_yaml (deckhouse
  schema, mr-iid ordering, :low strip, unsupported-type skip),
  render_markdown, minor_version_from_tag.
- test:scripts:python now runs py_compile + `unittest discover`, no
  longer allow_failure.

JS (mrs_notifier): export shouldNotifyMR (open-MR filter) and formatUser
as pure helpers; add unit tests for both (29 tests total). Drop the
stale "smoke test / cannot be imported" framing in the job comment.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Comment-only audit of .gitlab/** surfaced one internal contradiction and
three stale TODOs (no behavior change):

- stages.yml: the "Stage semantics" legend listed prod_check after
  build/scan/deploy_dev, contradicting both the actual `stages:` order
  (prod_check is declared before build) and its own "Runs BEFORE build"
  note. Reordered to match, and clarified that prod_check runs ONLY in the
  manual web release-channel flow (prod:check-requirements,
  CI_PIPELINE_SOURCE == web) — its early position is a DAG-ordering
  artifact so prod:build:* can `needs:` it, not a dev/MR-pipeline stage.

- backport.yml (x2), changelog.yml, manual-tools.yml: dropped the
  "TODO: webhook-listener" framing. Reactive webhook automation is an
  accepted permanent gap (no webhook-listener will be built); reworded
  accordingly, without citing a tracker id.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Three build/deploy parity fixes for the GitHub Actions -> GitLab CI
migration, found by reviewing .github/workflows against the new
.gitlab/ci/** files.

- Drop the DEV release-channel fan-out. deploy_for_dev_tag crane-copied a
  dev tag into alpha/beta/early-access/stable/rock-solid, but the DEV
  registry has no release channels, only tags. The GitHub "Deploy Dev"
  workflow is build-only. Remove deploy-dev.yml, its include, and the
  now-unused deploy_dev stage; dev tags stay built by build_dev_tags.

- Pass secondary_repo to prod builds. GitHub builds set
  secondary_repo=${DEV_MODULE_SOURCE}/${MODULE_NAME} so prod werf builds
  reuse already-built layers from the DEV registry. Add
  WERF_SECONDARY_REPO_1 to .dual_registry_login (a prod-only template),
  so it applies to build_prod and prod:build:* but never to dev builds.

- Use "main" as the main-branch module tag instead of v0.0.0-main, to
  match GitHub set_vars (MODULES_MODULE_TAG = ref_name = "main").

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…hangelog impact

Fix the functional bugs found while reviewing the GitHub Actions ->
GitLab CI migration (vs .github/workflows).

- cve-scan: the manual scan set RELEASE_IN_DEV=${SCAN_TAG:-false}, passing
  the tag string into a boolean. Derive it via rules instead, mirroring
  the GitHub `startsWith(tag || 'main', 'release-')` expression: a
  release-* SCAN_TAG sets "true", anything else keeps "false".

- svace: svace:notify reported status from CI_JOB_STATUS of the notify job
  itself (almost always success). Read the real svace:analyze status via
  the pipeline jobs API, and run notify on both success and failure with
  an on_success/on_failure rule pair (same idiom as prod:notify-loop).
  Drop GIT_STRATEGY: none so the api.sh helper is available.

- cleanup: restore the explicit WERF_DRY_RUN="false" from
  dev_registry-cleanup.yml, so an inherited WERF_DRY_RUN=true cannot turn
  cleanup into a silent no-op.

- changelog_collect.py: preserve the free-text `impact` migration note for
  high-impact entries (parse multi-line block values, emit `impact` after
  `pull_request`), and make CHANGELOG-<minor>.md cumulative across patch
  releases instead of overwriting it with only the current milestone.
  Add unit tests for all four behaviours.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The "avoid duplicate pipelines" comment sat above the default-branch rule,
which does not skip anything. The branch-pipeline skip is actually done by
the `push && $CI_OPEN_MERGE_REQUESTS -> when: never` rule. Move the
explanation onto that rule, and give the default-branch and tag rules their
own accurate comments.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Remove references to the internal planning document (section markers and
tmp/ paths) from comments across .gitlab/** and the root .gitlab-ci.yml,
and replace the absolute local checkout paths (/Users/...) with the
canonical upstream repo name (deckhouse/3p/deckhouse/modules-gitlab-ci).
Comments keep their substance; only the internal/local references are
dropped. No behavior change.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…g context

Two template cleanups, both behavior-preserving (same variables/rules emitted).

Registry login:
- Replace the misleadingly named .dual_registry_login (it only configured the
  DEV registry, not "two") with a single base/registry-login.yml that names
  each login explicitly: .login_dev_registry and .login_prod_registry (primary
  registry select), .login_prod_read_registry (read-only checks), and
  .also_login_dev_registry (the extra DEV login + werf secondary repo a prod
  build composes to also read DEV). This mirrors the GitHub pipeline, which
  logged into the prod and dev registries explicitly.
- .dev_vars / .prod_vars now extend the matching .login_*_registry, so the
  registry credentials live in one file and the vars bundles only add
  MODULES_MODULE_SOURCE + ENV. Move .prod_read_registry there as
  .login_prod_read_registry.

Prod tag context:
- prod_always.yml and prod_manual.yml were identical except the rule's
  `when:` (always vs manual). Merge them into prod_tag.yml with a shared
  .prod_tag base; .prod_always / .prod_manual now only carry their rule.

Anchor names used by jobs (.dev_vars, .prod_vars, .prod_always, .prod_manual)
are unchanged; only .dual_registry_login -> .also_login_dev_registry and
.prod_read_registry -> .login_prod_read_registry references were updated.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
- backport.yml: remove the scheduled "backport sweep" rule (Mode 3). It was
  beyond the GitHub workflow / migration scope and non-functional anyway
  (a `when: manual` job on a schedule pipeline is never triggered). Manual
  TARGET_BRANCH (Mode 1) and the status/backport label (Mode 2) remain the
  working backport paths. Drop its row from the SCHEDULE_TYPE table too.
- deploy-prod.yml: remove the "inputs not yet ported" TODO — it contradicted
  the very next paragraph; those inputs are implemented in the web flow in
  release-channels.yml.
- prod_tag.yml: demote the same "TODO" to a plain note (the design decision is
  made: tag-push uses the matrix, the input dispatch lives in release-channels).

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Pin the mrs_notifier JS test dependencies with a committed package-lock.json
and switch the test:scripts:js job from `npm install` to `npm ci` for
reproducible, lockfile-verified installs.

package-lock.json is ignored globally at the repo root, so a scoped
.gitlab/scripts/js/.gitignore re-includes this one. Verified locally:
`npm ci` + `npm test` pass (29 tests).

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
…release/mutating jobs

Centralize the cancel-in-progress behavior (GitHub concurrency equivalent):
- defaults.yml now sets `interruptible: true` for every job, so a new commit
  cancels the redundant in-flight pipeline once the project enables
  "Auto-cancel redundant pipelines". Drop the resolved TODO in workflow.yml.
- Remove the now-redundant per-job `interruptible: true` lines.
- Override `interruptible: false` where a run must not be cancelled mid-flight:
  prod release build/deploy (via .prod_vars) and the whole web release flow
  (via .prod_release_rules), plus state-mutating/long jobs: cleanup,
  changelog (both), backport, translate-changelog (already: precache, cve
  daily/manual, gitleaks full, svace build/analyze). build_prod drops its
  explicit false (inherited from .prod_vars).

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
The decision is to keep tracking the v13.0 branch (upstream fixes flow in
automatically). Replace the "pin to SHA" TODO in includes.yml with a plain
note that records the branch HEAD SHA to use if pinning is ever wanted.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Replace the leftover GitHub username default ("z9r5") with the GitLab handle
"gitlab-virt-bot" — the one reviewer kept as a real @-mention in the Loop MR
summary. Still overridable via the DOC_REVIEWER CI/CD variable. Removes the
last open TODO in the GitLab CI scripts.

Signed-off-by: Nikita Korolev <nikita.korolev@flant.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants