Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package updatecli for openSUSE:Factory checked in at 2025-06-13 18:47:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/updatecli (Old) and /work/SRC/openSUSE:Factory/.updatecli.new.19631 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "updatecli" Fri Jun 13 18:47:54 2025 rev:21 rq:1285465 version:0.102.0 Changes: -------- --- /work/SRC/openSUSE:Factory/updatecli/updatecli.changes 2025-05-31 19:18:21.162450945 +0200 +++ /work/SRC/openSUSE:Factory/.updatecli.new.19631/updatecli.changes 2025-06-13 18:48:05.877360376 +0200 @@ -1,0 +2,29 @@ +Fri Jun 13 11:31:18 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.102.0: + * Features + - Various feature additions for CUE @refi64 (#5352) + - feat(bitbucket): add support for pull request description + merging @mcwarman (#5350) + * Bug Fixes + - fix: fix default argocd autodiscovery action title @olblak + (#5419) + - fix(reports): update target description to output correctly + in markdown @mcwarman (#5309) + - fix: remove duplicate generate schema @qianlongzt (#5299) + * Maintenance + - deps(go): bump module + github.com/hashicorp/terraform-registry-address to v0.3.0 + @updateclibot[bot] (#5409) + - deps(go): bump module cuelang.org/go to v0.13.1 + @updateclibot[bot] (#5400) + - deps(go): bump module golang.org/x/net to v0.41.0 + @updateclibot[bot] (#5381) + - deps(go): bump module github.com/fluxcd/source-controller/api + to v1.6.0 @updateclibot[bot] (#5380) + - deps(go): bump module github.com/go-git/go-git/v5 to v5.16.2 + @updateclibot[bot] (#5373) + - deps(go): bump module helm.sh/helm/v3 to v3.18.2 + @updateclibot[bot] (#5362) + +------------------------------------------------------------------- Old: ---- updatecli-0.101.0.obscpio New: ---- updatecli-0.102.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ updatecli.spec ++++++ --- /var/tmp/diff_new_pack.5fXz73/_old 2025-06-13 18:48:07.297419164 +0200 +++ /var/tmp/diff_new_pack.5fXz73/_new 2025-06-13 18:48:07.301419329 +0200 @@ -17,7 +17,7 @@ Name: updatecli -Version: 0.101.0 +Version: 0.102.0 Release: 0 Summary: A Declarative Dependency Management tool License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.5fXz73/_old 2025-06-13 18:48:07.341420985 +0200 +++ /var/tmp/diff_new_pack.5fXz73/_new 2025-06-13 18:48:07.345421151 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/updatecli/updatecli</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.101.0</param> + <param name="revision">v0.102.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.5fXz73/_old 2025-06-13 18:48:07.365421978 +0200 +++ /var/tmp/diff_new_pack.5fXz73/_new 2025-06-13 18:48:07.369422145 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/updatecli/updatecli</param> - <param name="changesrevision">86ea3f3f2b773121086ab701900843d999e29f6b</param></service></servicedata> + <param name="changesrevision">a6194320af7931b03cd9855f98e7f35938509cba</param></service></servicedata> (No newline at EOF) ++++++ updatecli-0.101.0.obscpio -> updatecli-0.102.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/.devcontainer/devcontainer.json new/updatecli-0.102.0/.devcontainer/devcontainer.json --- old/updatecli-0.101.0/.devcontainer/devcontainer.json 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/.devcontainer/devcontainer.json 2025-06-13 09:15:32.000000000 +0200 @@ -3,7 +3,7 @@ { "name": "Go", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm", + "image": "mcr.microsoft.com/devcontainers/go:1-1.24-bookworm", // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Use 'forwardPorts' to make a list of ports inside the container available locally. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/README.adoc new/updatecli-0.102.0/README.adoc --- old/updatecli-0.101.0/README.adoc 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/README.adoc 2025-06-13 09:15:32.000000000 +0200 @@ -52,7 +52,7 @@ Once you have the three files locally, you can execute the following command ``` -cosign verify-blob --certificate-identity-regexp "https://github.com/updatecli/updatecli" --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' --cert https://github.com/updatecli/updatecli/releases/download/v0.100.0/checksums.txt.pem --signature https://github.com/updatecli/updatecli/releases/download/v0.100.0/checksums.txt.sig checksums.txt +cosign verify-blob --certificate-identity-regexp "https://github.com/updatecli/updatecli" --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' --cert https://github.com/updatecli/updatecli/releases/download/v0.101.0/checksums.txt.pem --signature https://github.com/updatecli/updatecli/releases/download/v0.101.0/checksums.txt.sig checksums.txt ``` A successful output looks like @@ -76,7 +76,7 @@ **Verify Container signature** ``` -cosign verify --certificate-identity-regexp "https://github.com/updatecli/updatecli" --certificate-oidc-issuer "https://token.actions.githubusercontent.com" ghcr.io/updatecli/updatecli:v0.100.0 +cosign verify --certificate-identity-regexp "https://github.com/updatecli/updatecli" --certificate-oidc-issuer "https://token.actions.githubusercontent.com" ghcr.io/updatecli/updatecli:v0.101.0 ``` == Documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/go.mod new/updatecli-0.102.0/go.mod --- old/updatecli-0.101.0/go.mod 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/go.mod 2025-06-13 09:15:32.000000000 +0200 @@ -1,6 +1,6 @@ module github.com/updatecli/updatecli -go 1.24.3 +go 1.24.4 require ( dario.cat/mergo v1.0.2 @@ -10,7 +10,7 @@ github.com/containerd/containerd v1.7.27 // indirect github.com/fatih/color v1.18.0 github.com/getsops/sops/v3 v3.9.2 - github.com/go-git/go-git/v5 v5.16.0 + github.com/go-git/go-git/v5 v5.16.2 github.com/heimdalr/dag v1.5.0 github.com/hexops/gotextdiff v1.0.3 github.com/lithammer/dedent v1.1.0 @@ -26,25 +26,25 @@ github.com/stretchr/testify v1.10.0 golang.org/x/oauth2 v0.30.0 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.18.1 + helm.sh/helm/v3 v3.18.2 sigs.k8s.io/yaml v1.4.0 ) require ( - cuelang.org/go v0.13.0 + cuelang.org/go v0.13.1 github.com/BurntSushi/toml v1.5.0 github.com/JohannesKaufmann/html-to-markdown v1.6.0 github.com/ProtonMail/go-crypto v1.1.6 github.com/beevik/etree v1.5.1 github.com/drone/go-scm v1.40.1 github.com/fluxcd/helm-controller/api v1.3.0 - github.com/fluxcd/source-controller/api v1.5.0 + github.com/fluxcd/source-controller/api v1.6.0 github.com/goccy/go-yaml v1.18.0 github.com/google/go-containerregistry v0.20.5 github.com/google/go-github/v69 v69.2.0 github.com/goware/urlx v0.3.2 github.com/hashicorp/hcl/v2 v2.23.1-0.20250211201033-5c140ce1cb20 - github.com/hashicorp/terraform-registry-address v0.2.5 + github.com/hashicorp/terraform-registry-address v0.3.0 github.com/invopop/jsonschema v0.13.0 github.com/joho/godotenv v1.5.1 github.com/minamijoyo/hcledit v0.2.17 @@ -60,7 +60,7 @@ github.com/yuin/goldmark v1.7.12 github.com/zclconf/go-cty v1.16.3 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - golang.org/x/text v0.25.0 + golang.org/x/text v0.26.0 golang.org/x/time v0.11.0 gopkg.in/ini.v1 v1.67.0 oras.land/oras-go/v2 v2.6.0 @@ -129,7 +129,7 @@ github.com/envoyproxy/go-control-plane v0.13.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fluxcd/pkg/apis/acl v0.6.0 // indirect + github.com/fluxcd/pkg/apis/acl v0.7.0 // indirect github.com/fluxcd/pkg/apis/kustomize v1.10.0 // indirect github.com/fluxcd/pkg/apis/meta v1.12.0 // indirect github.com/fxamacker/cbor/v2 v2.8.0 // indirect @@ -298,10 +298,10 @@ github.com/xlab/treeprint v1.2.0 // indirect gitlab.com/gitlab-org/api/client-go v0.129.0 go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.38.0 // indirect - golang.org/x/mod v0.24.0 - golang.org/x/net v0.40.0 - golang.org/x/sync v0.14.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/mod v0.25.0 + golang.org/x/net v0.41.0 + golang.org/x/sync v0.15.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/tools v0.33.0 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/go.sum new/updatecli-0.102.0/go.sum --- old/updatecli-0.101.0/go.sum 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/go.sum 2025-06-13 09:15:32.000000000 +0200 @@ -27,8 +27,8 @@ cloud.google.com/go/trace v1.11.2/go.mod h1:bn7OwXd4pd5rFuAnTrzBuoZ4ax2XQeG3qNgYmfCy0Io= cuelabs.dev/go/oci/ociregistry v0.0.0-20250304105642-27e071d2c9b1 h1:Dmbd5Q+ENb2C6carvwrMsrOUwJ9X9qfL5JdW32gYAHo= cuelabs.dev/go/oci/ociregistry v0.0.0-20250304105642-27e071d2c9b1/go.mod h1:dqrnoZx62xbOZr11giMPrWbhlaV8euHwciXZEy3baT8= -cuelang.org/go v0.13.0 h1:Z9NQY9RK3zMbjq1ZK67hvOV58pI3FKQgfuu1Znz+akQ= -cuelang.org/go v0.13.0/go.mod h1:8MoQXu+RcXsa2s9mebJN1HJ1orVDc9aI9/yKi6Dzsi4= +cuelang.org/go v0.13.1 h1:gG01N9B7P95MsQh0EBmr63mVOz7seTP3KH/zg6oAvSs= +cuelang.org/go v0.13.1/go.mod h1:8MoQXu+RcXsa2s9mebJN1HJ1orVDc9aI9/yKi6Dzsi4= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o= @@ -278,14 +278,14 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fluxcd/helm-controller/api v1.3.0 h1:PupXPuQbksmU0g2Lc6NjIYal2HJGL+6xohsf82eGVjo= github.com/fluxcd/helm-controller/api v1.3.0/go.mod h1:4b8PfdH0e/9Pfol2ogdMYbQ1nLjcVu9gAv27cQzIPK4= -github.com/fluxcd/pkg/apis/acl v0.6.0 h1:rllf5uQLzTow81ZCslkQ6LPpDNqVQr6/fWaNksdUEtc= -github.com/fluxcd/pkg/apis/acl v0.6.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs= +github.com/fluxcd/pkg/apis/acl v0.7.0 h1:dMhZJH+g6ZRPjs4zVOAN9vHBd1DcavFgcIFkg5ooOE0= +github.com/fluxcd/pkg/apis/acl v0.7.0/go.mod h1:uv7pXXR/gydiX4MUwlQa7vS8JONEDztynnjTvY3JxKQ= github.com/fluxcd/pkg/apis/kustomize v1.10.0 h1:47EeSzkQvlQZdH92vHMe2lK2iR8aOSEJq95avw5idts= github.com/fluxcd/pkg/apis/kustomize v1.10.0/go.mod h1:UsqMV4sqNa1Yg0pmTsdkHRJr7bafBOENIJoAN+3ezaQ= github.com/fluxcd/pkg/apis/meta v1.12.0 h1:XW15TKZieC2b7MN8VS85stqZJOx+/b8jATQ/xTUhVYg= github.com/fluxcd/pkg/apis/meta v1.12.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI= -github.com/fluxcd/source-controller/api v1.5.0 h1:caSR+u/r2Vh0jq/0pNR0r1zLxyvgatWuGSV2mxgTB/I= -github.com/fluxcd/source-controller/api v1.5.0/go.mod h1:OZPuHMlLH2E2mnj6Q5DLkWfUOmJ20zA1LIvUVfNsYl8= +github.com/fluxcd/source-controller/api v1.6.0 h1:IxfjUczJ2pzbXIef6iQ0RHEH4AYA9anJfTGK8dzwODM= +github.com/fluxcd/source-controller/api v1.6.0/go.mod h1:ZJcAi0nemsnBxjVgmJl0WQzNvB0rMETxQMTdoFosmMw= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -310,8 +310,8 @@ github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ= -github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= +github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM= +github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= @@ -457,8 +457,8 @@ github.com/hashicorp/hcl/v2 v2.23.1-0.20250211201033-5c140ce1cb20/go.mod h1:k+HgkLpoWu9OS81sy4j1XKDXaWm/rLysG33v5ibdDnc= github.com/hashicorp/terraform-config-inspect v0.0.0-20230614215431-f32df32a01cd h1:1uPcotqoL4TjcGKlgIe7OFSRplf7BMVtUjekwmCrvuM= github.com/hashicorp/terraform-config-inspect v0.0.0-20230614215431-f32df32a01cd/go.mod h1:l8HcFPm9cQh6Q0KSWoYPiePqMvRFenybP1CH2MjKdlg= -github.com/hashicorp/terraform-registry-address v0.2.5 h1:2GTftHqmUhVOeuu9CW3kwDkRe4pcBDq0uuK5VJngU1M= -github.com/hashicorp/terraform-registry-address v0.2.5/go.mod h1:PpzXWINwB5kuVS5CA7m1+eO2f1jKb5ZDIxrOPfpnGkg= +github.com/hashicorp/terraform-registry-address v0.3.0 h1:HMpK3nqaGFPS9VmgRXrJL/dzHNdheGVKk5k7VlFxzCo= +github.com/hashicorp/terraform-registry-address v0.3.0/go.mod h1:jRGCMiLaY9zii3GLC7hqpSnwhfnCN5yzvY0hh4iCGbM= github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA= @@ -822,8 +822,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -834,8 +834,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -856,8 +856,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= @@ -868,8 +868,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -924,8 +924,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1008,8 +1008,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -helm.sh/helm/v3 v3.18.1 h1:qLhXmtqXOHQb0Xv9HJolOLlah8RWbgyzt50xrtTWAlg= -helm.sh/helm/v3 v3.18.1/go.mod h1:43QHS1W97RcoFJRk36ZBhHdTfykqBlJdsWp3yhzdq8w= +helm.sh/helm/v3 v3.18.2 h1:mPQP/HHYjNEDAztAK50dD6uxTCNV1zSVU38WwSVdw9M= +helm.sh/helm/v3 v3.18.2/go.mod h1:43QHS1W97RcoFJRk36ZBhHdTfykqBlJdsWp3yhzdq8w= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/config/helper.go new/updatecli-0.102.0/pkg/core/config/helper.go --- old/updatecli-0.101.0/pkg/core/config/helper.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/config/helper.go 2025-06-13 09:15:32.000000000 +0200 @@ -13,9 +13,6 @@ "golang.org/x/text/cases" "golang.org/x/text/language" "gopkg.in/yaml.v3" - - "cuelang.org/go/cue/cuecontext" - cueyaml "cuelang.org/go/encoding/yaml" ) // FileChecksum returns sha256 checksum based on a file content. @@ -137,27 +134,6 @@ } -// readCueConfig loads a cue spec and convert it to YAML before converting it to an Updatecli config spec -// An important limitation in today's Updatecli implementation is that -// Updatecli loads all configuration in memory and then apply each files individually as independent pipeline. -// So cuelang feature won't be able to load module or package using the directory structure. -func readCueConfig(in []byte) ([]byte, error) { - - ctx := cuecontext.New() - - compiledVal := ctx.CompileBytes(in) - if compiledVal.Err() != nil { - return nil, fmt.Errorf("compile cue spec: %w", compiledVal.Err()) - } - - val, err := cueyaml.Encode(compiledVal) - if err != nil { - return nil, fmt.Errorf("encode cue spec to yaml: %w", err) - } - - return val, nil -} - // unmarshalConfigSpec unmarshal an Updatecli config spec func unmarshalConfigSpec(in []byte, out *[]Spec) error { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/config/main.go new/updatecli-0.102.0/pkg/core/config/main.go --- old/updatecli-0.101.0/pkg/core/config/main.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/config/main.go 2025-06-13 09:15:32.000000000 +0200 @@ -28,6 +28,10 @@ "github.com/hexops/gotextdiff/myers" "github.com/hexops/gotextdiff/span" "github.com/updatecli/updatecli/pkg/plugins/utils/gitgeneric" + + "cuelang.org/go/cue" + "cuelang.org/go/cue/cuecontext" + cueformat "cuelang.org/go/cue/format" ) const ( @@ -235,6 +239,8 @@ specs := []Spec{} + isCue := false + switch extension := filepath.Ext(basename); extension { case ".tpl", ".tmpl", ".yaml", ".yml", ".json": // @@ -242,16 +248,14 @@ if !cmdoptions.Experimental { return configs, fmt.Errorf("cuelang support is experimental, please use '--experimental' flag to enable it") } - rawManifestContent, err = readCueConfig(rawManifestContent) - if err != nil { - return configs, err - } + isCue = true default: logrus.Debugf("file extension '%s' not supported for file '%s'", extension, option.ManifestFile) return configs, ErrConfigFileTypeNotSupported } + var cueManifest cue.Value if !option.DisableTemplating { // Try to template manifest no matter the extension // templated manifest must respect its extension before and after templating @@ -269,13 +273,33 @@ fs: fs, } - templatedManifestContent, err = t.New(rawManifestContent) + if isCue { + cueManifest, err = t.NewCueTemplate(rawManifestContent) + } else { + templatedManifestContent, err = t.NewStringTemplate(rawManifestContent) + } if err != nil { logrus.Errorf("Error while templating %q:\n---\n%s\n---\n\t%s\n", option.ManifestFile, string(rawManifestContent), err.Error()) return configs, err } if GolangTemplatingDiff { + if isCue { + // Reformat all the CUE sources so that they can be diffed. + rawManifestContent, err = cueformat.Source(rawManifestContent, cueformat.Simplify()) + if err != nil { + logrus.Errorf("Error formatting %q for diff: %s", option.ManifestFile, err.Error()) + return configs, err + } + + node := cueManifest.Syntax(cue.Final(), cue.ErrorsAsValues(true)) + templatedManifestContent, err = cueformat.Node(node, cueformat.Simplify()) + if err != nil { + logrus.Errorf("Error formatting %q (templated) for diff: %s", option.ManifestFile, err.Error()) + return configs, err + } + } + diff := text.Diff("raw manifest", "templated manifest", string(rawManifestContent), string(templatedManifestContent)) switch diff { case "": @@ -284,11 +308,23 @@ logrus.Debugf("Golang templating change detected:\n%s\n\n---\n", diff) } } + } else if isCue { + ctx := cuecontext.New() + cueManifest = ctx.CompileBytes(rawManifestContent) } - err = unmarshalConfigSpec(templatedManifestContent, &specs) - if err != nil { - return configs, err + if isCue { + var spec Spec + err = cueManifest.Decode(&spec) + if err != nil { + return configs, err + } + specs = append(specs, spec) + } else { + err := unmarshalConfigSpec(templatedManifestContent, &specs) + if err != nil { + return configs, err + } } configs = make([]Config, len(specs)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/config/template.go new/updatecli-0.102.0/pkg/core/config/template.go --- old/updatecli-0.101.0/pkg/core/config/template.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/config/template.go 2025-06-13 09:15:32.000000000 +0200 @@ -15,6 +15,10 @@ "github.com/getsops/sops/v3/decrypt" "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" + + "cuelang.org/go/cue" + cueast "cuelang.org/go/cue/ast" + "cuelang.org/go/cue/cuecontext" ) // Template contains template information used to generate updatecli configuration struct @@ -33,21 +37,13 @@ fs fs.FS } -// Init parses a golang template then return an updatecli configuration as a struct -func (t *Template) New(content []byte) ([]byte, error) { - err := t.readValuesFiles(t.ValuesFiles, false) - if err != nil { - return []byte{}, err - } - - err = t.readValuesFiles(t.SecretsFiles, true) +// NewStringTemplate parses a golang template then return an updatecli configuration as a struct +func (t *Template) NewStringTemplate(content []byte) ([]byte, error) { + templateValues, err := t.readAllValues() if err != nil { return []byte{}, err } - // Merge yaml configuration and sops secrets into one configuration - templateValues := mergeValueFile(t.Values, t.Secrets) - tmpl, err := template.New("cfg"). Funcs(sprig.FuncMap()). Funcs(helmFuncMap()). // add helm funcMap @@ -67,6 +63,40 @@ return b.Bytes(), nil } +// NewCueTemplate parses a Cue template then return an updatecli configuration as a struct +func (t *Template) NewCueTemplate(content []byte) (cue.Value, error) { + ctx := cuecontext.New() + + templateValues, err := t.readAllValues() + if err != nil { + return cue.Value{}, err + } + + scope := ctx.BuildExpr(cueast.NewStruct()) + valuesPath := cue.MakePath(cue.Def("#values")) + scope = scope.FillPath(valuesPath, ctx.Encode(templateValues)) + + result := ctx.CompileBytes(content, cue.Scope(scope)) + return result, nil + +} + +// readAllValues reads and merges all the values and secrets files into one map +func (t *Template) readAllValues() (map[string]any, error) { + err := t.readValuesFiles(t.ValuesFiles, false) + if err != nil { + return nil, err + } + + err = t.readValuesFiles(t.SecretsFiles, true) + if err != nil { + return nil, err + } + + // Merge yaml configuration and sops secrets into one configuration + return mergeValueFile(t.Values, t.Secrets), nil +} + // readValuesFiles reads one or multiple updatecli values files and merge them into one func (t *Template) readValuesFiles(valueFiles []string, encrypted bool) error { // Read every files containing yaml key/values diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/config/template_test.go new/updatecli-0.102.0/pkg/core/config/template_test.go --- old/updatecli-0.101.0/pkg/core/config/template_test.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/config/template_test.go 2025-06-13 09:15:32.000000000 +0200 @@ -88,7 +88,7 @@ }, } expected := dedent.Dedent(testTemplate.ExpectedManifest) - rendered, err := template.New([]byte(dedent.Dedent(testTemplate.ManifestTemplate))) + rendered, err := template.NewStringTemplate([]byte(dedent.Dedent(testTemplate.ManifestTemplate))) if testTemplate.ExpectError { require.Error(t, err) return @@ -103,7 +103,7 @@ ValuesFiles: []string{"values.yml"}, fs: fstest.MapFS{}, } - _, err := template.New([]byte("")) + _, err := template.NewStringTemplate([]byte("")) require.Equal(t, err.Error(), fmt.Sprintf("open values.yml: %s", fs.ErrNotExist.Error())) }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/engine/configuration.go new/updatecli-0.102.0/pkg/core/engine/configuration.go --- old/updatecli-0.101.0/pkg/core/engine/configuration.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/engine/configuration.go 2025-06-13 09:15:32.000000000 +0200 @@ -7,6 +7,7 @@ "strings" "github.com/sirupsen/logrus" + "github.com/updatecli/updatecli/pkg/core/cmdoptions" "github.com/updatecli/updatecli/pkg/core/config" "github.com/updatecli/updatecli/pkg/core/pipeline" "github.com/updatecli/updatecli/pkg/core/reports" @@ -27,15 +28,20 @@ // If updatecli.yaml doesn't exists then Updatecli parses the directory updatecli.d for any manifests. // if there is no manifests in the directory updatecli.d then Updatecli returns no manifest files. - // defaultManifestFilename defines the default updatecli configuration filename - defaultManifestFilename := "updatecli.yaml" + // defaultManifestFilenames defines the default updatecli configuration filenames + defaultManifestFilenames := []string{"updatecli.yaml"} + if cmdoptions.Experimental { + defaultManifestFilenames = append(defaultManifestFilenames, "updatecli.cue") + } // defaultManifestDirname defines the default updatecli manifest directory defaultManifestDirname := "updatecli.d" // If no manifest file is specified, we try to detect one - if _, err := os.Stat(defaultManifestFilename); err == nil { - logrus.Debugf("Default Updatecli manifest detected %q", defaultManifestFilename) - e.Options.Manifests[i].Manifests = append(e.Options.Manifests[i].Manifests, defaultManifestFilename) + for _, filename := range defaultManifestFilenames { + if _, err := os.Stat(filename); err == nil { + logrus.Debugf("Default Updatecli manifest detected %q", filename) + e.Options.Manifests[i].Manifests = append(e.Options.Manifests[i].Manifests, filename) + } } if fs, err := os.Stat(defaultManifestDirname); err == nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/engine/schema.go new/updatecli-0.102.0/pkg/core/engine/schema.go --- old/updatecli-0.101.0/pkg/core/engine/schema.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/engine/schema.go 2025-06-13 09:15:32.000000000 +0200 @@ -2,9 +2,8 @@ import ( "fmt" - "path/filepath" - "net/url" + "path/filepath" "github.com/sirupsen/logrus" "github.com/updatecli/updatecli/pkg/core/compose" @@ -14,11 +13,9 @@ ) func GenerateSchema(baseSchemaID, schemaDir string) error { - PrintTitle("Json Schema") err := jsonschema.CloneCommentDirectory() - if err != nil { return err } @@ -31,7 +28,6 @@ }() generateSchema := func(baseSchemaID, schemaDir, subSchemaDir string, spec interface{}) error { - if subSchemaDir != "" { schemaDir = filepath.Join(schemaDir, subSchemaDir) @@ -58,11 +54,7 @@ return fmt.Errorf("unable to save schema - %s", err) } - return s.GenerateSchema(spec) - } - - if err = generateSchema(baseSchemaID, schemaDir, "", config.Spec{}); err != nil { - return fmt.Errorf("unable to generate schema - %s", err) + return nil } if err = generateSchema(baseSchemaID, schemaDir, "policy/manifest", config.Spec{}); err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/reports/action.go new/updatecli-0.102.0/pkg/core/reports/action.go --- old/updatecli-0.101.0/pkg/core/reports/action.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/reports/action.go 2025-06-13 09:15:32.000000000 +0200 @@ -5,6 +5,7 @@ "encoding/xml" "fmt" "sort" + "strings" "text/template" "github.com/sirupsen/logrus" @@ -110,8 +111,21 @@ } } +// updateTargetDescriptions updates descriptions from being console friendly to markdown friendly +func (a *Action) updateTargetDescriptions() { + for id, target := range a.Targets { + d := target.Description + d = strings.Replace(d, "\n\t*", "\n\n*", 1) + d = strings.ReplaceAll(d, "\n\t*", "\n*") + a.Targets[id].Description = d + } +} + // ToActionsString show an action report formatted as a string func (a Action) ToActionsString() string { + a.sort() + a.updateTargetDescriptions() + output, err := xml.MarshalIndent( Actions{ Actions: []Action{ @@ -127,6 +141,8 @@ // ToActionsMarkdownString show an action report formatted as a string using markdown func (a Action) ToActionsMarkdownString() string { + a.updateTargetDescriptions() + tmpl, err := template.New("actions").Parse(markdownReportTemplate) if err != nil { logrus.Errorf("error: %v\n", err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/reports/action_markdown_template.go new/updatecli-0.102.0/pkg/core/reports/action_markdown_template.go --- old/updatecli-0.101.0/pkg/core/reports/action_markdown_template.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/reports/action_markdown_template.go 2025-06-13 09:15:32.000000000 +0200 @@ -3,10 +3,14 @@ // markdownReportTemplate is the Go template used to generate markdown report var markdownReportTemplate string = `# {{ .PipelineTitle }} +Pipeline ID: ` + "`" + `{{ .ID }}` + "`" + ` + {{- range .Targets}} ## {{ .Title }} +Target ID: ` + "`" + `{{ .ID }}` + "`" + ` + {{- if .Description }} {{ .Description }} @@ -29,5 +33,5 @@ {{- if .PipelineURL }} -[{{ .PipelineURL.Name }}]({{ .PipelineURL.URL }}) +Pipeline URL: [{{ .PipelineURL.Name }}]({{ .PipelineURL.URL }}) {{- end}}` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/reports/action_test.go new/updatecli-0.102.0/pkg/core/reports/action_test.go --- old/updatecli-0.101.0/pkg/core/reports/action_test.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/reports/action_test.go 2025-06-13 09:15:32.000000000 +0200 @@ -366,12 +366,12 @@ }, }, { - ID: "4567", + ID: "4568", Title: "Target Two", Description: "Description", }, { - ID: "4567", + ID: "4569", Title: "Target Three", Changelogs: []ActionTargetChangelog{ { @@ -384,18 +384,26 @@ }, expectedOutput: `# Test Title +Pipeline ID: ` + "`" + `1234` + "`" + ` + ## Target One +Target ID: ` + "`" + `4567` + "`" + ` + ### 1.0.0 ### 1.0.1 ## Target Two +Target ID: ` + "`" + `4568` + "`" + ` + Description ## Target Three +Target ID: ` + "`" + `4569` + "`" + ` + ### 1.0.0 ` + "```" + ` @@ -403,6 +411,94 @@ ` + "```", }, { + name: "Multiline", + report: Action{ + ID: "1234", + Title: "Action Title", + PipelineTitle: "Test Title", + Targets: []ActionTarget{ + { + ID: "4567", + Title: "Target One", + Description: "Something happened\n\t* to this file", + Changelogs: []ActionTargetChangelog{ + { + Title: "1.0.0", + Description: "# v1.0.0\n\nfeat: something cool", + }, + { + Title: "1.0.1", + Description: "# v1.0.1\n\nfix: something fixed", + }, + }, + }, + { + ID: "4568", + Title: "Target Two", + Description: "Something happened\n\t* to this other file\n\t* and this other file", + }, + { + ID: "4569", + Title: "Target Three", + Changelogs: []ActionTargetChangelog{ + { + Title: "1.0.0", + Description: "# v1.0.0\n\nfeat: something cool", + }, + }, + }, + }, + }, + expectedOutput: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +Something happened + +* to this file + +### 1.0.0 + +` + "```" + ` +# v1.0.0 + +feat: something cool +` + "```" + ` + +### 1.0.1 + +` + "```" + ` +# v1.0.1 + +fix: something fixed +` + "```" + ` + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +Something happened + +* to this other file +* and this other file + +## Target Three + +Target ID: ` + "`" + `4569` + "`" + ` + +### 1.0.0 + +` + "```" + ` +# v1.0.0 + +feat: something cool +` + "```", + }, + { name: "with PipelineUrl", report: Action{ ID: "1234", @@ -428,12 +524,12 @@ }, }, { - ID: "4567", + ID: "4568", Title: "Target Two", Description: "Description", }, { - ID: "4567", + ID: "4569", Title: "Target Three", Changelogs: []ActionTargetChangelog{ { @@ -446,31 +542,48 @@ }, expectedOutput: `# Test Title +Pipeline ID: ` + "`" + `1234` + "`" + ` + ## Target One +Target ID: ` + "`" + `4567` + "`" + ` + ### 1.0.0 ### 1.0.1 ## Target Two +Target ID: ` + "`" + `4568` + "`" + ` + Description ## Target Three +Target ID: ` + "`" + `4569` + "`" + ` + ### 1.0.0 ` + "```" + ` Description ` + "```" + ` -[updatecli](https://www.updatecli.io/)`, +Pipeline URL: [updatecli](https://www.updatecli.io/)`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expectedOutput, tt.report.ToActionsMarkdownString()) + markdown := tt.report.ToActionsMarkdownString() + assert.Equal(t, tt.expectedOutput, markdown) + + // roundtrip to ensure no information loss + var newReport Actions + err := markdownToActions(markdown, &newReport) + assert.Nil(t, err) + newReport.Actions[0].Title = "Action Title" + + assert.Equal(t, &Actions{Actions: []Action{tt.report}}, &newReport) }) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/reports/actions.go new/updatecli-0.102.0/pkg/core/reports/actions.go --- old/updatecli-0.101.0/pkg/core/reports/actions.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/reports/actions.go 2025-06-13 09:15:32.000000000 +0200 @@ -1,11 +1,16 @@ package reports import ( + "bytes" "encoding/xml" "fmt" "sort" + "strings" "github.com/sirupsen/logrus" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" ) type Actions struct { @@ -106,3 +111,152 @@ } return nil } + +func markdownToActions(input string, actions *Actions) error { + source := []byte(input) + + actionCount := -1 + actionTargetCount := -1 + actionTargetChangeLogCount := -1 + + md := goldmark.New() + node := md.Parser().Parse(text.NewReader(source)) + + err := ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + switch n := n.(type) { + case *ast.Heading: + title := string(n.Lines().Value(source)) + + switch n.Level { + case 1: + action := Action{ + PipelineTitle: title, + } + actions.Actions = append(actions.Actions, action) + actionCount++ + actionTargetCount = -1 + actionTargetChangeLogCount = -1 + case 2: + actionTarget := ActionTarget{ + Title: title, + } + actions.Actions[actionCount].Targets = append(actions.Actions[actionCount].Targets, actionTarget) + actionTargetCount++ + actionTargetChangeLogCount = -1 + case 3: + actionTargetChangelog := ActionTargetChangelog{ + Title: title, + } + actions.Actions[actionCount].Targets[actionTargetCount].Changelogs = append( + actions.Actions[actionCount].Targets[actionTargetCount].Changelogs, + actionTargetChangelog) + actionTargetChangeLogCount++ + } + return ast.WalkSkipChildren, nil + case *ast.Paragraph: + contents := n.Lines().Value(source) + if child, ok := n.FirstChild().(*ast.Text); ok { + switch string(child.Value(source)) { + case "Pipeline ID: ": + if sibling, ok := child.NextSibling().(*ast.CodeSpan); ok { + if codespanValue, ok := sibling.FirstChild().(*ast.Text); ok { + actions.Actions[actionCount].ID = string(codespanValue.Value(source)) + } + } + return ast.WalkSkipChildren, nil + case "Target ID: ": + if sibling, ok := child.NextSibling().(*ast.CodeSpan); ok { + if codespanValue, ok := sibling.FirstChild().(*ast.Text); ok { + actions.Actions[actionCount].Targets[actionTargetCount].ID = string(codespanValue.Value(source)) + } + } + return ast.WalkSkipChildren, nil + case "Pipeline URL: ": + if sibling, ok := child.NextSibling().(*ast.Link); ok { + var name string + if codespanValue, ok := sibling.FirstChild().(*ast.Text); ok { + name = string(codespanValue.Value(source)) + } + actions.Actions[actionCount].PipelineURL = &PipelineURL{ + Name: name, + URL: string(sibling.Destination), + } + } + return ast.WalkSkipChildren, nil + } + } + if actionCount > -1 && actionTargetCount > -1 { + actions.Actions[actionCount].Targets[actionTargetCount].Description = string(contents) + return ast.WalkSkipChildren, nil + } + case *ast.FencedCodeBlock: + if actionTargetChangeLogCount > -1 { + contents := n.Lines().Value(source) + actions.Actions[actionCount].Targets[actionTargetCount].Changelogs[actionTargetChangeLogCount].Description = strings.TrimSpace(string(contents)) + return ast.WalkSkipChildren, nil + } + case *ast.List: + if actionCount > -1 && actionTargetCount > -1 { + var buf bytes.Buffer + for children := n.FirstChild(); children != nil; children = children.NextSibling() { + if listValue, ok := children.FirstChild().(*ast.TextBlock); ok { + buf.Write([]byte("\n* ")) + buf.Write(listValue.Lines().Value(source)) + } + } + actions.Actions[actionCount].Targets[actionTargetCount].Description += "\n" + actions.Actions[actionCount].Targets[actionTargetCount].Description += buf.String() + return ast.WalkSkipChildren, nil + } + case *ast.ThematicBreak: + // start of footer stop processing + return ast.WalkStop, nil + } + + return ast.WalkContinue, nil + }) + if err != nil { + return err + } + + return nil +} + +func MergeFromMarkdown(old, new string) (string, error) { + var oldReport Actions + var newReport Actions + + if old == "" && new != "" { + return new, nil + } + + if old != "" && new == "" { + return old, nil + } + + if err := markdownToActions(old, &oldReport); err != nil { + return "", err + } + + if err := markdownToActions(new, &newReport); err != nil { + return "", err + } + + newReport.Merge(&oldReport) + newReport.sort() + + var report string + + for i, action := range newReport.Actions { + if i > 0 { + report += "\n\n" + } + r := action.ToActionsMarkdownString() + report += r + } + + return report, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/core/reports/actions_test.go new/updatecli-0.102.0/pkg/core/reports/actions_test.go --- old/updatecli-0.101.0/pkg/core/reports/actions_test.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/core/reports/actions_test.go 2025-06-13 09:15:32.000000000 +0200 @@ -1629,3 +1629,233 @@ }) } } + +func TestMergeFromMarkdown(t *testing.T) { + tests := []struct { + name string + oldReport string + newReport string + expectedFinalReport string + }{ + { + name: "Default none situation", + oldReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1 + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + newReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1 + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + expectedFinalReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1 + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + }, + { + name: "Test target merge", + oldReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1`, + newReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + expectedFinalReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1 + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + }, + { + name: "Test that old report includes unexpected text", + oldReport: `This is not a markdown expected format + +# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + newReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + expectedFinalReport: `# Test Title + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + }, + { + name: "Test Pipeline merge", + oldReport: `# Old Pipeline + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1`, + newReport: `# New Pipeline + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + expectedFinalReport: `# New Pipeline + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1 + +## Target Two + +Target ID: ` + "`" + `4568` + "`" + ` + +## Target Three + +Target ID: ` + "`" + `4569` + "`", + }, + { + name: "No merge needed", + newReport: `# New Pipeline + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1`, + oldReport: "", + expectedFinalReport: `# New Pipeline + +Pipeline ID: ` + "`" + `1234` + "`" + ` + +## Target One + +Target ID: ` + "`" + `4567` + "`" + ` + +### 1.0.0 + +### 1.0.1`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotFinalReport, err := MergeFromMarkdown(tt.oldReport, tt.newReport) + assert.Nil(t, err) + assert.Equal(t, tt.expectedFinalReport, gotFinalReport) + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/plugins/autodiscovery/argocd/main_test.go new/updatecli-0.102.0/pkg/plugins/autodiscovery/argocd/main_test.go --- old/updatecli-0.101.0/pkg/plugins/autodiscovery/argocd/main_test.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/plugins/autodiscovery/argocd/main_test.go 2025-06-13 09:15:32.000000000 +0200 @@ -11,6 +11,8 @@ testdata := []struct { name string rootDir string + actionID string + scmID string expectedPipelines []string }{ { @@ -101,6 +103,55 @@ `}, }, { + name: "ArgoCD manifests discovery with several sources and both action and scm IDs", + rootDir: "testdata/sealed-secrets_sources", + actionID: "argoRepo", + scmID: "scm123", + expectedPipelines: []string{`name: 'deps(helm): bump Helm chart "sealed-secrets" in ArgoCD manifest "manifest.yaml"' +actions: + argoRepo: + title: 'deps(argocd): update Helm chart sealed-secrets to {{ source "sealed-secrets" }}' +sources: + sealed-secrets: + name: 'Get latest "sealed-secrets" Helm chart version' + kind: 'helmchart' + spec: + name: 'sealed-secrets' + url: 'https://bitnami-labs.github.io/sealed-secrets' + versionfilter: + kind: 'semver' + pattern: '*' +conditions: + sealed-secrets-name: + name: 'Ensure Helm chart name sealed-secrets is specified' + kind: 'yaml' + disablesourceinput: true + scmid: scm123 + spec: + file: 'manifest.yaml' + key: '$.spec.sources[0].chart' + value: 'sealed-secrets' + sealed-secrets-repository: + name: 'Ensure Helm chart repository https://bitnami-labs.github.io/sealed-secrets is specified' + kind: 'yaml' + disablesourceinput: true + scmid: scm123 + spec: + file: 'manifest.yaml' + key: '$.spec.sources[0].repoURL' + value: 'https://bitnami-labs.github.io/sealed-secrets' +targets: + sealed-secrets: + name: 'deps(helm): update Helm chart "sealed-secrets" to {{ source "sealed-secrets" }}' + kind: 'yaml' + scmid: scm123 + spec: + file: 'manifest.yaml' + key: '$.spec.sources[0].targetRevision' + sourceid: 'sealed-secrets' +`}, + }, + { name: "ArgoCD manifests discovery with OCI source", rootDir: "testdata/oci-helm-source", expectedPipelines: []string{`name: 'deps(helm): bump Helm chart "nginx" in ArgoCD manifest "manifest.yaml"' @@ -147,7 +198,7 @@ t.Run(tt.name, func(t *testing.T) { argocd, err := New( - Spec{}, tt.rootDir, "", "") + Spec{}, tt.rootDir, tt.scmID, tt.actionID) require.NoError(t, err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/plugins/autodiscovery/argocd/manifestTemplate.go new/updatecli-0.102.0/pkg/plugins/autodiscovery/argocd/manifestTemplate.go --- old/updatecli-0.101.0/pkg/plugins/autodiscovery/argocd/manifestTemplate.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/plugins/autodiscovery/argocd/manifestTemplate.go 2025-06-13 09:15:32.000000000 +0200 @@ -6,8 +6,8 @@ {{- if .ActionID }} actions: {{ .ActionID }}: - title: 'deps: update Go version to {{ "{{" }} source "go" {{ "}}" }}' -{{ end }} + title: 'deps(argocd): update Helm chart {{ .ChartName }} to {{ "{{" }} source "{{ .SourceID }}" {{ "}}" }}' +{{- end }} sources: {{ .SourceID }}: name: '{{ .SourceName }}' @@ -25,7 +25,7 @@ disablesourceinput: true {{- if .ScmID }} scmid: {{ .ScmID }} -{{ end }} +{{- end }} spec: file: '{{ .File }}' key: '{{ .TargetKey }}.chart' @@ -36,7 +36,7 @@ disablesourceinput: true {{- if .ScmID }} scmid: {{ .ScmID }} -{{ end }} +{{- end }} spec: file: '{{ .File }}' key: '{{ .TargetKey }}.repoURL' @@ -47,7 +47,7 @@ kind: 'yaml' {{- if .ScmID }} scmid: {{ .ScmID }} -{{ end }} +{{- end }} spec: file: '{{ .File }}' key: '{{ .TargetKey }}.targetRevision' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/pkg/plugins/resources/bitbucket/pullrequest/create.go new/updatecli-0.102.0/pkg/plugins/resources/bitbucket/pullrequest/create.go --- old/updatecli-0.101.0/pkg/plugins/resources/bitbucket/pullrequest/create.go 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/pkg/plugins/resources/bitbucket/pullrequest/create.go 2025-06-13 09:15:32.000000000 +0200 @@ -22,18 +22,6 @@ title = b.spec.Title } - // One Bitbucket pull request body can contain multiple action report - // It would be better to refactor CreateAction to be able to reuse existing pull request description. - // similar to what we did for github pull request. - body, err := utils.GeneratePullRequestBodyMarkdown("", report.ToActionsMarkdownString()) - if err != nil { - logrus.Warningf("something went wrong while generating Bitbucket Pull Request body: %s", err) - } - - if len(b.spec.Body) > 0 { - body = b.spec.Body - } - // Test that both sourceBranch and targetBranch exists on remote before creating a new one ok, err := b.isRemoteBranchesExist() if err != nil { @@ -54,12 +42,6 @@ return nil } - logrus.Debugf("Title:\t%q\nBody:\t%q\nSource:\n%q\ntarget:\t%q\n", - title, - body, - b.SourceBranch, - b.TargetBranch) - pullRequestExists, pullRequestDetails, err := b.isPullRequestExist() if err != nil { return err @@ -67,6 +49,23 @@ var responseTitle, responseBody, responseLink string if pullRequestExists { + + mergedDescription, err := reports.MergeFromMarkdown(pullRequestDetails.Description, report.ToActionsMarkdownString()) + if err != nil { + return err + } + + body, err := utils.GeneratePullRequestBodyMarkdown("", mergedDescription) + if err != nil { + return err + } + + logrus.Debugf("Title:\t%q\nBody:\t%q\nSource:\n%q\nTarget:\t%q\n", + title, + body, + b.SourceBranch, + b.TargetBranch) + responseTitle, responseBody, responseLink, err = b.updatePullRequest(pullRequestDetails.Number, title, body) if err != nil { return err @@ -74,6 +73,22 @@ logrus.Infof("%s Bitbucket Cloud pull request successfully updated %q", result.SUCCESS, responseLink) } else { + + body, err := utils.GeneratePullRequestBodyMarkdown("", report.ToActionsMarkdownString()) + if err != nil { + logrus.Warningf("something went wrong while generating Bitbucket Pull Request body: %s", err) + } + + if len(b.spec.Body) > 0 { + body = b.spec.Body + } + + logrus.Debugf("Title:\t%q\nBody:\t%q\nSource:\n%q\nTarget:\t%q\n", + title, + body, + b.SourceBranch, + b.TargetBranch) + responseTitle, responseBody, responseLink, err = b.createPullRequest(title, body) if err != nil { return err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/updatecli-0.101.0/updatecli/updatecli.d/devcontainer.yaml new/updatecli-0.102.0/updatecli/updatecli.d/devcontainer.yaml --- old/updatecli-0.101.0/updatecli/updatecli.d/devcontainer.yaml 2025-05-30 09:06:30.000000000 +0200 +++ new/updatecli-0.102.0/updatecli/updatecli.d/devcontainer.yaml 2025-06-13 09:15:32.000000000 +0200 @@ -48,6 +48,7 @@ devcontainer: name: 'deps: update devcontainer to golang {{ source "golang" }}' kind: file + scmid: default spec: file: '.devcontainer/devcontainer.json' matchpattern: '"image": "mcr\.microsoft\.com/devcontainers/go:.*"' ++++++ updatecli.obsinfo ++++++ --- /var/tmp/diff_new_pack.5fXz73/_old 2025-06-13 18:48:07.829441189 +0200 +++ /var/tmp/diff_new_pack.5fXz73/_new 2025-06-13 18:48:07.829441189 +0200 @@ -1,5 +1,5 @@ name: updatecli -version: 0.101.0 -mtime: 1748588790 -commit: 86ea3f3f2b773121086ab701900843d999e29f6b +version: 0.102.0 +mtime: 1749798932 +commit: a6194320af7931b03cd9855f98e7f35938509cba ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/updatecli/vendor.tar.gz /work/SRC/openSUSE:Factory/.updatecli.new.19631/vendor.tar.gz differ: char 13, line 1