Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package werf for openSUSE:Factory checked in at 2026-07-15 16:50:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/werf (Old) and /work/SRC/openSUSE:Factory/.werf.new.1991 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "werf" Wed Jul 15 16:50:01 2026 rev:78 rq:1365798 version:2.73.1 Changes: -------- --- /work/SRC/openSUSE:Factory/werf/werf.changes 2026-07-02 20:15:57.810890279 +0200 +++ /work/SRC/openSUSE:Factory/.werf.new.1991/werf.changes 2026-07-15 17:05:18.462669731 +0200 @@ -1,0 +2,15 @@ +Wed Jul 15 04:50:05 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 2.73.1: + * Bug Fixes + - build: useUUID-based naming for scratch base images to + prevent buildah misinterpretation (#7602) (9ce7545) +- Update to version 2.73.0: + * Features + - deploy: move dockerconfigjson to .global.werf (#7583) + (79d90cb) + * Bug Fixes + - build, buildah, dockerfile, staged: resolve staged Dockerfile + RUN --mount from=<stage> to built image (#7594) (b1933b3) + +------------------------------------------------------------------- Old: ---- werf-2.72.2.obscpio New: ---- werf-2.73.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ werf.spec ++++++ --- /var/tmp/diff_new_pack.wFbWLL/_old 2026-07-15 17:05:43.423519933 +0200 +++ /var/tmp/diff_new_pack.wFbWLL/_new 2026-07-15 17:05:43.427520070 +0200 @@ -17,7 +17,7 @@ Name: werf -Version: 2.72.2 +Version: 2.73.1 Release: 0 Summary: CLI for the Werf CI/CD system License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.wFbWLL/_old 2026-07-15 17:05:43.467521438 +0200 +++ /var/tmp/diff_new_pack.wFbWLL/_new 2026-07-15 17:05:43.471521574 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/werf/werf.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">refs/tags/v2.72.2</param> + <param name="revision">refs/tags/v2.73.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.wFbWLL/_old 2026-07-15 17:05:43.499522532 +0200 +++ /var/tmp/diff_new_pack.wFbWLL/_new 2026-07-15 17:05:43.503522669 +0200 @@ -3,6 +3,6 @@ <param name="url">https://github.com/werf/werf</param> <param name="changesrevision">508fb9aee29baca228674ba7a3d2d4fa1f5844d5</param></service><service name="tar_scm"> <param name="url">https://github.com/werf/werf.git</param> - <param name="changesrevision">e5cc40533ad562ef3cddec21bb444bf44cdf6501</param></service></servicedata> + <param name="changesrevision">122c59efc52769e6aab7d1637ff241367f2bf476</param></service></servicedata> (No newline at EOF) ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/werf/vendor.tar.gz /work/SRC/openSUSE:Factory/.werf.new.1991/vendor.tar.gz differ: char 143, line 1 ++++++ werf-2.72.2.obscpio -> werf-2.73.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/.agents/skills/review-multi/SKILL.md new/werf-2.73.1/.agents/skills/review-multi/SKILL.md --- old/werf-2.72.2/.agents/skills/review-multi/SKILL.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/.agents/skills/review-multi/SKILL.md 2026-06-26 10:48:33.000000000 +0200 @@ -29,16 +29,18 @@ 1. **DoD first.** Ask user for numbered acceptance criteria. Block until received. Nothing proceeds without DoD. Record the criteria — they will be passed inline to every sub-skill. 2. **Get branch name:** `git rev-parse --abbrev-ref HEAD` → `$BRANCH`. Create safe directory name: `$SAFE_BRANCH=$(echo "$BRANCH" | sed 's|/|-|g')`. Create directory `reviews/$SAFE_BRANCH/`. -3. **Save diff to file:** `git --no-pager diff main...HEAD > reviews/$SAFE_BRANCH/pr_diff.txt` — read via `read_file` with `start_line`/`end_line`. Avoids terminal truncation. +3. **Save diff to file:** `git --no-pager diff origin/main...HEAD > reviews/$SAFE_BRANCH/pr_diff.txt`. Avoids terminal truncation. 4. **Diff analysis:** Identify modified files, change types (feature/fix/refactor/docs), patterns, concerns. 5. **Deep analysis:** Read changed files and their consumers. Examine key functions and their callers in the codebase. -6. **Read diff for sub-skills:** Use `read_file(path="reviews/$SAFE_BRANCH/pr_diff.txt")` to get the full diff content. It will be passed inline to every sub-skill. -7. **Phase 1a — Technical Reviewer (parallel).** Activate **review-tech**. Provide: the full diff content inline, the DoD criteria inline, analysis. +6. **Read diff for sub-skills (MANDATORY):** Use `read_file(path="reviews/$SAFE_BRANCH/pr_diff.txt")` to get the full diff content. + - If read_file returns the full text → include the COMPLETE diff inline in every spawn_agent message. + - If read_file returns an outline/truncation (file too large) → output `ERROR: Diff too large for review-multi workflow.` and STOP. Do NOT split, summarize, or pass a file path. +7. **Phase 1a — Technical Reviewer (parallel).** Activate **review-tech**. Provide: the COMPLETE diff content inline (NOT a file path or summary), the DoD criteria inline, analysis. → **Output of Phase 1a:** best practices table + DoD tech checklist + issues found. -8. **Phase 1b — Product Reviewer (parallel with 1a).** Activate **review-product**. Provide: the full diff content inline, the DoD criteria inline, analysis. +8. **Phase 1b — Product Reviewer (parallel with 1a).** Activate **review-product**. Provide: the COMPLETE diff content inline (NOT a file path or summary), the DoD criteria inline, analysis. → **Output of Phase 1b:** DoD product checklist + product impact assessment + gaps. → **Wait for BOTH Phase 1a and Phase 1b to complete before proceeding.** -9. **Phase 2 — Risk Analyst.** Activate **review-risk**. Provide: the full diff content inline, the DoD criteria inline, analysis, AND full outputs from Phase 1a + Phase 1b. +9. **Phase 2 — Risk Analyst.** Activate **review-risk**. Provide: the COMPLETE diff content inline (NOT a file path or summary), the DoD criteria inline, analysis, AND full outputs from Phase 1a + Phase 1b. → **Output of Phase 2:** risk analysis table with numbered rows. 10. **Phase 3 — Final report.** Assemble combined report (format below). Save to `reviews/$SAFE_BRANCH/REPORT.md`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/.agents/skills/review-product/SKILL.md new/werf-2.73.1/.agents/skills/review-product/SKILL.md --- old/werf-2.72.2/.agents/skills/review-product/SKILL.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/.agents/skills/review-product/SKILL.md 2026-06-26 10:48:33.000000000 +0200 @@ -22,7 +22,8 @@ 3. Be concrete — no vague statements. 4. NEVER sugarcoat. Deliver honest, fact-based critiques. 5. First message opens with the full role declaration above. -6. The full diff is provided to you inline. Do NOT run `git diff` yourself. +6. **MANDATORY:** The full diff is provided to you inline. Do NOT read it from a file or run `git diff` yourself. + - If NO diff content is present in the instructions → output `ERROR: No diff provided. Cannot perform review.` and STOP immediately. Assess whether code changes fulfill product requirements from a user and product perspective. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/.agents/skills/review-risk/SKILL.md new/werf-2.73.1/.agents/skills/review-risk/SKILL.md --- old/werf-2.72.2/.agents/skills/review-risk/SKILL.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/.agents/skills/review-risk/SKILL.md 2026-06-26 10:48:33.000000000 +0200 @@ -22,7 +22,8 @@ 3. Be realistic about probability and severity — do not inflate. 4. NEVER sugarcoat. Base risks only on evidence. 5. First message opens with the full role declaration above. -6. The full diff is provided to you inline. Do NOT run `git diff` yourself. +6. **MANDATORY:** The full diff is provided to you inline. Do NOT read it from a file or run `git diff` yourself. + - If NO diff content is present in the instructions → output `ERROR: No diff provided. Cannot perform review.` and STOP immediately. Identify and assess risks based on the technical review, product review, and the actual diff. The output is a single table. No prose summary. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/.agents/skills/review-tech/SKILL.md new/werf-2.73.1/.agents/skills/review-tech/SKILL.md --- old/werf-2.72.2/.agents/skills/review-tech/SKILL.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/.agents/skills/review-tech/SKILL.md 2026-06-26 10:48:33.000000000 +0200 @@ -22,7 +22,8 @@ 3. Be concrete — no vague generalizations. 4. NEVER sugarcoat. Deliver honest, fact-based critiques. 5. First message opens with the full role declaration above. -6. The full diff is provided to you inline. Do NOT run `git diff` yourself. +6. **MANDATORY:** The full diff is provided to you inline. Do NOT read it from a file or run `git diff` yourself. + - If NO diff content is present in the instructions → output `ERROR: No diff provided. Cannot perform review.` and STOP immediately. Review code changes for quality, architecture, and best practices. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/CHANGELOG.md new/werf-2.73.1/CHANGELOG.md --- old/werf-2.72.2/CHANGELOG.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/CHANGELOG.md 2026-06-26 10:48:33.000000000 +0200 @@ -1,5 +1,24 @@ # Changelog +## [2.73.1](https://github.com/werf/werf/compare/v2.73.0...v2.73.1) (2026-06-26) + + +### Bug Fixes + +* **build:** use UUID-based naming for scratch base images to prevent buildah misinterpretation ([#7602](https://github.com/werf/werf/issues/7602)) ([9ce7545](https://github.com/werf/werf/commit/9ce7545582c59de01789d72c6f56bdf13b1e6a22)) + +## [2.73.0](https://github.com/werf/werf/compare/v2.72.2...v2.73.0) (2026-06-23) + + +### Features + +* **deploy:** move `dockerconfigjson` to .global.werf ([#7583](https://github.com/werf/werf/issues/7583)) ([79d90cb](https://github.com/werf/werf/commit/79d90cb69f563a2ec7b109de5481c4eba45f9722)) + + +### Bug Fixes + +* **build, buildah, dockerfile, staged:** resolve staged Dockerfile RUN --mount from=<stage> to built image ([#7594](https://github.com/werf/werf/issues/7594)) ([b1933b3](https://github.com/werf/werf/commit/b1933b36118fb36a5bab847a93c56bc9196c13b1)) + ## [2.72.2](https://github.com/werf/werf/compare/v2.72.1...v2.72.2) (2026-06-18) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/Taskfile.dist.yaml new/werf-2.73.1/Taskfile.dist.yaml --- old/werf-2.72.2/Taskfile.dist.yaml 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/Taskfile.dist.yaml 2026-06-26 10:48:33.000000000 +0200 @@ -27,7 +27,7 @@ devBinary: './bin/werf{{if (eq .targetOS "windows")}}.exe{{end}}' withCoverageBinary: './bin/werf-with-coverage{{if (eq .targetOS "windows")}}.exe{{end}}' package: "github.com/werf/werf/v2/cmd/werf" - kubeVersion: '{{.kubeVersion | default "1.33.1"}}' + kubeVersion: '{{.kubeVersion | default "1.36.1"}}' goTags: "dfrunsecurity dfrunnetwork dfrunmount dfssh containers_image_openpgp" goLDFlags: "-s -w -X github.com/werf/werf/v2/pkg/werf.Version={{.version}}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/cmd/werf/common/common.go new/werf-2.73.1/cmd/werf/common/common.go --- old/werf-2.72.2/cmd/werf/common/common.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/cmd/werf/common/common.go 2026-06-26 10:48:33.000000000 +0200 @@ -75,7 +75,7 @@ func SetupSetDockerConfigJsonValue(cmdData *CmdData, cmd *cobra.Command) { cmdData.SetDockerConfigJsonValue = new(bool) - cmd.Flags().BoolVarP(cmdData.SetDockerConfigJsonValue, "set-docker-config-json-value", "", util.GetBoolEnvironmentDefaultFalse("WERF_SET_DOCKER_CONFIG_JSON_VALUE"), "Shortcut to set current docker config into the .Values.dockerconfigjson") + cmd.Flags().BoolVarP(cmdData.SetDockerConfigJsonValue, "set-docker-config-json-value", "", util.GetBoolEnvironmentDefaultFalse("WERF_SET_DOCKER_CONFIG_JSON_VALUE"), "Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson") } func SetupGitWorkTree(cmdData *CmdData, cmd *cobra.Command) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_bundle_apply.md new/werf-2.73.1/docs/_includes/reference/cli/werf_bundle_apply.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_bundle_apply.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_bundle_apply.md 2026-06-26 10:48:33.000000000 +0200 @@ -262,7 +262,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_bundle_plan.md new/werf-2.73.1/docs/_includes/reference/cli/werf_bundle_plan.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_bundle_plan.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_bundle_plan.md 2026-06-26 10:48:33.000000000 +0200 @@ -240,7 +240,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_bundle_render.md new/werf-2.73.1/docs/_includes/reference/cli/werf_bundle_render.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_bundle_render.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_bundle_render.md 2026-06-26 10:48:33.000000000 +0200 @@ -227,7 +227,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_converge.md new/werf-2.73.1/docs/_includes/reference/cli/werf_converge.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_converge.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_converge.md 2026-06-26 10:48:33.000000000 +0200 @@ -440,7 +440,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_helm_get_autogenerated_values.md new/werf-2.73.1/docs/_includes/reference/cli/werf_helm_get_autogenerated_values.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_helm_get_autogenerated_values.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_helm_get_autogenerated_values.md 2026-06-26 10:48:33.000000000 +0200 @@ -204,7 +204,7 @@ Also, can be specified with $WERF_SECONDARY_REPO_* (e.g. $WERF_SECONDARY_REPO_1=..., $WERF_SECONDARY_REPO_2=...) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --skip-tls-verify-registry=false Skip TLS certificate validation when accessing a registry (default $WERF_SKIP_TLS_VERIFY_REGISTRY) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_lint.md new/werf-2.73.1/docs/_includes/reference/cli/werf_lint.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_lint.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_lint.md 2026-06-26 10:48:33.000000000 +0200 @@ -348,7 +348,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_plan.md new/werf-2.73.1/docs/_includes/reference/cli/werf_plan.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_plan.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_plan.md 2026-06-26 10:48:33.000000000 +0200 @@ -420,7 +420,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/_includes/reference/cli/werf_render.md new/werf-2.73.1/docs/_includes/reference/cli/werf_render.md --- old/werf-2.72.2/docs/_includes/reference/cli/werf_render.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/_includes/reference/cli/werf_render.md 2026-06-26 10:48:33.000000000 +0200 @@ -341,7 +341,7 @@ Also, can be defined with $WERF_SET_* (e.g. $WERF_SET_1=key1=val1, $WERF_SET_2=key2=val2) --set-docker-config-json-value=false - Shortcut to set current docker config into the .Values.dockerconfigjson + Shortcut to set current docker config into the .Values.global.werf.dockerconfigjson --set-file=[] Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/pages_en/usage/cleanup/cr_cleanup.md new/werf-2.73.1/docs/pages_en/usage/cleanup/cr_cleanup.md --- old/werf-2.72.2/docs/pages_en/usage/cleanup/cr_cleanup.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/pages_en/usage/cleanup/cr_cleanup.md 2026-06-26 10:48:33.000000000 +0200 @@ -174,7 +174,7 @@ By default, werf uses the [_Docker Registry API_](https://docs.docker.com/registry/spec/api/) for deleting tags. The user must be authenticated and have a sufficient set of permissions. If the _Docker Registry API_ isn't supported and tags are deleted using the native API, then some additional container registry-specific actions are required on the user's part. | | | -|-----------------------------|:---------------------------:| +| --------------------------- | :-------------------------: | | _AWS ECR_ | [***ok**](#aws-ecr) | | _Azure CR_ | [***ok**](#azure-cr) | | _Default_ | **ok** | @@ -238,7 +238,9 @@ werf uses the _GitLab container registry API_ or _Docker Registry API_ (depending on the GitLab version) to delete tags. -> The privileges of the temporary CI job token ($CI_JOB_TOKEN) are not sufficient to delete tags. Therefore, the user must create a dedicated token in the Access Token section, select api in the Scope section, and ensure the role of Maintainer or Owner is assigned before using it for authorization +> You can use the temporary CI job token (`$CI_JOB_TOKEN`) to delete tags if the user who started the job has sufficient permissions in the project and the project Job token permissions allow the required access. +> +> If these conditions are not met (for example, because of cross-project restrictions or an insufficient role), use a dedicated Project/Personal Access Token with the `api` scope. ## Saving the result of work diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/docs/pages_ru/usage/cleanup/cr_cleanup.md new/werf-2.73.1/docs/pages_ru/usage/cleanup/cr_cleanup.md --- old/werf-2.72.2/docs/pages_ru/usage/cleanup/cr_cleanup.md 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/docs/pages_ru/usage/cleanup/cr_cleanup.md 2026-06-26 10:48:33.000000000 +0200 @@ -174,7 +174,7 @@ По умолчанию при удалении тегов werf использует [_Docker Registry API_](https://docs.docker.com/registry/spec/api/) и от пользователя требуется только авторизация с использованием доступов с достаточным набором прав. Если же удаление посредством _Docker Registry API_ не поддерживается и оно реализуется в нативном API container registry, то от пользователя могут потребоваться специфичные для используемого container registry действия. | | | -|-----------------------------|:---------------------------:| +| --------------------------- | :-------------------------: | | _AWS ECR_ | [***ок**](#aws-ecr) | | _Azure CR_ | [***ок**](#azure-cr) | | _Default_ | **ок** | @@ -237,7 +237,9 @@ При удалении тегов werf использует _GitLab container registry API_ или _Docker Registry API_ в зависимости от версии GitLab. -> Прав временного токена CI-задания ($CI_JOB_TOKEN) недостаточно для удаления тегов, поэтому пользователю необходимо создать специальный токен в разделе Access Token, выбрать api в секции Scope и назначить роль Maintainer или Owner перед использованием его для авторизации +> Для удаления тегов можно использовать временный токен CI-задания (`$CI_JOB_TOKEN`), если пользователь, запустивший задание, имеет достаточные права в проекте, а настройки Job token permissions разрешают требуемый доступ. +> +> Если эти условия не выполняются (например, из-за ограничений межпроектного доступа или недостаточной роли), используйте отдельный Project/Personal Access Token со scope `api`. ## Сохранение результата работы diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/build/image/image.go new/werf-2.73.1/pkg/build/image/image.go --- old/werf-2.72.2/pkg/build/image/image.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/build/image/image.go 2026-06-26 10:48:33.000000000 +0200 @@ -6,6 +6,7 @@ "strings" "time" + "github.com/google/uuid" "github.com/gookit/color" "github.com/werf/logboek" @@ -297,7 +298,11 @@ } // TODO: do not use container_backend.LegacyStageImage for base image. - i.baseStageImage = i.Conveyor.GetOrCreateStageImage(i.baseImageReference, nil, nil, i) + stageImageName := i.baseImageReference + if i.baseImageReference == "scratch" { + stageImageName = fmt.Sprintf("werf-scratch-%s", uuid.New().String()) + } + i.baseStageImage = i.Conveyor.GetOrCreateStageImage(stageImageName, nil, nil, i) // Do not override the base image description if it is already set. // TODO: It might be a stage as base image (passed as dependency), and the absence of StageID in the description will lead to breaking the logic. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/build/image/stapel.go new/werf-2.73.1/pkg/build/image/stapel.go --- old/werf-2.72.2/pkg/build/image/stapel.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/build/image/stapel.go 2026-06-26 10:48:33.000000000 +0200 @@ -236,6 +236,9 @@ if err != nil { return nil, fmt.Errorf("unable to open remote git repo %s by url %s: %w", remoteGitMappingConfig.Name, remoteGitMappingConfig.Url, err) } + remoteGitRepo.Branch = remoteGitMappingConfig.Branch + remoteGitRepo.Tag = remoteGitMappingConfig.Tag + remoteGitRepo.Commit = remoteGitMappingConfig.Commit if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Refreshing %s repository", remoteGitMappingConfig.Name)). DoError(func() error { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/build/stage/instruction/export_test.go new/werf-2.73.1/pkg/build/stage/instruction/export_test.go --- old/werf-2.72.2/pkg/build/stage/instruction/export_test.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/build/stage/instruction/export_test.go 2026-06-26 10:48:33.000000000 +0200 @@ -23,3 +23,7 @@ func ExportStopSignalCommands(stg *StopSignal) (backend, source instructions.StopSignalCommand) { return stg.backendInstruction.StopSignalCommand, *stg.instruction.Data } + +func ExportRunMounts(stg *Run) []*instructions.Mount { + return stg.backendInstruction.GetMounts() +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/build/stage/instruction/run.go new/werf-2.73.1/pkg/build/stage/instruction/run.go --- old/werf-2.72.2/pkg/build/stage/instruction/run.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/build/stage/instruction/run.go 2026-06-26 10:48:33.000000000 +0200 @@ -33,6 +33,16 @@ } // Setup RUN envs after 2nd stage expansion stg.backendInstruction.Envs = EnvToSortedArr(stg.GetExpandedEnv(c)) + + for _, mnt := range instructions.GetMounts(stg.instruction.Data) { + if mnt.From == "" { + continue + } + if ds := stg.instruction.GetDependencyByStageRef(mnt.From); ds != nil { + mnt.From = c.GetImageNameForLastImageStage(stg.TargetPlatform(), ds.GetWerfImageName()) + } + } + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/build/stage/instruction/run_ai_test.go new/werf-2.73.1/pkg/build/stage/instruction/run_ai_test.go --- old/werf-2.72.2/pkg/build/stage/instruction/run_ai_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/werf-2.73.1/pkg/build/stage/instruction/run_ai_test.go 2026-06-26 10:48:33.000000000 +0200 @@ -0,0 +1,111 @@ +package instruction_test + +import ( + "bytes" + "fmt" + + "github.com/moby/buildkit/frontend/dockerfile/instructions" + "github.com/moby/buildkit/frontend/dockerfile/parser" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/werf/werf/v2/pkg/build/stage" + "github.com/werf/werf/v2/pkg/build/stage/instruction" +) + +func parseRunCommandAI(dockerfileText string) *instructions.RunCommand { + p, err := parser.Parse(bytes.NewReader([]byte(dockerfileText))) + Expect(err).To(Succeed()) + + dockerStages, _, err := instructions.Parse(p.AST) + Expect(err).To(Succeed()) + Expect(dockerStages).NotTo(BeEmpty()) + + for _, cmd := range dockerStages[len(dockerStages)-1].Commands { + if run, ok := cmd.(*instructions.RunCommand); ok { + return run + } + } + + Fail("no RUN command found in dockerfile") + return nil +} + +func newRunStageAI(runCommand *instructions.RunCommand, dependencyStages []string) *instruction.Run { + return instruction.NewRun( + NewDockerfileStageInstructionWithDependencyStages(runCommand, dependencyStages), + nil, false, + &stage.BaseStageOptions{ImageName: "example-image", ProjectName: "example-project"}, + nil, "", + ) +} + +var _ = Describe("TestAI_ RUN mount from stage resolution", func() { + const resolvedOsImage = "ghcr.io/werf/instruction-test:a71052baf9c6ace8171e59a2ae5ea1aede3fb89aa95d160ec354b205-1661868399091" + + It("TestAI_ resolves --mount from=<stage> to the built werf stage image in the backend instruction", func(ctx SpecContext) { + stg := newRunStageAI( + parseRunCommandAI("FROM alpine AS os\nRUN --mount=type=bind,from=os,source=/apk,target=/apk true\n"), + []string{"os"}, + ) + + conveyor := stage.NewConveyorStub( + stage.NewGiterminismManagerStub(stage.NewLocalGitRepoStub("test"), stage.NewGiterminismInspectorStub()), + map[string]string{"/stage/os": resolvedOsImage}, + nil, nil, + ) + + Expect(stg.ExpandDependencies(ctx, conveyor, map[string]string{})).To(Succeed()) + + mounts := instruction.ExportRunMounts(stg) + Expect(mounts).To(HaveLen(1)) + Expect(mounts[0].From).To(Equal(resolvedOsImage)) + }) + + It("TestAI_ leaves external --mount from=<image> references unchanged", func(ctx SpecContext) { + stg := newRunStageAI( + parseRunCommandAI("FROM alpine\nRUN --mount=type=bind,from=alpine:3.19,source=/etc,target=/etc true\n"), + nil, + ) + + conveyor := stage.NewConveyorStub( + stage.NewGiterminismManagerStub(stage.NewLocalGitRepoStub("test"), stage.NewGiterminismInspectorStub()), + nil, nil, nil, + ) + + Expect(stg.ExpandDependencies(ctx, conveyor, map[string]string{})).To(Succeed()) + + mounts := instruction.ExportRunMounts(stg) + Expect(mounts).To(HaveLen(1)) + Expect(mounts[0].From).To(Equal("alpine:3.19")) + }) + + digestFor := func(ctx SpecContext, resolvedImage string) string { + stg := newRunStageAI( + parseRunCommandAI("FROM alpine AS os\nRUN --mount=type=bind,from=os,source=/apk,target=/apk true\n"), + []string{"os"}, + ) + + conveyor := stage.NewConveyorStub( + stage.NewGiterminismManagerStub(stage.NewLocalGitRepoStub("test"), stage.NewGiterminismInspectorStub()), + map[string]string{"/stage/os": resolvedImage}, + nil, nil, + ) + + Expect(stg.ExpandDependencies(ctx, conveyor, map[string]string{})).To(Succeed()) + + digest, err := stg.GetDependencies(ctx, conveyor, stage.NewContainerBackendStub(), nil, nil, nil) + Expect(err).To(Succeed()) + return digest + } + + It("TestAI_ digest reflects the resolved stage image and is stable for identical inputs", func(ctx SpecContext) { + digest1 := digestFor(ctx, resolvedOsImage) + digest2 := digestFor(ctx, resolvedOsImage) + Expect(digest1).To(Equal(digest2)) + + changedDigest := digestFor(ctx, "ghcr.io/werf/instruction-test:4930d562bfbee9c931413c826137d49eff6a2e7d39519c1c9488a747-1655913653892") + fmt.Printf("digest: %s, changedDigest: %s\n", digest1, changedDigest) + Expect(changedDigest).NotTo(Equal(digest1)) + }) +}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/deploy/helm/chart_extender/helpers/service_values.go new/werf-2.73.1/pkg/deploy/helm/chart_extender/helpers/service_values.go --- old/werf-2.72.2/pkg/deploy/helm/chart_extender/helpers/service_values.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/deploy/helm/chart_extender/helpers/service_values.go 2026-06-26 10:48:33.000000000 +0200 @@ -177,7 +177,18 @@ if data, err := ioutil.ReadFile(configJsonPath); err != nil { return fmt.Errorf("error reading %q: %w", configJsonPath, err) } else { - values["dockerconfigjson"] = base64.StdEncoding.EncodeToString(data) + dockerConfigBase64 := base64.StdEncoding.EncodeToString(data) + values["dockerconfigjson"] = dockerConfigBase64 + + if exposeGlobalServiceValues() { + if globalValues, ok := values["global"].(map[string]interface{}); !ok { + return fmt.Errorf("set .Values.global.werf.dockerconfigjson: expected map at .Values.global, got %T", values["global"]) + } else if werfValues, ok := globalValues["werf"].(map[string]interface{}); !ok { + return fmt.Errorf("set .Values.global.werf.dockerconfigjson: expected map at .Values.global.werf, got %T", globalValues["werf"]) + } else { + werfValues["dockerconfigjson"] = dockerConfigBase64 + } + } } logboek.Context(ctx).Default().LogF("NOTE: ### --set-docker-config-json-value option has been specified ###\n") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/deploy/helm_for_werf_helm/chart_extender_for_werf_helm/helpers_for_werf_helm/service_values.go new/werf-2.73.1/pkg/deploy/helm_for_werf_helm/chart_extender_for_werf_helm/helpers_for_werf_helm/service_values.go --- old/werf-2.72.2/pkg/deploy/helm_for_werf_helm/chart_extender_for_werf_helm/helpers_for_werf_helm/service_values.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/deploy/helm_for_werf_helm/chart_extender_for_werf_helm/helpers_for_werf_helm/service_values.go 2026-06-26 10:48:33.000000000 +0200 @@ -202,7 +202,18 @@ if data, err := ioutil.ReadFile(configJsonPath); err != nil { return fmt.Errorf("error reading %q: %w", configJsonPath, err) } else { - values["dockerconfigjson"] = base64.StdEncoding.EncodeToString(data) + dockerConfigBase64 := base64.StdEncoding.EncodeToString(data) + values["dockerconfigjson"] = dockerConfigBase64 + + if exposeGlobalServiceValues() { + if globalValues, ok := values["global"].(map[string]interface{}); !ok { + return fmt.Errorf("set .Values.global.werf.dockerconfigjson: expected map at .Values.global, got %T", values["global"]) + } else if werfValues, ok := globalValues["werf"].(map[string]interface{}); !ok { + return fmt.Errorf("set .Values.global.werf.dockerconfigjson: expected map at .Values.global.werf, got %T", globalValues["werf"]) + } else { + werfValues["dockerconfigjson"] = dockerConfigBase64 + } + } } logboek.Context(ctx).Default().LogF("NOTE: ### --set-docker-config-json-value option has been specified ###\n") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/git_repo/remote.go new/werf-2.73.1/pkg/git_repo/remote.go --- old/werf-2.72.2/pkg/git_repo/remote.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/git_repo/remote.go 2026-06-26 10:48:33.000000000 +0200 @@ -34,6 +34,10 @@ Endpoint *transport.Endpoint BasicAuth *BasicAuth + + Branch string + Tag string + Commit string } func OpenRemoteRepo(name, url string, auth *BasicAuthCredentials) (*Remote, error) { @@ -151,6 +155,34 @@ return timestamps.WriteTimestampFile(path, time.Now()) } +func buildCloneOptions(url, branch string) *git.CloneOptions { + opts := &git.CloneOptions{ + URL: url, + RecurseSubmodules: git.DefaultSubmoduleRecursionDepth, + } + + if branch != "" { + opts.SingleBranch = true + opts.ReferenceName = plumbing.NewBranchReferenceName(branch) + opts.Tags = git.NoTags + } + + return opts +} + +func buildFetchOptions(remoteName, branch string) *git.FetchOptions { + tags := git.AllTags + if branch != "" { + tags = git.NoTags + } + + return &git.FetchOptions{ + RemoteName: remoteName, + Force: true, + Tags: tags, + } +} + func (repo *Remote) Clone(ctx context.Context) (bool, error) { if repo.IsDryRun { return false, nil @@ -202,10 +234,7 @@ // Ensure cleanup on failure defer os.RemoveAll(tmpPath) - cloneOpts := &git.CloneOptions{ - URL: repo.Url, - RecurseSubmodules: git.DefaultSubmoduleRecursionDepth, - } + cloneOpts := buildCloneOptions(repo.Url, repo.Branch) if repo.BasicAuth != nil { cloneOpts.Auth = newBasicAuth(repo.BasicAuth.Username, repo.BasicAuth.Password).AuthMethod @@ -285,11 +314,7 @@ logboek.Context(ctx).Default().LogFDetails("Fetch remote %s of %s\n", remoteName, repo.Url) - fetchOpts := &git.FetchOptions{ - RemoteName: remoteName, - Force: true, - Tags: git.AllTags, - } + fetchOpts := buildFetchOptions(remoteName, repo.Branch) if repo.BasicAuth != nil { fetchOpts.Auth = newBasicAuth(repo.BasicAuth.Username, repo.BasicAuth.Password).AuthMethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/pkg/git_repo/remote_ai_test.go new/werf-2.73.1/pkg/git_repo/remote_ai_test.go --- old/werf-2.72.2/pkg/git_repo/remote_ai_test.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/pkg/git_repo/remote_ai_test.go 2026-06-26 10:48:33.000000000 +0200 @@ -10,6 +10,36 @@ "github.com/stretchr/testify/require" ) +func TestAI_BuildCloneOptions(t *testing.T) { + t.Run("branch mapping clones single branch without tags", func(t *testing.T) { + opts := buildCloneOptions("https://example.com/repo.git", "main") + assert.True(t, opts.SingleBranch) + assert.Equal(t, plumbing.NewBranchReferenceName("main"), opts.ReferenceName) + assert.Equal(t, git.NoTags, opts.Tags) + }) + + t.Run("no branch clones everything", func(t *testing.T) { + opts := buildCloneOptions("https://example.com/repo.git", "") + assert.False(t, opts.SingleBranch) + assert.Empty(t, opts.ReferenceName) + assert.NotEqual(t, git.NoTags, opts.Tags) + }) +} + +func TestAI_BuildFetchOptions(t *testing.T) { + t.Run("branch mapping fetches without tags", func(t *testing.T) { + opts := buildFetchOptions("origin", "main") + assert.Equal(t, git.NoTags, opts.Tags) + assert.True(t, opts.Force) + }) + + t.Run("no branch fetches all tags", func(t *testing.T) { + opts := buildFetchOptions("origin", "") + assert.Equal(t, git.AllTags, opts.Tags) + assert.True(t, opts.Force) + }) +} + func TestAI_SyncLocalBranches(t *testing.T) { tmpDir := t.TempDir() rawRepo, err := git.PlainInit(tmpDir, true) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/test/e2e/build/_fixtures/scratch/state0/werf.yaml new/werf-2.73.1/test/e2e/build/_fixtures/scratch/state0/werf.yaml --- old/werf-2.72.2/test/e2e/build/_fixtures/scratch/state0/werf.yaml 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/test/e2e/build/_fixtures/scratch/state0/werf.yaml 2026-06-26 10:48:33.000000000 +0200 @@ -2,5 +2,16 @@ configVersion: 1 --- +image: source +from: alpine +shell: + install: + - echo "werf-test-scratch-import" > /etc/werf-test-scratch-import +--- image: stapel-scratch from: scratch +import: +- image: source + add: /etc/werf-test-scratch-import + to: /etc/werf-test-scratch-import + before: install diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/test/e2e/build/multiarch_test.go new/werf-2.73.1/test/e2e/build/multiarch_test.go --- old/werf-2.72.2/test/e2e/build/multiarch_test.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/test/e2e/build/multiarch_test.go 2026-06-26 10:48:33.000000000 +0200 @@ -8,6 +8,7 @@ "github.com/containerd/containerd/platforms" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/werf/common-go/pkg/util" "github.com/werf/werf/v2/pkg/container_backend/thirdparty/platformutil" @@ -103,16 +104,19 @@ platformSpec, err := platformutil.ParsePlatform(platform) Expect(err).To(Succeed()) - platformSpec = platforms.Normalize(platformSpec) ref := fmt.Sprintf("%s:%s", SuiteData.WerfRepo, byPlatform[platform].DockerTag) inspect := contBack.GetImageInspect(ctx, ref) fmt.Printf("Check image %q inspect:\n%#v\n---\n", ref, inspect) - Expect(inspect.Os).To(Equal(platformSpec.OS)) - Expect(inspect.Architecture).To(Equal(platformSpec.Architecture)) - Expect(inspect.Variant).To(Equal(platformSpec.Variant)) + expectedPlatform := platforms.Format(platforms.Normalize(platformSpec)) + actualPlatform := platforms.Format(platforms.Normalize(v1.Platform{ + OS: inspect.Os, + Architecture: inspect.Architecture, + Variant: inspect.Variant, + })) + Expect(actualPlatform).To(Equal(expectedPlatform)) } // Meta digest only used for multiplatform builds diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/test/e2e/build/scratch_test.go new/werf-2.73.1/test/e2e/build/scratch_test.go --- old/werf-2.72.2/test/e2e/build/scratch_test.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/test/e2e/build/scratch_test.go 2026-06-26 10:48:33.000000000 +0200 @@ -7,6 +7,7 @@ "github.com/werf/werf/v2/pkg/image" "github.com/werf/werf/v2/test/pkg/contback" "github.com/werf/werf/v2/test/pkg/report" + "github.com/werf/werf/v2/test/pkg/utils" "github.com/werf/werf/v2/test/pkg/werf" ) @@ -19,7 +20,7 @@ func(ctx SpecContext, testOpts scratchTestOptions) { By("initializing") setupEnv(testOpts.setupEnvOptions) - contRuntime, err := contback.NewContainerBackend(testOpts.ContainerBackendMode) + _, err := contback.NewContainerBackend(testOpts.ContainerBackendMode) if err == contback.ErrRuntimeUnavailable { Skip(err.Error()) } else if err != nil { @@ -39,22 +40,15 @@ buildOut, buildReport := reportProject.BuildWithReport(ctx, SuiteData.GetBuildReportPath(buildReportName), nil) Expect(buildOut).To(ContainSubstring("Building stage")) - By("checking scratch image labels") + By("checking scratch image contents and labels") imageName := buildReport.Images["stapel-scratch"].DockerImageName - if testOpts.WithLocalRepo { - contRuntime.Pull(ctx, imageName) - } - inspect := contRuntime.GetImageInspect(ctx, imageName) - labels := inspect.Config.Labels - Expect(labels).NotTo(BeNil()) - Expect(labels).To(HaveKey(image.WerfLabel)) - Expect(labels[image.WerfLabel]).NotTo(BeEmpty()) - Expect(labels).To(HaveKey(image.WerfVersionLabel)) - Expect(labels[image.WerfVersionLabel]).NotTo(BeEmpty()) - Expect(labels).To(HaveKey(image.WerfStageContentDigestLabel)) - Expect(labels[image.WerfStageContentDigestLabel]).NotTo(BeEmpty()) - Expect(labels).To(HaveKey(image.WerfProjectRepoCommitLabel)) - Expect(labels[image.WerfProjectRepoCommitLabel]).NotTo(BeEmpty()) + utils.ExpectFileContentInImage(ctx, testOpts.ContainerBackendMode, imageName, "etc/werf-test-scratch-import", "werf-test-scratch-import\n") + utils.ExpectImageHasNonEmptyLabels(ctx, testOpts.ContainerBackendMode, imageName, + image.WerfLabel, + image.WerfVersionLabel, + image.WerfStageContentDigestLabel, + image.WerfProjectRepoCommitLabel, + ) }, Entry("using Vanilla Docker", scratchTestOptions{setupEnvOptions{ ContainerBackendMode: "vanilla-docker", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/test/pkg/utils/image.go new/werf-2.73.1/test/pkg/utils/image.go --- old/werf-2.72.2/test/pkg/utils/image.go 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/test/pkg/utils/image.go 2026-06-26 10:48:33.000000000 +0200 @@ -1,10 +1,83 @@ package utils import ( + "archive/tar" "context" + "io" + "os" "strings" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/tarball" + . "github.com/onsi/gomega" ) +func ExpectFileContentInImage(ctx context.Context, backendMode, imageName, filePath, expectedContent string) { + img, cleanup := loadLocalImage(ctx, backendMode, imageName) + defer cleanup() + rc := mutate.Extract(img) + defer rc.Close() + + var fileContent string + + tr := tar.NewReader(rc) + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + Expect(err).NotTo(HaveOccurred()) + + if hdr.Name != filePath && hdr.Name != "./"+filePath { + continue + } + + data, err := io.ReadAll(tr) + Expect(err).NotTo(HaveOccurred()) + fileContent = string(data) + } + + Expect(fileContent).To(Equal(expectedContent), "expected image file content to match for %s", filePath) +} + +func ExpectImageHasNonEmptyLabels(ctx context.Context, backendMode, imageName string, labelKeys ...string) { + img, cleanup := loadLocalImage(ctx, backendMode, imageName) + defer cleanup() + config, err := img.ConfigFile() + Expect(err).NotTo(HaveOccurred()) + + labels := config.Config.Labels + Expect(labels).NotTo(BeNil()) + + for _, key := range labelKeys { + Expect(labels).To(HaveKey(key)) + Expect(labels[key]).NotTo(BeEmpty()) + } +} + +func loadLocalImage(ctx context.Context, backendMode, imageName string) (v1.Image, func()) { + tempFile, err := os.CreateTemp("", "werf-e2e-image-*.tar") + Expect(err).NotTo(HaveOccurred()) + + tempTarPath := tempFile.Name() + Expect(tempFile.Close()).To(Succeed()) + + switch backendMode { + case "docker", "vanilla-docker", "buildkit-docker": + RunSucceedCommand(ctx, "/", "docker", "save", "-o", tempTarPath, imageName) + case "native-rootless", "native-chroot": + RunSucceedCommand(ctx, "/", "buildah", "push", "--tls-verify=false", "--format", "docker", imageName, "docker-archive:"+tempTarPath) + default: + Expect(false).To(BeTrue(), "unsupported backend mode: %s", backendMode) + } + + img, err := tarball.ImageFromPath(tempTarPath, nil) + Expect(err).NotTo(HaveOccurred()) + + return img, func() { os.Remove(tempTarPath) } +} + func GetBuiltImageLastStageImageName(ctx context.Context, testDirPath, werfBinPath, imageName string) string { stageImageName := SucceedCommandOutputString(ctx, testDirPath, werfBinPath, "stage", "image", imageName) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/werf-2.72.2/trdl_channels.yaml new/werf-2.73.1/trdl_channels.yaml --- old/werf-2.72.2/trdl_channels.yaml 2026-06-18 16:14:11.000000000 +0200 +++ new/werf-2.73.1/trdl_channels.yaml 2026-06-26 10:48:33.000000000 +0200 @@ -38,12 +38,12 @@ - name: "2" channels: - name: alpha - version: 2.72.1 + version: 2.73.0 - name: beta - version: 2.72.0 + version: 2.72.2 - name: ea - version: 2.71.0 + version: 2.72.2 - name: stable - version: 2.70.0 + version: 2.71.0 - name: rock-solid version: 2.70.0 ++++++ werf.obsinfo ++++++ --- /var/tmp/diff_new_pack.wFbWLL/_old 2026-07-15 17:05:46.731633022 +0200 +++ /var/tmp/diff_new_pack.wFbWLL/_new 2026-07-15 17:05:46.743633432 +0200 @@ -1,5 +1,5 @@ name: werf -version: 2.72.2 -mtime: 1781792051 -commit: e5cc40533ad562ef3cddec21bb444bf44cdf6501 +version: 2.73.1 +mtime: 1782463713 +commit: 122c59efc52769e6aab7d1637ff241367f2bf476
