Changelog
All notable changes to this project will be documented here.
The format follows Keep a Changelog.
2026-10-29
Changed
- Slack messages for preview deploys, thread replies included, no longer carry the Release Notes attachment; staging and production messages still do
2026-10-27
Fixed
claude:scheduledfails with a message that says so when a schedule'sAGENT_SCHEDULED_PROMPTnames a variable without a value, such as$AGENT_PROMPT_MERGE, instead of failing with Claude's "Input must be provided", or running Claude on only the text after the name
2026-10-26
Breaking Changes
- The agent jobs ship no prompts: the texts of
AGENT_PROMPT_REVIEW,AGENT_PROMPT_WORK,AGENT_PROMPT_UPDATE,AGENT_PROMPT_AUDIT,AGENT_PROMPT_BACKLOG,AGENT_PROMPT_MERGEandAGENT_PROMPT_STATUSare removed, soclaude:reviewandclaude:workrun only when a group or project setsAGENT_PROMPT_REVIEWorAGENT_PROMPT_WORK, and a schedule that sets$AGENT_PROMPT_UPDATEfails until it names a prompt of its own, such as a command of its agent image
Added
- You can now run the agent jobs on an agent image of your own with
AGENT_CLAUDE_IMAGE, and keep the prompts there as Claude Code commands, such as/review - A scheduled run whose answer is only
NO_REPORTposts nothing to Slack, so a prompt can keep the runs that changed nothing out of the channel
2026-10-23
Added
- You can now set the name and icon that a Slack message shows as its sender, with
SLACK_MESSAGE_USERandSLACK_MESSAGE_USER_ICON_URL, when the Slack app has thechat:write.customizescope;SLACK_MESSAGE_USERis empty by default instead of the GitLab login, which it never sent
Changed
uninstall:previewalways posts its Slack message on its own in the channel, never as a reply in the branch's preview thread
2026-10-22
Breaking Changes
- The predefined prompts are named
AGENT_PROMPT_<name>:AGENT_PROMPT_REVIEW,AGENT_PROMPT_WORK,AGENT_PROMPT_UPDATE,AGENT_PROMPT_AUDITandAGENT_PROMPT_STATUSreplaceAGENT_REVIEW_PROMPTand its siblings; a schedule that setsAGENT_SCHEDULED_PROMPTto$AGENT_UPDATE_PROMPTnow fails until it says$AGENT_PROMPT_UPDATE yamllintalso runs in a project whose only YAML files end in.yml, such as a lone.gitlab-ci.yml; without a.yamllint, it uses yamllint's default config, which fails a line over 80 characters, so such a project adds a.yamllintor fixes its files- Preview releases are named
preview-<branch>instead of<branch>: a preview that is running when a project picks this up gets a second release with the same hostname on its next deploy, anduninstall:previewonly removes the new one, so stop open previews first or remove the old release withhelm uninstall <branch> --namespace preview-<project> claude:worktakes one prompt,AGENT_PROMPT_WORK, and rebases a conflicting branch itself;AGENT_WORK_IMPROVE_PROMPT, theAGENT_REBASE_*variables andAGENT_CLAUDE_REBASE_ALLOWED_TOOLSare removed- The agent jobs are named
<agent>:<task>:code:claudeisclaude:work,review:claudeisclaude:reviewandscheduled:claudeisclaude:scheduled, and the work job's variables areAGENT_WORK_*instead ofAGENT_CODE_*; a project that overrides one of these jobs or sets one of those variables renames it
Changed
claude:workfinishes only after the pipeline of its last push: it fixes a job its change broke and tests the preview environment, when there is one, the way a person would; its timeout is 60 minutes instead of 30, and the merge preset tests the preview the same way before it merges- The agents title their merge requests the way the project does, which may start with the issue number, instead of
Resolve "<issue title>", andclaude:workretitles a merge request that still has GitLab's default title - The update and audit presets name their branches after what they change, such as
update-inventree-1-6-1orfix-broken-links, without anupdate/oraudit/prefix, and follow the repository's own branch naming when it has one - The audit preset acts on what it finds instead of only reporting: it sweeps the repository, compares it with the reference repositories it checks out without ever changing them, opens a merge request per group of related fixes, asks questions as threads on those merge requests, files issues for bigger work, adds notes for ideas, and reports to Slack with the links (
$AGENT_PROMPT_AUDIT) claude:scheduledgets 2 hours instead of 1 before GitLab stops it, so a sweep that opens several merge requests finishes; the budget and turn caps still bound its costclaude:workworks on any branch: Claude finds the merge request, the issue (also from a branch name such as7-update-inventree), the unresolved threads and the failed jobs itself; the job runs automatically on a branch without changes, such as one an issue's Create merge request button creates, whose merge request GitLab gives no pipeline, and is a button in every other branch and merge request pipelineclaude:reviewwaits for a click, so a review only costs tokens when someone wants one; a group or project that setsAGENT_REVIEW_AUTOMATICto"true"gets a review on every push
Fixed
- A Helm diff job whose chart fails to render shows Helm's error in a few readable lines instead of after the chart's whole JSON schema, because
HELM_DIFF_ARGSno longer passes--debug yamllintalso runs when a merge request or branch changes a.ymlfile, such as.gitlab-ci.yml, so a merge request that only changes.gitlab-ci.ymlno longer ends with a skipped pipeline, which blocks merging where pipelines must succeed- A preview deploys for a branch whose name starts with a digit, such as one an issue's Create merge request button creates, because its Service name now starts with
preview-instead of the digit Kubernetes rejects - The update agent pushes the branch of a new merge request with
-o ci.skip, so a branch pipeline no longer runs every job next to the merge request pipeline
Added
- A daily schedule can work through the backlog: it picks the ready issue with the highest impact for the lowest effort, says why on the issue, and starts
claude:workon it with a draft merge request ($AGENT_PROMPT_BACKLOG) claude:workmarks a draft merge request ready once the work is about 80% done and no question waits for an answer, and asks what it can't decide in a thread, so a merge request with open questions stays a draftclaude:workmoves the issue on the project's board to the list for work in progress when it starts and to the list for review when it marks the merge request ready, when the board has such lists- A daily schedule can merge the agents' merge requests that need no person, such as typo fixes and minor updates with read release notes, and comment on the rest with what a person has to decide (
$AGENT_PROMPT_MERGE) claude:reviewreads the artifacts of the pipeline's earlier jobs, such as test reports and the Helm manifest diff, which GitLab already unpacks in its checkout
2026-10-21
Added
Pipelines
- An app whose Helm values files aren't in
kubernetes/helm, such as one app of a monorepo, can deploy from its own directory; the deploy rules and version commits follow it (HELM_VALUES_DIR) - Each agent job runs on a model and effort level that fit its work: Opus at high effort for reviews, code and rebases, Sonnet at high effort for scheduled runs, which a schedule can change with
AGENT_CLAUDE_MODELandAGENT_CLAUDE_EFFORT - Every project with the default pipeline gets the Claude agent jobs as soon as its group or project sets
CLAUDE_CODE_OAUTH_TOKENorANTHROPIC_API_KEY; without one, the jobs don't appear - Projects that include
pipelines/agents.yamlnext to another pipeline file get Claude agent jobs, which read and write GitLab themselves withglaband Git as their ownAGENT_GITLAB_AUTH_TOKEN, and cap every run by budget, turns and job timeout - A merge request gets a Claude code review on every push once the other jobs finish, with comments as threads on the lines they concern, code suggestions you can apply, and one summary note that each review updates (
review:claude) - An empty merge request created from an issue gets an implementation of that issue, written by Claude and pushed to its branch (
code:claude) - On a merge request with changes, playing
code:claudehas Claude work through the unresolved threads and the jobs its code made fail, and push the changes, so a developer can answer review comments without checking out the branch; the job replies on each thread it handled code:clauderuns adocker:dindservice, so Claude can run quick checks with tools the image lacks, such ashelm, in containers before it pushes- Commits from
code:claudecarry the name of the user who started the pipeline or played the job, with anAssisted-by: Claude Codetrailer, and its rebases record that user as committer - Playing
code:claudeon a merge request whose branch conflicts with its target first rebases the branch: Claude resolves each conflicted commit, and the job pushes it with--force-with-leasebefore Claude works through the threads - The agents read the repositories a group lists in
GIT_REPOSITORIES, such as its handbooks, and use the skills of the repositories inAGENT_SKILLS; each job has its own pair, such asAGENT_CODE_REPOSITORIES, socode:claudeor one schedule can get more context than the review - A pipeline schedule that sets
AGENT_SCHEDULED_PROMPTruns Claude on that prompt and posts the answer to Slack, so each project can schedule its own tasks; presets cover updates, which file asecurityissue for each advisory that affects a pinned version and open a merge request from it once a fix exists, forcode:claudeto implement, and open a merge request against the schedule's branch per pinned version with a newer stable release that has been out a week ($AGENT_UPDATE_PROMPT), technical audits ($AGENT_AUDIT_PROMPT) and team status updates ($AGENT_STATUS_PROMPT) (scheduled:claude)
Helpers
- The default stages gain an
agentsstage beforeextrafor the agent jobs; a project with its ownstages:list addsagentsto use them - Every Claude job attaches a report of each run's model, effort, turns, duration, cost and tokens, linked from the merge request, with the totals in the metrics widget on Premium, and the full transcript for project members (
.claude_report) - Any job can check out other repositories of the same GitLab instance with its job token (
.git_repositories,GIT_REPOSITORIES) - The job log shows each step Claude takes, one line per tool call, while it works
- Jobs can run Claude Code headless with budget, turn, permission and tool caps and a chosen model and effort level, on an image with a pinned Claude Code (
.claude,claude_run,AGENT_CLAUDE_MODEL,AGENT_CLAUDE_EFFORT)
Changed
Pipelines
- A preview deploys on its own in a child pipeline of a merge request pipeline too, where it was a manual job, so each app of a monorepo can run as a child pipeline
- Deploy messages name the app with
GITLAB_PROJECT_NAME, so each app of a monorepo can set its own name; the default is still the project title - Deploy messages no longer end in No changes or Version update only: a missing Configuration or Kubernetes attachment already shows that nothing changed there, and in a preview the note read as if the commits listed under Changes weren't changes
Helpers
- A project that includes
helpers/docker.yamlwithoutpipelines/docker.yamldefines theDOCKER_IMAGE_*names its jobs read, such asDOCKER_IMAGE_CACHE, itself
Fixed
Pipelines
- Helm deploys of a chart without an image of the project's own, such as cert-manager or sealed-secrets, no longer get
image.repository,image.tagandversionvalues: the image names,DOCKER_IMAGE_BRANCHamong them, come from the Docker pipeline instead of the Docker helper, which the agent jobs include for.docker
Helpers
- A
DOCKER_BUILD_TARGETSstage image carriesDOCKER_IMAGE_SUFFIXin its tag, so it matchesDOCKER_IMAGE_BUILD, and two variants of one project no longer overwrite each other's stage image - A chart from a Helm repository, such as
jetstack/cert-manager, deploys and diffs atHELM_CHART_VERSIONinstead of the repository's newest version
2026-10-20
Added
Pipelines
- Branches with hotfix in their name can deploy test, staging and production with a click, each on its own, besides their preview; production deploys through
production:hotfix, and the dry runs those deploys need run without a click (.hotfix:test,.hotfix:staging,.hotfix:production,.hotfix) - Version commits can go to another branch than the default one, for example
mainin a gitflow project (HELM_VALUES_COMMIT_BRANCH)
Changed
Pipelines
- The
helm:testandhelm:productiondry runs follow their deploy's rules, so they no longer run in scheduled pipelines - Version commits record every deploy except previews, also one from a hotfix branch, a merge request pipeline or a tag, so a hotfix deployed to production shows in its values file
- Deploy messages outside previews show the app URL beside the View app button, instead of the commit or merge request description;
SLACK_MESSAGE_TEXT_SUCCESSandSLACK_MESSAGE_TEXT_FAILUREstill replace it - The Commits section of deploy messages is called Changes
- Preview deploy messages read as one sentence: "deployment successful for version my-feature" instead of "deployment successful, version my-feature"; update any Slack filter that matches the old wording
- The Configuration attachment of deploy messages is grey on success too, instead of green; set
SLACK_MESSAGE_ATTACHMENTS_CONFIG_COLORto choose another color
Fixed
Pipelines
- Deploy messages from merge request pipelines list the branch's commits under Changes; GitLab sets
CI_COMMIT_BEFORE_SHAto the pipeline's own commit there, which left the list empty - The
helm:<environment>dry run waits for a deploy of the same release that is still running in an older pipeline, instead of failing with "another operation (install/upgrade/rollback) is in progress"; it shares the deploy's resource group - The deploy message's Kubernetes workload list shows the long-running pods only, so an old failed CronJob run no longer turns a successful deploy red; a failed hook job still fails the deploy and shows in the job logs
2026-10-19
Added
Docs
- The documentation site counts page views and clicks on outbound links with Plausible Analytics, which sets no cookies
- The Kubernetes pipeline page lists the three settings a group needs before its first deploy (chart access, cluster token, registry deploy token), with the error each missing setting causes
Pipelines
- Deploys can commit the image values they pass to Helm to the environment's values file on the default branch, so git shows which version runs where (
HELM_VALUES_COMMIT) - Projects can pass the image to Helm under other keys, for example as one
imagestring, by settingHELM_IMAGE_ARGS
Changed
Pipelines
- Slack deploy messages name the app first, so titles read "My App (production): Deployment successful" or "My App (production): Deployment failed" and preview messages read "My App (preview) deployment successful, version my-feature"; update any Slack filter or alert that matches the old wording
Fixed
Docs
- The cert-manager and F5 NGINX Ingress examples create their namespace on the first deploy: they set
HELM_ARGSon.deploy, where--create-namespacereaches Helm, instead of globally, where the job-levelHELM_ARGSof.helm:installoverrode it
Helpers
- The Helm values summary in the job log and the Slack message lists keys in the order of the chart's
values.yaml, as intended; the order lookup usedkeys_unsorted, which yq doesn't have, so the summary kept the diff's order
Pipelines
- The automatic rollback after a failed deploy and the
rollback:<environment>jobs no longer fail on a field that another field manager, such as an oldkubectl apply, last wrote; like the deploy, they apply server-side with--force-conflicts(HELM_ROLLBACK_ARGS) - A version commit that the group refuses because it allows Git over SSH only says so in the job log, instead of pointing at the job token setting
2026-10-16
Added
Helpers
- Every pushed image records the commit it was built from and its project URL as OCI annotations (
org.opencontainers.image.revision,org.opencontainers.image.source), whichdocker buildx imagetools inspect --rawand registries that read OCI annotations show
Changed
Helpers
- Helm deploys apply server-side with
--force-conflicts, so a field changed by hand withkubectlor written by another controller gets the chart's value on the next deploy instead of failing it; setHELM_ARGSon.deploywithout the flag to keep the old behavior - The Helm diff compares the chart against the live objects (
--three-way-merge), so it shows the manual changes a deploy reverts
Pipelines
- Deploys to test, staging, and production wait for a running deploy of the same environment instead of colliding with it on the Helm release, and each
rollback:<environment>job waits in the same queue
Fixed
Pipelines
- Preview deploys no longer fail with
release: already existswhen a branch pipeline and a merge request pipeline deploy the same branch at once;previewanduninstall:previewqueue per branch
2026-10-13
Breaking Changes
Pipelines
- The preview stop job is renamed from
preview:uninstalltouninstall:preview, matching the action-first names ofhelm:<environment>androllback:<environment>; move any override ofpreview:uninstallto the new name, since an override left on the old name becomes a separate job without ascriptand breaks pipeline creation
Added
Pipelines
- You can roll back test, staging, and production from the pipeline with the manual
rollback:test,rollback:staging, androllback:productionjobs, which printhelm historyand roll their deploy job's release back to the last successful revision before the live one, skipping failed revisions - You get a one-line Slack message in the deploy channel when a
rollback:<environment>job finishes, naming the environment and the revisions it rolled back from and to, or saying that the rollback failed
Docs
- Every page of the documentation site has a footer saying that GitLab Pipelines is not affiliated with, endorsed, sponsored, or approved by GitLab Inc.
Changed
Helpers
- The first
docker:imagejob on a new branch starts from the default branch's BuildKit registry cache (DOCKER_IMAGE_CACHE_DEFAULT) instead of rebuilding every layer - Images and their registry cache are pushed with zstd-compressed OCI layers, which inflate several times faster on pull than gzip; clusters need containerd 1.5 or later, or set
DOCKER_BUILD_COMPRESSION: gzip - Images are pushed as a plain single-platform manifest without a provenance attestation (
--provenance=false)
Pipelines
- Tag pipelines read and refresh the default branch's BuildKit cache instead of writing a cache image per tag
- Slack deploy messages no longer contain em-dashes: titles read "Deployment successful: My App (production)", the kubectl pipeline's Kubernetes header reads "Kubernetes: main", and preview thread replies separate the link with
·; update any Slack filter or alert that matches the old titles
Fixed
Helpers
- The branding link in Slack deploy messages works again:
SLACK_MESSAGE_BRANDINGnow defaults to "by gitlabpipelines.com", linking to https://gitlabpipelines.com, because gitlab.hosst.io no longer serves the docs - A diff job whose
helm upgrade --dry-runfails shows Helm's error in the job log and thehelm-dry-run.txtartifact again: under GitLab Runner'sset -eo pipefailthe failing pipe ended the script before the dump, so the log stopped at the command with no reason given
Pipelines
- Stopping a preview environment now uninstalls its release when a project moves previews to another namespace or release name through
PREVIEW_KUBERNETES_NAMESPACEandPREVIEW_HELM_RELEASE; the stop job ignored overrides ofKUBERNETES_NAMESPACEandHELM_RELEASEon.deploy:preview, reported "nothing to uninstall" and left the release running
2026-10-12
Fixed
Pipelines
- Deploys of a commit whose short SHA is all digits, such as
17716742, no longer fail the standard chart's schema check with "got number, want null or string"; the image tag and version now reach Helm as strings
2026-09-30
Breaking Changes
Pipelines
- Production deploys automatically on the default branch once the
testandstagingjobs pass instead of waiting for a click, while the gitflow pipeline keeps it manual on tags; setwhen: manualon.deploy:productionto keep the click
Fixed
Pipelines
- The gitflow pipeline deploys staging and production on tags, with production manual, instead of on the default branch like the continuous deployment pipeline; its overrides targeted the old
.deploy_*aliases, which no deploy job extends
2026-09-29
Changed
Pipelines
- You can read the commits straight in the rich Slack deploy message again (test, staging, production, and the
.applyequivalents): they sit under a bold Commits title right below the summary, where the text used to say "(see all changes below)". The Commits attachment andSLACK_MESSAGE_ATTACHMENTS_COMMITS_COLORare removed; the branch link and compare view it carried are still in the Version field and the Code changes button
Added
Pipelines
- You now get a Slack message when a preview environment is uninstalled, in the same channel as the preview deploy messages:
preview:uninstallreplies in the branch's preview thread while it is withinSLACK_THREAD_TTL_SECONDS, posts on its own otherwise, and reports a failed uninstall too. The next preview deploy of that branch starts a new thread
2026-09-16
Changed
Pipelines
- Slack deploy messages no longer send the status emoticon as
icon_emoji, so the Slack app keeps its own avatar - The status emoticon, including
:warning:and:danger:for a successful deploy that needs attention, shows only in preview thread replies; message titles keep their fixed success and failure emoticons - Setting
SLACK_MESSAGE_EMOTICONon a job still sets the bot icon
Helpers
- Slack messages omit
icon_emojifrom the payload whenSLACK_MESSAGE_EMOTICONis empty instead of sending an empty string
2026-08-20
Fixed
Helpers
- A failing
helm upgrade --dry-runin the diff jobs now prints its output in the job log and keeps it as thehelm-dry-run.txtartifact - The dry-run output goes to
/tmpwith stdout discarded, so until now a failure ended the job inside the collapsed Helm Values (new) section with only the command echoed: no error, no artifact
2026-08-19
Added
Pipelines
preview:uninstalljob tears down a preview release when its environment is stopped: manually, when the source branch's merge request merges or closes, or automatically afterPREVIEW_AUTO_STOPpreview:uninstallis wired to the preview deploy viaenvironment:on_stopand runshelm uninstallfor the branch release only; the shared preview namespace stays intactpreview:uninstallusesGIT_STRATEGY: none, so it still runs after the source branch is deletedpreview:uninstallrules mirror.deploy:previewon both pipeline types, which GitLab requires: a stop job that is absent from the pipeline that created the environment can never stop it
Changed
Pipelines
- The commits list in the rich Slack deploy message (test, staging, production, and the
.applyequivalents) moved out of the message body into its own Commits attachment, so it gets a colored bar and a header instead of running into the metadata fields above it - The Commits attachment leads the attachments on success and comes last on failure, where the job logs and rollback output are read first; it carries a context line linking the branch and the compare view
- Preview deployments keep their commits inline in the compact message:
SLACK_MESSAGE_ATTACHMENTS_COMMITSis empty there, and setting it empty on any job restores the old inline layout
2026-08-17
Changed
Pipelines
- Slack deploy messages for a successful deployment carry the Kubernetes pod list and Kubernetes Containers (logs) attachments only when a pod is in a failed state, a pod restarted more than five times, or the container logs hold a warning or error
- A healthy deploy's message holds the title, the configuration diff and the release notes
- The Kubernetes and Kubernetes Containers (logs) attachments are sent together, so the pod list can still be read against the logs
- A failed deployment still sends everything it collected
- The preview-only suppression is removed: it hid the pod list whenever preview pods looked healthy, and the container logs on every green preview, whatever either contained
2026-08-11
Fixed
Pipelines
- Deploy and apply jobs no longer run on scheduled pipelines
- A scheduled pipeline sets
CI_COMMIT_BRANCHlike a branch pipeline, so.deploy:test,.deploy:staging,.deploy:production,.apply:staging,.apply:productionand gitflow's.deploy_testmatched their default-branch rule and would have deployed the default branch, production included, on every scheduled run
Added
Pipelines
pre-commit:autoupdaterunspre-commit autoupdateon scheduled pipelines and fails when pinned hook revisions have fallen behind upstream, giving projects a place for the check other than a per-commit hook, which reaches the network on every commit and cannot work as alocalhook, since pre-commit invoking itself fails
2026-07-13
Changed
Pipelines
- Feature branches now run merge request pipelines when an MR is open and fall back to regular branch pipelines when no MR is active; the
workflow:rulesno longer disable merge request pipelines and now suppress the duplicate branch pipeline while an MR is open - Job
rulesthat previously guarded on$CI_PIPELINE_SOURCE != "merge_request_event"were reworked so quality, diff, and preview jobs run in merge request pipelines: preview deploys (.deploy:preview,.apply:preview) run automatically on merge request pipelines and remain manual on branch pipelines without an open MR - Long-lived branches (the default branch and
develop/main/master) never deploy to a preview environment, in both the merge request and branch pipeline paths - The default branch never switches to a merge request pipeline: it always keeps its branch pipeline, so gitflow's
developkeeps deploying totestwhile adevelop → mainMR is open
Helpers
.gitlab_merge_requestand.git_changes_summarynow resolve the merge request IID from$CI_MERGE_REQUEST_IID(set in merge request pipelines) before falling back to$CI_OPEN_MERGE_REQUESTS, so MR links and change summaries work in both pipeline types
2026-06-08
Added
Helpers
.slack_authverifiesSLACK_AUTHENTICATION_TOKENagainstauth.testin a collapsed job log section; prints HTTP status, parsed JSON response, andX-OAuth-Scopesheader (one scope per line, sorted); warns on auth failure without failing the job.slack_messagenow prints the Slack API response (was silently discarded)SLACK_THREAD_FILE(default empty): when set,.slack_messagereadsthread_tsfrom the file before posting to reply to an existing thread and writes the newtsbackSLACK_THREAD_TTL_SECONDS(default 28800, 8 h) starts a new thread whenSLACK_THREAD_FILEis older than the limit; set to0to never expireSLACK_MESSAGE_TEXT_REPLY(default empty): when set and posting as a thread reply, overridesSLACK_MESSAGE_TEXTfor that reply onlySLACK_MESSAGE_BLOCKS_REPLY(default empty): when set and posting as a thread reply, overridesSLACK_MESSAGE_BLOCKSfor that reply only
Pipelines
- The
after_scriptnow runs.slack_authbetween the GitLab env section and the Slack notification to surface token scopes and connectivity in the job log for debugging .deploy:previewand.apply:previewnow useSLACK_THREAD_FILE: .slack-thread-tswith a per-branch cache ($CI_PROJECT_ID-slack-thread-$CI_COMMIT_REF_SLUG) so repeated preview deploys on the same branch reply to the same Slack thread;SLACK_THREAD_TTL_SECONDSis set to14400(4 h) for preview; thread replies for successful re-deploys show only the commit list (SLACK_MESSAGE_BLOCKS_REPLY), dropping the deployment summary and branding; failed deploys post as a new top-level message and clear the thread so the next success starts freshPREVIEW_AUTO_STOPvariable (default7 days) configures how long before a preview environment is automatically stopped; accepts any GitLab duration string (e.g.30 days,never)
Changed
Pipelines
- Slack deploy message now shows pod health summary (
2/2 pods · 0 restarts) as a second line in the Kubernetes field; shows unhealthy status and total restart count when non-zero - Slack deploy message now includes the deployed image tag in the Version field as
· `tag`whenDOCKER_IMAGE_BRANCHis set - Slack deploy message no longer wraps No changes and Version update only in parentheses; preview deploys that only change the image tag now show Version update only instead of silently omitting the suffix
- Slack deploy message Roll back button now shows a confirmation dialog explaining that it opens the environment page, not an automated rollback
- Slack deploy message Job logs attachment context now includes a direct link to
helm-install.txtartifact alongside the job link - Slack deploy message success emoticon now overrides to
:warning:when max pod restarts > 5 and to:danger:when logs contain error keywords - The
after_scriptresource color logic now setsSLACK_COLOR_WARNINGwhen no error keywords are detected but any pod has more than 5 restarts - Slack deploy message Kubernetes Resources attachment renamed to Kubernetes; now queries pods and jobs directly via
kubectl get pods,jobs --selector app.kubernetes.io/instance=<release>instead of pipinghelm get manifest, and shows real pod status columns (NAME, READY, STATUS, RESTARTS, AGE) - Slack deploy message no longer shows the inline Kubernetes diff; diff is now accessible via three links in the Kubernetes attachment footer: colored workloads log, colored diff log, and
helm-kubernetes-dyff.txtartifact - Slack deploy message Kubernetes attachment default color changed from grey to blue (
SLACK_COLOR_INFO) - Slack deploy message attachment context lines now name the chart, release, and namespace explicitly: Configuration shows
Helm Chart <chart> · Release <release> in namespace <namespace>; Kubernetes showsContainers for release <release> in namespace <namespace>; Container Logs showsContainer logs for release <release> in namespace <namespace> - Slack deploy message Container Logs attachment prepends
:warning: WARNING: The container logs contain warningsabove the log block when the attachment color is orange - Slack deploy message attachment headers simplified: Configuration and Release Notes no longer include the branch name suffix
- Release Notes attachment now uses a root-level
markdownblock instead ofsection/mrkdwnso standard markdown (headings, bold, lists) renders correctly in Slack - Kubernetes apply Slack deploy message no longer wraps No changes in parentheses
Helpers
SLACK_THREAD_TTL_SECONDSdefault reduced from 86400 (24 h) to 28800 (8 h); redundant:-fallbacks removed since the variable always has a value from the defaults.slack_messagenow setsreply_broadcast: truewhen posting a thread reply on a failed job, so the failure is also visible in the main channel
Fixed
Helpers
.git_commitsnow exportsGITLAB_CODE_CHANGES_URLusing the computedGIT_COMMITS_FROM/GIT_COMMITS_TO; previously used the staticCI_COMMIT_BEFORE_SHAwhich is0000...000for scheduled/API-triggered pipelines, producing a broken compare URLGITLAB_ROLLBACK_URLnow points to the environment page ($CI_PROJECT_URL/-/environments/$CI_ENVIRONMENT_ID) instead of the pipelines list; the environment page lists deployments with a direct Re-deploy action
Docs
- Homepage feature cards now split Multi-environment strategy into Preview environments and Test / Staging / Production; all cards simplified and linked to relevant docs; summary paragraph added
- Pipelines sidebar reorganized into General / Build / Deploy / Programming sections
2026-06-04
Added
Helpers
.helm:diffnow generateshelm-plan.json(Terraform plan JSON) from rendered Kubernetes manifests; surfaced as a Terraform MR widget viaartifacts: reports: terraform:; each Kubernetes resource maps to oneresource_changeentry withcreate/update/delete/no-opactions; includesmode,provider_name, andafter_unknownfields for full Terraform plan schema compliance; prints a colored summary (+/~/-) to the collapsed job log sectionlog_env <pattern>prints matching env vars with the key in cyan bold and value in yellow; replaces allenv | grep "^PREFIX_" | sortcall sites- Global
before_scriptnow loads.gitlab_section_helpersso all helpers (section*,print_command*,log_*) are available in every job without explicit!reference HELM_VALUES_ALLuses computed (chart defaults + user) values in the diff summary when set; generateshelm-values-all.txtandhelm-values-summary-all.txtalongside the user-supplied equivalents
Pipelines
- Test suite extracts shell functions from YAML at runtime via
yq(awk fallback for local dev); split intotest_format_summary.shandtest_helm_plan.shorchestrated byrun_tests.sh; coversformat_summaryandhelm_planjq generation across first deploy, update, delete, noop, and mixed scenarios testsjob runstests/run_tests.shin theteststage on every pipeline using thecloud-toolbox/main:helmimagediff:stagingnow also runs on preview branches to give cross-environment diff visibility before merging to the default branch
Fixed
Helpers
format_summarynow skips dyff meta-blocks at indent 0 ((root level)headers and- N map/list entries removed/addedlines) that caused garbled output when top-level keys were structurally different between environments; any stalepoldaccumulated inside a skipped block is discarded before processing the next real path.helm:diffnow uses--namespace $HELM_NAMESPACEinstead of$HELM_RELEASE_ARGSforhelm get manifest; preview environments set--set nameOverride/fullnameOverrideinHELM_RELEASE_ARGSwhichhelm get manifestdoes not accept, causing it to fail silently and leavehelm-kubernetes-current.yamlempty so dyff always reported every resource as new.helm:diffHelm Values Summary awk parser now correctly handles dyff's output format: dotted paths likeimage.tag:are split into proper YAML hierarchy, change-type lines are skipped, and list index path components ([0]) are handled.helm:diffhelm-plan.jsonbefore/afterfields now contain onlykind,metadata.name,metadata.labels, andmetadata.annotationsinstead of the full Kubernetes manifest; full manifests caused GitLab's terraform MR widget to fail to render due to deeply nested spec objects
Pipelines
_kubectl_logsno longer redirects stderr with2>&1so kubectl output goes to the job log only and does not end up inkubernetes-logs.txtor the Slack attachment.slack_deploy_notificationnow changes the Slack icon to:danger:on success whenSLACK_MESSAGE_ATTACHMENTS_KUBERNETES_LOGS_COLORis not the default (i.e. logs contain warnings or errors)
Changed
Helpers
- Helper functions renamed for a consistent public API:
_section*→section*,run→print_command,run_pty→print_command_pty,_log_*→log_* .helm:diff_run_summary_awkrenamed toformat_summary;helm-template.txtartifact renamed tokubernetes-manifests.txt.kubernetes_stateremoved; resource capture moved into the Kubernetes Helm pipeline; artifact renamedkubernetes-state.txt→kubernetes-resources.txt; export renamedKUBERNETES_STATE_CONTENT→KUBERNETES_RESOURCES_CONTENT
Pipelines
- Resource capture (
helm get manifest | kubectl get, current +--previouslogs) is now inlined in deployscriptafter install, before rollback - Rollback failures now fail the job; kubernetes resources and logs included in Slack success notifications
SLACK_MESSAGE_ATTACHMENTS_KUBERNETES_*limit and color variables moved from helpers to pipeline
2026-06-02
Added
Helpers
.helm:installmixin provides generic Helm deploy using composable variables; output saved tohelm-install.txtartifact; usesset -o pipefailso failures propagate throughtee;expire_in: 30 days.helm:diffmixin extends.helm:installand runshelm diff; captures current/incoming values, computes values diff, rendershelm template;interruptible: true;expire_in: 7 days; skips Slack notifications;environment: action: prepare.helm_repository,.helm_values_args,.helm_values_current,.helm_values_new,.helm_chart_versionhelper mixins addedHELM_ACTION,HELM_ARGS,HELM_VALUES,HELM_FILES,HELM_EXTRA_ARGS,HELM_ARGS_SECRET,HELM_EXTRA_ARGS_SECRET,HELM_IMAGE_ARGS,HELM_RELEASE_ARGS,HELM_DIFF_OUTPUT,HELM_DIFF_CONTEXT,HELM_DIFF_ARGS,HELM_DIFF_SUMMARY_ARGSvariables added.kubectl_docker_registrymixin creates or updates an image pull secret in the target namespace before the Helm upgrade runs.gitlab_job_durationand.gitlab_pipeline_durationmixins addedSLACK_COLOR_*semantic color variables (DANGER,WARNING,SUCCESS,INFO,DEFAULT) added; per-attachmentSLACK_MESSAGE_ATTACHMENTS_*_LINESand*_COLORlimit variables;SLACK_MESSAGE_BLOCKS_SIMPLEvariantDOCKER_IMAGE_SUFFIXappended to every image tag to build variants from the same repo (e.g.-alpine); included inDOCKER_IMAGE_CACHEso parallel variant builds use separate caches
Pipelines
- New Kubernetes manifest pipeline deploys raw manifests via
kubectl apply; mirrors the Helm pipeline structure with preview/test/staging/production and diff jobs; configurable viaKUBERNETES_MANIFESTSandKUBECTL_ARGSvariables diff:preview,diff:test,diff:staging,diff:productionjobs now run at pipeline start (needs: [])HOSTNAME_PREVIEW,HOSTNAME_TEST,HOSTNAME_STAGING,HOSTNAME_PRODUCTIONvariables added.slack_deploy_notificationmixin assembles Slack attachments conditionally from available content (config diff, Kubernetes diff, release notes on success; job logs, rollback, state, container logs on failure)needs:on all deploy jobs now waits for the correspondingdiff:*job anddocker:image(optional: trueso pipelines without a build job are unaffected)
Docs
- cert-manager example shows deployment from the Jetstack Helm repository with version pinning,
--create-namespace, CRD management, and per-environment values - F5 NGINX Ingress Controller example shows deployment from an OCI registry with
HELM_REPOSITORY: oci://...and automaticHELM_CHARTresolution - Docker helper now includes an Image variants section with parallel build example
- Kubernetes pipeline now includes an examples section with public Helm chart and OCI chart walkthroughs
Changed
Helpers
DOCKER_IMAGE_NAMErenamed toDOCKER_IMAGE_REPOSITORY; variables grouped by concern.git_changes_summaryMR lookup now uses|| trueto prevent job failure when no MR matches.git_release_notesnow initializes to empty; for tag pipelines falls back to the matching CHANGELOG section; for branch pipelines extracts only lines added to CHANGELOG.md in the current range; output truncated to 2900 charactersHELM_REPOSITORY_GITandHELM_REPOSITORY_URLmerged intoHELM_REPOSITORY, auto-detected:oci://→helm pull --untar;.git/git@→git clone; other URL →helm repo add; empty → skippedHELM_REPOSITORY_NAMEis now required for plain Helm repos: an empty value causes a hard failure, preventing a silenthelm repo add ""HELM_CHART_VERSIONdefault changed to"": git clone uses the default branch, OCI pull gets latestHELM_REPOSITORY_USERfixed togitlab-ci-token(was$CI_JOB_USER, not a valid GitLab CI variable)HELM_EXPERIMENTAL_OCIremoved; OCI support is enabled by default since Helm 3.8HELM_VALUESdefault changed to"": avoids a silent failure whenvalues.yamldoes not existHELM_VALUES_ARGSandHELM_FILES_ARGSremoved fromvariables:, computed by.helm_values_args; pre-setting them skips the automatic expansion ofHELM_VALUES/HELM_FILES- Kubernetes helper image changed to
cloud-toolbox:kubectl .kubectl_docker_registrynow skips registry secret creation whenKUBERNETES_DOCKER_REGISTRY_PASSWORDis not set- Slack helper image changed from
curlimages/curl:latesttocloud-toolbox:base; attachment content truncated to 2900 characters to stay within Slack's 3000 character block limit
Pipelines
pre-commitandyamllintnow setinterruptible: truehadolintanddocker:imagenow setinterruptible: true;hadolintartifact expires in 7 days.deploynow extends.helm:install, usesk8simage, and setsdependencies: [];after_scriptrestores cluster auth, captures state and logs, and runshelm rollbackon failure; deploy artifacts expire in 30 days- Preview deploy now sets
nameOverrideto project name; ingress host simplified to--set ingress.hosts[0]=$HOSTNAME
2026-05-21
Added
- Extra default stage named
extraadded
Changed
- Helm helper now uses
cloud-toolbox:helminstead ofcloud-toolbox:latest(172 MB vs 1.05 GB) - Kubernetes helper now uses
cloud-toolbox:ciinstead ofcloud-toolbox:latest(279 MB vs 1.05 GB) - Google helper now uses
cloud-toolbox:gcloudinstead ofcloud-toolbox:latest(863 MB vs 1.05 GB) - GitLab helper now uses
cloud-toolbox:baseinstead ofcloud-toolbox:latest(50.8 MB vs 1.05 GB)
2026-05-15
Fixed
.gitlab_messagenow usesAuthorization: Bearerheader instead ofPRIVATE-TOKEN, making it compatible with the defaultCI_JOB_TOKEN.git_release_notesCHANGELOG fallback now guards against unsetGIT_COMMITS_FROM/GIT_COMMITS_TOwhen.git_commitsis not in the chain
2026-05-01
Added
- Release notes are now resolved automatically from the GitLab release description, tag message, or CHANGELOG.md
- Failed deployments now include the stderr job log in the Slack notification
- Successful deployments now include release notes in the Slack notification
2026-04-29
Added
- GitFlow pipeline:
testenvironment deploys automatically from the default branch;stagingandproductiondeploy on tag push - Slack helper for deployment notifications with success, failure, and warning message templates
- GitLab helper for posting merge request notes and creating releases
- Google Cloud helper for authentication and project setup
- Sentry helper for release tracking and error reporting integration
- HTTP helper for generic HTTP request jobs
- Documentation site covering all pipelines and helpers
Changed
- Preview deployments now trigger automatically when a merge request is open, and fall back to manual otherwise
- Preview deployments now trigger on feature branch pushes instead of merge request events
- The
testenvironment has been renamed tostaging - The
testspipeline stage has been renamed totest
2025-11-11
Added
- Kubernetes/Helm deployment pipeline with preview, test, staging, and production environments
- DigitalOcean helper for
doctlauthentication and Kubernetes cluster setup - Helm helper for deploying charts from a GitLab Helm registry
- Kubernetes helper with
kubectljobs and Docker registry secret management - Docker buildx support for multi-platform and multi-stage builds
- Docker variables and base jobs extracted into a standalone helper
Changed
- Gitflow helper renamed to
git.yaml
2024-07-07
Added
pre-commitjob runs pre-commit hooks automatically in the quality stageyamllintjob for YAML linting in the quality stage- Default pipeline stages defined:
quality,build,test,publish,deploy,release hadolintreport output is now configurable with custom args, ignore rules, and report path
2024-07-02
Added
- Docker build pipeline with GitLab registry integration, layer caching, and optional multi-stage build support
- GitFlow helper with rules scoping jobs to merge requests, tags, and the default branch