From 7fdc8c9c50d1b4a2b207e85e5c0a3e3ec6d2cbfa Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 21 Sep 2023 10:24:11 +0200 Subject: [PATCH 01/63] refactor: move examples --- .../common}/charts/backend/Chart.yaml | 0 .../charts/backend/templates/deployment.yaml | 2 +- .../charts/backend/templates/service.yaml | 2 +- _examples/common/charts/backend/values.yaml | 3 + .../common}/charts/frontend/Chart.yaml | 0 .../charts/frontend/templates/deployment.yaml | 2 +- .../charts/frontend/templates/service.yaml | 2 +- _examples/common/charts/frontend/values.yaml | 3 + .../common}/docker/backend.Dockerfile | 2 +- .../common}/docker/frontend.Dockerfile | 0 _examples/helloworld/Makefile | 59 +++++++++++++++ _examples/helloworld/app/go.mod | 3 + {example => _examples}/helloworld/app/main.go | 0 _examples/helloworld/squadron.yaml | 19 +++++ _examples/monorepo/Makefile | 61 ++++++++++++++++ .../squadrons/checkout}/backend/go.mod | 0 .../squadrons/checkout}/backend/main.go | 0 .../squadrons/checkout/backend/squadron.yaml | 17 +++++ .../squadrons/checkout}/frontend/index.html | 0 .../squadrons/checkout/frontend/squadron.yaml | 17 +++++ _examples/monorepo/squadrons/squadron.yaml | 6 ++ .../squadrons/storefinder/backend/go.mod | 3 + .../squadrons/storefinder/backend/main.go | 13 ++++ .../storefinder/backend/squadron.yaml | 17 +++++ .../squadrons/storefinder/frontend/index.html | 12 ++++ .../storefinder/frontend/squadron.yaml | 17 +++++ example/helloworld/app/Dockerfile | 11 --- example/helloworld/chart/Chart.yaml | 0 example/helloworld/squadron.yaml | 15 ---- example/monorepo/Makefile | 71 ------------------- example/monorepo/charts/backend/values.yaml | 3 - example/monorepo/charts/frontend/values.yaml | 3 - example/monorepo/squadrons/squadron.yaml | 20 ------ .../storefinder/backend/squadron.yaml | 16 ----- .../storefinder/frontend/squadron.yaml | 16 ----- .../squadrons/storefinder/squadron.yaml | 4 -- 36 files changed, 255 insertions(+), 164 deletions(-) rename {example/monorepo => _examples/common}/charts/backend/Chart.yaml (100%) rename {example/monorepo => _examples/common}/charts/backend/templates/deployment.yaml (97%) rename {example/monorepo => _examples/common}/charts/backend/templates/service.yaml (96%) create mode 100644 _examples/common/charts/backend/values.yaml rename {example/monorepo => _examples/common}/charts/frontend/Chart.yaml (100%) rename {example/monorepo => _examples/common}/charts/frontend/templates/deployment.yaml (97%) rename {example/monorepo => _examples/common}/charts/frontend/templates/service.yaml (96%) create mode 100644 _examples/common/charts/frontend/values.yaml rename {example/monorepo => _examples/common}/docker/backend.Dockerfile (88%) rename {example/monorepo => _examples/common}/docker/frontend.Dockerfile (100%) create mode 100644 _examples/helloworld/Makefile create mode 100644 _examples/helloworld/app/go.mod rename {example => _examples}/helloworld/app/main.go (100%) create mode 100644 _examples/helloworld/squadron.yaml create mode 100644 _examples/monorepo/Makefile rename {example/monorepo/squadrons/storefinder => _examples/monorepo/squadrons/checkout}/backend/go.mod (100%) rename {example/monorepo/squadrons/storefinder => _examples/monorepo/squadrons/checkout}/backend/main.go (100%) create mode 100644 _examples/monorepo/squadrons/checkout/backend/squadron.yaml rename {example/monorepo/squadrons/storefinder => _examples/monorepo/squadrons/checkout}/frontend/index.html (100%) create mode 100644 _examples/monorepo/squadrons/checkout/frontend/squadron.yaml create mode 100644 _examples/monorepo/squadrons/squadron.yaml create mode 100644 _examples/monorepo/squadrons/storefinder/backend/go.mod create mode 100644 _examples/monorepo/squadrons/storefinder/backend/main.go create mode 100644 _examples/monorepo/squadrons/storefinder/backend/squadron.yaml create mode 100644 _examples/monorepo/squadrons/storefinder/frontend/index.html create mode 100644 _examples/monorepo/squadrons/storefinder/frontend/squadron.yaml delete mode 100644 example/helloworld/app/Dockerfile delete mode 100644 example/helloworld/chart/Chart.yaml delete mode 100644 example/helloworld/squadron.yaml delete mode 100644 example/monorepo/Makefile delete mode 100644 example/monorepo/charts/backend/values.yaml delete mode 100644 example/monorepo/charts/frontend/values.yaml delete mode 100644 example/monorepo/squadrons/squadron.yaml delete mode 100644 example/monorepo/squadrons/storefinder/backend/squadron.yaml delete mode 100644 example/monorepo/squadrons/storefinder/frontend/squadron.yaml delete mode 100644 example/monorepo/squadrons/storefinder/squadron.yaml diff --git a/example/monorepo/charts/backend/Chart.yaml b/_examples/common/charts/backend/Chart.yaml similarity index 100% rename from example/monorepo/charts/backend/Chart.yaml rename to _examples/common/charts/backend/Chart.yaml diff --git a/example/monorepo/charts/backend/templates/deployment.yaml b/_examples/common/charts/backend/templates/deployment.yaml similarity index 97% rename from example/monorepo/charts/backend/templates/deployment.yaml rename to _examples/common/charts/backend/templates/deployment.yaml index d065a17..6e2bfee 100644 --- a/example/monorepo/charts/backend/templates/deployment.yaml +++ b/_examples/common/charts/backend/templates/deployment.yaml @@ -23,6 +23,6 @@ spec: - name: {{ .Release.Name }} image: {{ .Values.image.repository }}:{{ .Values.image.tag }} ports: - - + - name: http protocol: TCP containerPort: 80 diff --git a/example/monorepo/charts/backend/templates/service.yaml b/_examples/common/charts/backend/templates/service.yaml similarity index 96% rename from example/monorepo/charts/backend/templates/service.yaml rename to _examples/common/charts/backend/templates/service.yaml index f87c542..62043c5 100644 --- a/example/monorepo/charts/backend/templates/service.yaml +++ b/_examples/common/charts/backend/templates/service.yaml @@ -13,5 +13,5 @@ spec: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} ports: - - name: 80 + - name: http port: 80 diff --git a/_examples/common/charts/backend/values.yaml b/_examples/common/charts/backend/values.yaml new file mode 100644 index 0000000..ccf1216 --- /dev/null +++ b/_examples/common/charts/backend/values.yaml @@ -0,0 +1,3 @@ +image: + repository: nginx + tag: "latest" diff --git a/example/monorepo/charts/frontend/Chart.yaml b/_examples/common/charts/frontend/Chart.yaml similarity index 100% rename from example/monorepo/charts/frontend/Chart.yaml rename to _examples/common/charts/frontend/Chart.yaml diff --git a/example/monorepo/charts/frontend/templates/deployment.yaml b/_examples/common/charts/frontend/templates/deployment.yaml similarity index 97% rename from example/monorepo/charts/frontend/templates/deployment.yaml rename to _examples/common/charts/frontend/templates/deployment.yaml index d065a17..6e2bfee 100644 --- a/example/monorepo/charts/frontend/templates/deployment.yaml +++ b/_examples/common/charts/frontend/templates/deployment.yaml @@ -23,6 +23,6 @@ spec: - name: {{ .Release.Name }} image: {{ .Values.image.repository }}:{{ .Values.image.tag }} ports: - - + - name: http protocol: TCP containerPort: 80 diff --git a/example/monorepo/charts/frontend/templates/service.yaml b/_examples/common/charts/frontend/templates/service.yaml similarity index 96% rename from example/monorepo/charts/frontend/templates/service.yaml rename to _examples/common/charts/frontend/templates/service.yaml index f87c542..62043c5 100644 --- a/example/monorepo/charts/frontend/templates/service.yaml +++ b/_examples/common/charts/frontend/templates/service.yaml @@ -13,5 +13,5 @@ spec: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} ports: - - name: 80 + - name: http port: 80 diff --git a/_examples/common/charts/frontend/values.yaml b/_examples/common/charts/frontend/values.yaml new file mode 100644 index 0000000..ccf1216 --- /dev/null +++ b/_examples/common/charts/frontend/values.yaml @@ -0,0 +1,3 @@ +image: + repository: nginx + tag: "latest" diff --git a/example/monorepo/docker/backend.Dockerfile b/_examples/common/docker/backend.Dockerfile similarity index 88% rename from example/monorepo/docker/backend.Dockerfile rename to _examples/common/docker/backend.Dockerfile index 8407a4a..23b8a3b 100644 --- a/example/monorepo/docker/backend.Dockerfile +++ b/_examples/common/docker/backend.Dockerfile @@ -1,4 +1,4 @@ -FROM golang:alpine as base +FROM golang:alpine as builder ENV CGO_ENABLED=0 diff --git a/example/monorepo/docker/frontend.Dockerfile b/_examples/common/docker/frontend.Dockerfile similarity index 100% rename from example/monorepo/docker/frontend.Dockerfile rename to _examples/common/docker/frontend.Dockerfile diff --git a/_examples/helloworld/Makefile b/_examples/helloworld/Makefile new file mode 100644 index 0000000..10c5b3b --- /dev/null +++ b/_examples/helloworld/Makefile @@ -0,0 +1,59 @@ +.DEFAULT_GOAL:=help + +export PROJECT_ROOT=$(PWD) + +## === Tasks === + +.PHONY: list +## Show config +list: + @go run ../../cmd/main.go list + +.PHONY: config +## Show config +config: + @go run ../../cmd/main.go config + +.PHONY: build +## Show config +build: + @go run ../../cmd/main.go build + +.PHONY: template +## Show config +template: + @go run ../../cmd/main.go template + +## === Utils === + +## Show help text +help: + @awk '{ \ + if ($$0 ~ /^.PHONY: [a-zA-Z\-\_0-9]+$$/) { \ + helpCommand = substr($$0, index($$0, ":") + 2); \ + if (helpMessage) { \ + printf "\033[36m%-23s\033[0m %s\n", \ + helpCommand, helpMessage; \ + helpMessage = ""; \ + } \ + } else if ($$0 ~ /^[a-zA-Z\-\_0-9.]+:/) { \ + helpCommand = substr($$0, 0, index($$0, ":")); \ + if (helpMessage) { \ + printf "\033[36m%-23s\033[0m %s\n", \ + helpCommand, helpMessage"\n"; \ + helpMessage = ""; \ + } \ + } else if ($$0 ~ /^##/) { \ + if (helpMessage) { \ + helpMessage = helpMessage"\n "substr($$0, 3); \ + } else { \ + helpMessage = substr($$0, 3); \ + } \ + } else { \ + if (helpMessage) { \ + print "\n "helpMessage"\n" \ + } \ + helpMessage = ""; \ + } \ + }' \ + $(MAKEFILE_LIST) diff --git a/_examples/helloworld/app/go.mod b/_examples/helloworld/app/go.mod new file mode 100644 index 0000000..850fa2e --- /dev/null +++ b/_examples/helloworld/app/go.mod @@ -0,0 +1,3 @@ +module github.com/foomo/squadron/exmpale/helloworld + +go 1.21 diff --git a/example/helloworld/app/main.go b/_examples/helloworld/app/main.go similarity index 100% rename from example/helloworld/app/main.go rename to _examples/helloworld/app/main.go diff --git a/_examples/helloworld/squadron.yaml b/_examples/helloworld/squadron.yaml new file mode 100644 index 0000000..2a096fb --- /dev/null +++ b/_examples/helloworld/squadron.yaml @@ -0,0 +1,19 @@ +version: "2.0" + +squadron: + storefinder: + backend: + chart: <% env "PROJECT_ROOT" %>/../common/charts/backend + builds: + default: + tag: latest + context: <% env "PROJECT_ROOT" %>/app + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile + image: helloworld/app + values: + image: + tag: <% .Squadron.storefinder.backend.builds.default.tag | quote %> + repository: <% .Squadron.storefinder.backend.builds.default.image %> + service: + ports: + - 80 diff --git a/_examples/monorepo/Makefile b/_examples/monorepo/Makefile new file mode 100644 index 0000000..21164a4 --- /dev/null +++ b/_examples/monorepo/Makefile @@ -0,0 +1,61 @@ +.DEFAULT_GOAL:=help + +export PROJECT_ROOT=$(PWD) + +files=$(shell find . -name 'squadron.yaml' | tail -r | xargs echo -n | tr " ", ",") + +## === Tasks === + +.PHONY: list +## Show config +list: + @go run ../../cmd/main.go -f ${files} list + +.PHONY: config +## Show config +config: + @go run ../../cmd/main.go -f ${files} config + +.PHONY: build +## Show config +build: + @go run ../../cmd/main.go -f ${files} build + +.PHONY: template +## Show config +template: + @go run ../../cmd/main.go -f ${files} template + +## === Utils === + +## Show help text +help: + @awk '{ \ + if ($$0 ~ /^.PHONY: [a-zA-Z\-\_0-9]+$$/) { \ + helpCommand = substr($$0, index($$0, ":") + 2); \ + if (helpMessage) { \ + printf "\033[36m%-23s\033[0m %s\n", \ + helpCommand, helpMessage; \ + helpMessage = ""; \ + } \ + } else if ($$0 ~ /^[a-zA-Z\-\_0-9.]+:/) { \ + helpCommand = substr($$0, 0, index($$0, ":")); \ + if (helpMessage) { \ + printf "\033[36m%-23s\033[0m %s\n", \ + helpCommand, helpMessage"\n"; \ + helpMessage = ""; \ + } \ + } else if ($$0 ~ /^##/) { \ + if (helpMessage) { \ + helpMessage = helpMessage"\n "substr($$0, 3); \ + } else { \ + helpMessage = substr($$0, 3); \ + } \ + } else { \ + if (helpMessage) { \ + print "\n "helpMessage"\n" \ + } \ + helpMessage = ""; \ + } \ + }' \ + $(MAKEFILE_LIST) diff --git a/example/monorepo/squadrons/storefinder/backend/go.mod b/_examples/monorepo/squadrons/checkout/backend/go.mod similarity index 100% rename from example/monorepo/squadrons/storefinder/backend/go.mod rename to _examples/monorepo/squadrons/checkout/backend/go.mod diff --git a/example/monorepo/squadrons/storefinder/backend/main.go b/_examples/monorepo/squadrons/checkout/backend/main.go similarity index 100% rename from example/monorepo/squadrons/storefinder/backend/main.go rename to _examples/monorepo/squadrons/checkout/backend/main.go diff --git a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml new file mode 100644 index 0000000..df96fcd --- /dev/null +++ b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml @@ -0,0 +1,17 @@ +# Schema version +version: "2.0" + +squadron: + checkout: + backend: + chart: <% env "PROJECT_ROOT" %>/../common/charts/backend + builds: + default: + tag: <% .Global.docker.tag | quote %> + image: <% .Global.docker.registry %>/checkout-backend + context: <% env "PROJECT_ROOT" %>/squadrons/checkout/backend + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile + values: + image: + tag: <% .Global.docker.tag | quote %> + repository: <% .Squadron.checkout.backend.builds.default.image %> diff --git a/example/monorepo/squadrons/storefinder/frontend/index.html b/_examples/monorepo/squadrons/checkout/frontend/index.html similarity index 100% rename from example/monorepo/squadrons/storefinder/frontend/index.html rename to _examples/monorepo/squadrons/checkout/frontend/index.html diff --git a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml new file mode 100644 index 0000000..dca1fc0 --- /dev/null +++ b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml @@ -0,0 +1,17 @@ +# Schema version +version: "2.0" + +squadron: + checkout: + frontend: + chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend + builds: + default: + tag: "<% .Global.docker.tag %>" + image: <% .Global.docker.registry %>/checkout-frontend + context: <% env "PROJECT_ROOT" %>/squadrons/checkout/frontend + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend.Dockerfile + values: + image: + tag: "<% .Global.docker.tag %>" + repository: <% .Squadron.checkout.frontend.builds.default.image %> diff --git a/_examples/monorepo/squadrons/squadron.yaml b/_examples/monorepo/squadrons/squadron.yaml new file mode 100644 index 0000000..51b00a1 --- /dev/null +++ b/_examples/monorepo/squadrons/squadron.yaml @@ -0,0 +1,6 @@ +version: "2.0" + +global: + docker: + tag: "230101.0" + registry: monorepo diff --git a/_examples/monorepo/squadrons/storefinder/backend/go.mod b/_examples/monorepo/squadrons/storefinder/backend/go.mod new file mode 100644 index 0000000..d7d1b45 --- /dev/null +++ b/_examples/monorepo/squadrons/storefinder/backend/go.mod @@ -0,0 +1,3 @@ +module github.com/foomo/squadron/exmpale/monorepo/storefinder/backend + +go 1.16 diff --git a/_examples/monorepo/squadrons/storefinder/backend/main.go b/_examples/monorepo/squadrons/storefinder/backend/main.go new file mode 100644 index 0000000..55ca898 --- /dev/null +++ b/_examples/monorepo/squadrons/storefinder/backend/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + "net/http" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + _, _ = fmt.Fprintf(w, "hello") + }) + _ = http.ListenAndServe(":80", nil) +} diff --git a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml new file mode 100644 index 0000000..511e809 --- /dev/null +++ b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml @@ -0,0 +1,17 @@ +# Schema version +version: "2.0" + +squadron: + storefinder: + backend: + chart: <% env "PROJECT_ROOT" %>/../common/charts/backend + builds: + default: + tag: <% .Global.docker.tag | quote %> + image: <% .Global.docker.registry %>/storefinder-backend + context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/backend + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile + values: + image: + tag: <% .Global.docker.tag | quote %> + repository: <% .Squadron.storefinder.backend.builds.default.image %> diff --git a/_examples/monorepo/squadrons/storefinder/frontend/index.html b/_examples/monorepo/squadrons/storefinder/frontend/index.html new file mode 100644 index 0000000..f712531 --- /dev/null +++ b/_examples/monorepo/squadrons/storefinder/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +

Storefinder

+ + diff --git a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml new file mode 100644 index 0000000..6eb6297 --- /dev/null +++ b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml @@ -0,0 +1,17 @@ +# Schema version +version: "2.0" + +squadron: + storefinder: + frontend: + chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend + builds: + default: + tag: "<% .Global.docker.tag %>" + image: <% .Global.docker.registry %>/storefinder-frontend + context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/frontend + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend.Dockerfile + values: + image: + tag: "<% .Global.docker.tag %>" + repository: <% .Squadron.storefinder.frontend.builds.default.image %> diff --git a/example/helloworld/app/Dockerfile b/example/helloworld/app/Dockerfile deleted file mode 100644 index 7181694..0000000 --- a/example/helloworld/app/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM golang:alpine AS builder - -COPY main.go . - -RUN go build -o /helloworld . - -FROM alpine:latest - -COPY --from=builder /helloworld /helloworld - -ENTRYPOINT ["/helloworld"] \ No newline at end of file diff --git a/example/helloworld/chart/Chart.yaml b/example/helloworld/chart/Chart.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/example/helloworld/squadron.yaml b/example/helloworld/squadron.yaml deleted file mode 100644 index 8e6beeb..0000000 --- a/example/helloworld/squadron.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: "1.0" - -squadron: - app: - chart: ./chart - builds: - default: - tag: latest - context: ./app - image: helloworld/app - values: - image: "{{ .Squadron.app.builds.default.image }}:{{ .Squadron.app.builds.default.tag }}" - service: - ports: - - 80 diff --git a/example/monorepo/Makefile b/example/monorepo/Makefile deleted file mode 100644 index c188b47..0000000 --- a/example/monorepo/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -.DEFAULT_GOAL:=help - -export PROJECT_ROOT=$(PWD) - -storefinder.%:files=./squadrons/squadron.yaml,./squadrons/storefinder/squadron.yaml,./squadrons/storefinder/frontend/squadron.yaml,./squadrons/storefinder/backend/squadron.yaml - -.PHONY: storefinder.frontend.config -## Show config -storefinder.frontend.config: - @squadron -f ${files} config - -.PHONY: storefinder.frontend.template -## Show config -storefinder.frontend.template: - @squadron -f ${files} template - -.PHONY: storefinder.frontend.generate -## Generate helm chart -storefinder.frontend.generate: - @squadron -f ${files} generate - -storefinder.%:files=./squadrons/squadron.yaml,./squadrons/storefinder/squadron.yaml,./squadrons/storefinder/frontend/squadron.yaml,./squadrons/storefinder/backend/squadron.yaml - -.PHONY: storefinder.backend.config -## Show config -storefinder.backend.config: - @squadron -f ${files} config - -.PHONY: storefinder.backend.template -## Show template -storefinder.backend.template: - @squadron -f ${files} template - -.PHONY: storefinder.backend.generate -## Generate helm chart -storefinder.backend.generate: - @squadron -f ${files} generate - -## === Utils === - -## Show help text -help: - @awk '{ \ - if ($$0 ~ /^.PHONY: [a-zA-Z\-\_0-9]+$$/) { \ - helpCommand = substr($$0, index($$0, ":") + 2); \ - if (helpMessage) { \ - printf "\033[36m%-23s\033[0m %s\n", \ - helpCommand, helpMessage; \ - helpMessage = ""; \ - } \ - } else if ($$0 ~ /^[a-zA-Z\-\_0-9.]+:/) { \ - helpCommand = substr($$0, 0, index($$0, ":")); \ - if (helpMessage) { \ - printf "\033[36m%-23s\033[0m %s\n", \ - helpCommand, helpMessage"\n"; \ - helpMessage = ""; \ - } \ - } else if ($$0 ~ /^##/) { \ - if (helpMessage) { \ - helpMessage = helpMessage"\n "substr($$0, 3); \ - } else { \ - helpMessage = substr($$0, 3); \ - } \ - } else { \ - if (helpMessage) { \ - print "\n "helpMessage"\n" \ - } \ - helpMessage = ""; \ - } \ - }' \ - $(MAKEFILE_LIST) diff --git a/example/monorepo/charts/backend/values.yaml b/example/monorepo/charts/backend/values.yaml deleted file mode 100644 index 20b7595..0000000 --- a/example/monorepo/charts/backend/values.yaml +++ /dev/null @@ -1,3 +0,0 @@ -image: {} -# tag: null -# repository: null diff --git a/example/monorepo/charts/frontend/values.yaml b/example/monorepo/charts/frontend/values.yaml deleted file mode 100644 index 20b7595..0000000 --- a/example/monorepo/charts/frontend/values.yaml +++ /dev/null @@ -1,3 +0,0 @@ -image: {} -# tag: null -# repository: null diff --git a/example/monorepo/squadrons/squadron.yaml b/example/monorepo/squadrons/squadron.yaml deleted file mode 100644 index 692719d..0000000 --- a/example/monorepo/squadrons/squadron.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Schema version -version: "1.0" - -name: monorepo - -global: - docker: - tag: "211206.0" - registry: monorepo - -squadron: -# mongodb: -# chart: -# name: mongodb -# repository: https://charts.bitnami.com/bitnami -# version: 10.11.2 -# values: -# fullnameOverride: catalogue-mongodb -# auth: -# enabled: false diff --git a/example/monorepo/squadrons/storefinder/backend/squadron.yaml b/example/monorepo/squadrons/storefinder/backend/squadron.yaml deleted file mode 100644 index 3592cd3..0000000 --- a/example/monorepo/squadrons/storefinder/backend/squadron.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Schema version -version: "1.0" - -squadron: - backend: - chart: <% env "PROJECT_ROOT" %>/charts/backend - builds: - default: - tag: <% .Global.docker.tag | quote %> - image: <% .Global.docker.registry %>/storefinder-backend - context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/backend - dockefile: <% env "PROJECT_ROOT" %>/docker/backend.Dockerfile - values: - image: - tag: <% .Global.docker.tag | quote %> - repository: <% .Squadron.backend.builds.default.image %> diff --git a/example/monorepo/squadrons/storefinder/frontend/squadron.yaml b/example/monorepo/squadrons/storefinder/frontend/squadron.yaml deleted file mode 100644 index 54c6ad5..0000000 --- a/example/monorepo/squadrons/storefinder/frontend/squadron.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Schema version -version: "1.0" - -squadron: -# backend: -# chart: <% env "PROJECT_ROOT" %>/charts/frontend -# builds: -# default: -# tag: "<% .Global.docker.tag %>" -# image: <% .Global.docker.registry %>/storefinder-frontend -# context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/frontend -# dockefile: <% env "PROJECT_ROOT" %>/docker/frontend.Dockerfile -# values: -# image: -# tag: "<% .Global.docker.tag %>" -# repository: <% .Squadron.frontend.builds.default.image %> diff --git a/example/monorepo/squadrons/storefinder/squadron.yaml b/example/monorepo/squadrons/storefinder/squadron.yaml deleted file mode 100644 index b0813bc..0000000 --- a/example/monorepo/squadrons/storefinder/squadron.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# Schema version -version: "1.0" - -name: storefinder From 2b4348f7ddcbc2265e46b3a046cb6546d20aa2f8 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 21 Sep 2023 10:24:53 +0200 Subject: [PATCH 02/63] chore: change changelog --- .goreleaser.yml | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index cf4450a..1ffc920 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -26,36 +26,7 @@ archives: format: zip changelog: - filters: - exclude: - - "^wip" - - "^test" - - "^docs" - - "^chore" - - "^style" - - "go mod tidy" - - "merge conflict" - - "Merge pull request" - - "Merge remote-tracking branch" - - "Merge branch" - groups: - - title: Features - regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$' - order: 0 - - title: Dependency updates - regexp: '^.*?(feat|fix)\(deps\)!?:.+$' - order: 100 - - title: "Bug fixes" - regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$' - order: 150 - - title: "Security" - regexp: '^.*?sec(\([[:word:]]+\))??!?:.+$' - order: 200 - - title: "Performace" - regexp: '^.*?perf(\([[:word:]]+\))??!?:.+$' - order: 250 - - title: Other - order: 999 + use: github-native brews: # Repository to push the tap to. From 51f06aa761301caa7e172e46e14b11f06240125b Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 21 Sep 2023 10:25:10 +0200 Subject: [PATCH 03/63] chore: update test output --- Makefile | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index fb7c5b6..073a3e6 100644 --- a/Makefile +++ b/Makefile @@ -29,19 +29,12 @@ doc: .PHONY: test ## Run tests test: - @go test -v ./... + @go test -coverprofile=coverage.out -race -json ./... | gotestfmt .PHONY: test.update ## Run tests and update snapshots test.update: - go test -update ./... - -.PHONY: test.cover -## Run tests with coverage -test.cover: - @go test -v -coverprofile=coverage.out ./... - @go tool cover -func=coverage.out - @go tool cover -html=coverage.out + @go test -update -coverprofile=coverage.out -race -json ./... | gotestfmt .PHONY: lint ## Run linter @@ -65,12 +58,12 @@ outdated: ## Install binary install: - go build -o ${GOPATH}/bin/squadron cmd/main.go + @go build -o ${GOPATH}/bin/squadron cmd/main.go ## Build binary build: - mkdir -p bin - go build -o bin/squadron cmd/main.go + @mkdir -p bin + @go build -o bin/squadron cmd/main.go ## === Utils === From 2cc181ef3ac62385fd1aece35c72493f55762aa9 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 21 Sep 2023 10:25:28 +0200 Subject: [PATCH 04/63] test: update tests --- testdata/config-global/squadron.override.yaml | 4 -- testdata/config-global/squadron.yaml | 5 -- testdata/config-global/squadron.yaml.snapshot | 4 -- testdata/config-no-render/squadron.yaml | 37 -------------- .../config-no-render/squadron.yaml.snapshot | 35 ------------- testdata/config-no-values/squadron.yaml | 16 ------ .../config-no-values/squadron.yaml.snapshot | 15 ------ .../squadron.override.yaml | 4 -- testdata/config-override-null/squadron.yaml | 37 -------------- .../squadron.yaml.snapshot | 14 ------ .../config-override/squadron.override.yaml | 22 --------- testdata/config-override/squadron.yaml | 49 ------------------- .../config-override/squadron.yaml.snapshot | 32 ------------ testdata/config-simple/squadron.yaml | 1 - testdata/config-simple/squadron.yaml.snapshot | 1 - .../my-chart/Chart.yaml | 5 -- .../my-chart/values.yaml | 0 .../config-template-frontend/squadron.yaml | 39 --------------- .../squadron.yaml.snapshot | 21 -------- testdata/config-template/squadron.yaml | 43 ---------------- .../config-template/squadron.yaml.snapshot | 44 ----------------- testdata/global/squadron.override.yaml | 6 +++ testdata/global/squadron.yaml | 7 +++ testdata/override/squadron.override.yaml | 15 ++++++ testdata/override/squadron.yaml | 32 ++++++++++++ .../squadron.values.yaml} | 0 testdata/template/squadron.yaml | 38 ++++++++++++++ 27 files changed, 98 insertions(+), 428 deletions(-) delete mode 100644 testdata/config-global/squadron.override.yaml delete mode 100644 testdata/config-global/squadron.yaml delete mode 100644 testdata/config-global/squadron.yaml.snapshot delete mode 100644 testdata/config-no-render/squadron.yaml delete mode 100644 testdata/config-no-render/squadron.yaml.snapshot delete mode 100644 testdata/config-no-values/squadron.yaml delete mode 100644 testdata/config-no-values/squadron.yaml.snapshot delete mode 100644 testdata/config-override-null/squadron.override.yaml delete mode 100644 testdata/config-override-null/squadron.yaml delete mode 100644 testdata/config-override-null/squadron.yaml.snapshot delete mode 100644 testdata/config-override/squadron.override.yaml delete mode 100644 testdata/config-override/squadron.yaml delete mode 100644 testdata/config-override/squadron.yaml.snapshot delete mode 100644 testdata/config-simple/squadron.yaml delete mode 100644 testdata/config-simple/squadron.yaml.snapshot delete mode 100644 testdata/config-template-frontend/my-chart/Chart.yaml delete mode 100644 testdata/config-template-frontend/my-chart/values.yaml delete mode 100644 testdata/config-template-frontend/squadron.yaml delete mode 100644 testdata/config-template-frontend/squadron.yaml.snapshot delete mode 100644 testdata/config-template/squadron.yaml delete mode 100644 testdata/config-template/squadron.yaml.snapshot create mode 100644 testdata/global/squadron.override.yaml create mode 100644 testdata/global/squadron.yaml create mode 100644 testdata/override/squadron.override.yaml create mode 100644 testdata/override/squadron.yaml rename testdata/{config-template/values.yaml => template/squadron.values.yaml} (100%) create mode 100644 testdata/template/squadron.yaml diff --git a/testdata/config-global/squadron.override.yaml b/testdata/config-global/squadron.override.yaml deleted file mode 100644 index 1de0edc..0000000 --- a/testdata/config-global/squadron.override.yaml +++ /dev/null @@ -1,4 +0,0 @@ -version: "1.0" - -global: - foo: baz diff --git a/testdata/config-global/squadron.yaml b/testdata/config-global/squadron.yaml deleted file mode 100644 index f1f6439..0000000 --- a/testdata/config-global/squadron.yaml +++ /dev/null @@ -1,5 +0,0 @@ -version: "1.0" - -global: - foo: foo - bar: bar \ No newline at end of file diff --git a/testdata/config-global/squadron.yaml.snapshot b/testdata/config-global/squadron.yaml.snapshot deleted file mode 100644 index fdb5353..0000000 --- a/testdata/config-global/squadron.yaml.snapshot +++ /dev/null @@ -1,4 +0,0 @@ -global: - bar: bar - foo: baz -version: "1.0" diff --git a/testdata/config-no-render/squadron.yaml b/testdata/config-no-render/squadron.yaml deleted file mode 100644 index 4ccd5f7..0000000 --- a/testdata/config-no-render/squadron.yaml +++ /dev/null @@ -1,37 +0,0 @@ -version: "1.0" - -global: - host: mycompany.com - -squadron: - frontend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - default: - tag: latest - image: docker.mycompany.com/mycomapny/frontend - values: - image: - tag: <% .Squadron.frontend.builds.default.tag %> - repository: <% .Squadron.frontend.builds.default.image %> - env: <% env "SHELL" %> - global: <% .Global.host %> - base64: <% base64 "1234567890" %> - values: | - <% file "testdata/config-template/values.yaml" | indent 8 %> - frontend-admin: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - default: - tag: latest - image: docker.mycompany.com/mycomapny/frontend-admin - values: - image: - tag: <% .Squadron.frontend_admin.builds.default.tag %> - repository: <% .Squadron.frontend_admin.builds.default.image %> diff --git a/testdata/config-no-render/squadron.yaml.snapshot b/testdata/config-no-render/squadron.yaml.snapshot deleted file mode 100644 index 0815df0..0000000 --- a/testdata/config-no-render/squadron.yaml.snapshot +++ /dev/null @@ -1,35 +0,0 @@ -global: - host: mycompany.com -squadron: - frontend: - builds: - default: - image: docker.mycompany.com/mycomapny/frontend - tag: latest - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.1.0 - values: - base64: <% base64 "1234567890" %> - env: <% env "SHELL" %> - global: <% .Global.host %> - image: - repository: <% .Squadron.frontend.builds.default.image %> - tag: <% .Squadron.frontend.builds.default.tag %> - values: | - <% file "testdata/config-template/values.yaml" | indent 8 %> - frontend-admin: - builds: - default: - image: docker.mycompany.com/mycomapny/frontend-admin - tag: latest - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.1.0 - values: - image: - repository: <% .Squadron.frontend_admin.builds.default.image %> - tag: <% .Squadron.frontend_admin.builds.default.tag %> -version: "1.0" diff --git a/testdata/config-no-values/squadron.yaml b/testdata/config-no-values/squadron.yaml deleted file mode 100644 index 71f1cad..0000000 --- a/testdata/config-no-values/squadron.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: "1.0" - -squadron: - frontend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - service: - tag: latest - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - args: - - "foo=foo" - - "bar=bar" diff --git a/testdata/config-no-values/squadron.yaml.snapshot b/testdata/config-no-values/squadron.yaml.snapshot deleted file mode 100644 index 6c7bb63..0000000 --- a/testdata/config-no-values/squadron.yaml.snapshot +++ /dev/null @@ -1,15 +0,0 @@ -squadron: - frontend: - builds: - service: - args: - - foo=foo - - bar=bar - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - tag: latest - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.1.0 -version: "1.0" diff --git a/testdata/config-override-null/squadron.override.yaml b/testdata/config-override-null/squadron.override.yaml deleted file mode 100644 index 108772f..0000000 --- a/testdata/config-override-null/squadron.override.yaml +++ /dev/null @@ -1,4 +0,0 @@ -version: "1.0" - -squadron: - frontend: ~ diff --git a/testdata/config-override-null/squadron.yaml b/testdata/config-override-null/squadron.yaml deleted file mode 100644 index a0e8ecd..0000000 --- a/testdata/config-override-null/squadron.yaml +++ /dev/null @@ -1,37 +0,0 @@ -version: "1.0" - -squadron: - backend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - values: - ingress: - hosts: - - name: mycompany.com - path: / - port: 80 - frontend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - service: - tag: latest - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - args: - - "foo=foo" - - "bar=bar" - values: - image: docker.mycompany.com/mycomapny/frontend:latest - service: - ports: - - 80 - ingress: - hosts: - - name: mycompany.com - path: / - port: 80 diff --git a/testdata/config-override-null/squadron.yaml.snapshot b/testdata/config-override-null/squadron.yaml.snapshot deleted file mode 100644 index d188ad2..0000000 --- a/testdata/config-override-null/squadron.yaml.snapshot +++ /dev/null @@ -1,14 +0,0 @@ -squadron: - backend: - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.1.0 - values: - ingress: - hosts: - - name: mycompany.com - path: / - port: 80 - frontend: null -version: "1.0" diff --git a/testdata/config-override/squadron.override.yaml b/testdata/config-override/squadron.override.yaml deleted file mode 100644 index 305267c..0000000 --- a/testdata/config-override/squadron.override.yaml +++ /dev/null @@ -1,22 +0,0 @@ -version: "1.0" - -squadron: - frontend: - chart: - version: 0.2.0 - builds: - service: - tag: 0.2.0 - args: - - "bar=baz" - - "baz=baz" - values: - service: - ports: - - 8080 - ingress: - hosts: - - name: mycompany.com - path: /foo - port: 8080 - backend: ~ \ No newline at end of file diff --git a/testdata/config-override/squadron.yaml b/testdata/config-override/squadron.yaml deleted file mode 100644 index 558e76a..0000000 --- a/testdata/config-override/squadron.yaml +++ /dev/null @@ -1,49 +0,0 @@ -version: "1.0" - -squadron: - frontend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - service: - tag: latest - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - args: - - "foo=foo" - - "bar=bar" - values: - image: docker.mycompany.com/mycomapny/frontend:latest - service: - ports: - - 80 - ingress: - hosts: - - name: mycompany.com - path: / - port: 80 - backend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - service: - tag: latest - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - args: - - "foo=foo" - - "bar=bar" - values: - image: docker.mycompany.com/mycomapny/frontend:latest - service: - ports: - - 80 - ingress: - hosts: - - name: mycompany.com - path: / - port: 80 diff --git a/testdata/config-override/squadron.yaml.snapshot b/testdata/config-override/squadron.yaml.snapshot deleted file mode 100644 index 76a9e94..0000000 --- a/testdata/config-override/squadron.yaml.snapshot +++ /dev/null @@ -1,32 +0,0 @@ -squadron: - backend: null - frontend: - builds: - service: - args: - - foo=foo - - bar=bar - - bar=baz - - baz=baz - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - tag: 0.2.0 - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.2.0 - values: - image: docker.mycompany.com/mycomapny/frontend:latest - ingress: - hosts: - - name: mycompany.com - path: / - port: 80 - - name: mycompany.com - path: /foo - port: 8080 - service: - ports: - - 80 - - 8080 -version: "1.0" diff --git a/testdata/config-simple/squadron.yaml b/testdata/config-simple/squadron.yaml deleted file mode 100644 index d847aec..0000000 --- a/testdata/config-simple/squadron.yaml +++ /dev/null @@ -1 +0,0 @@ -version: "1.0" diff --git a/testdata/config-simple/squadron.yaml.snapshot b/testdata/config-simple/squadron.yaml.snapshot deleted file mode 100644 index d847aec..0000000 --- a/testdata/config-simple/squadron.yaml.snapshot +++ /dev/null @@ -1 +0,0 @@ -version: "1.0" diff --git a/testdata/config-template-frontend/my-chart/Chart.yaml b/testdata/config-template-frontend/my-chart/Chart.yaml deleted file mode 100644 index 94f8bf8..0000000 --- a/testdata/config-template-frontend/my-chart/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: Dummy chart -name: my-chart -version: 0.1.0 diff --git a/testdata/config-template-frontend/my-chart/values.yaml b/testdata/config-template-frontend/my-chart/values.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/testdata/config-template-frontend/squadron.yaml b/testdata/config-template-frontend/squadron.yaml deleted file mode 100644 index dd77615..0000000 --- a/testdata/config-template-frontend/squadron.yaml +++ /dev/null @@ -1,39 +0,0 @@ -version: "1.0" - -global: - host: mycompany.com - -squadron: - frontend: - chart: ./testdata/config-template-frontend/my-chart -# chart: -# name: mychart -# version: 0.1.0 -# repository: http://helm.mycompany.com/repository - builds: - default: - tag: latest - image: docker.mycompany.com/mycomapny/frontend - values: - image: - tag: <% .Squadron.frontend.builds.default.tag %> - repository: <% .Squadron.frontend.builds.default.image %> - env: - ENV: <% env "SHELL" %> - GLOBAL: <% .Global.host %> - BASE64: <% base64 "1234567890" %> - frontend-admin: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - default: - tag: latest - image: docker.mycompany.com/mycomapny/frontend-admin - values: - image: - tag: <% .Squadron.frontend_admin.builds.default.tag %> - repository: <% .Squadron.frontend_admin.builds.default.image %> - env: - ENV: <% env "SHELL" %> diff --git a/testdata/config-template-frontend/squadron.yaml.snapshot b/testdata/config-template-frontend/squadron.yaml.snapshot deleted file mode 100644 index d9e7da1..0000000 --- a/testdata/config-template-frontend/squadron.yaml.snapshot +++ /dev/null @@ -1,21 +0,0 @@ -version: "1.0" -global: - host: mycompany.com -squadron: - frontend: - chart: - name: my-chart - repository: file://./testdata/config-template-frontend/my-chart - version: 0.1.0 - builds: - default: - image: docker.mycompany.com/mycomapny/frontend - tag: latest - values: - env: - BASE64: MTIzNDU2Nzg5MA== - ENV: /bin/zsh - GLOBAL: mycompany.com - image: - repository: docker.mycompany.com/mycomapny/frontend - tag: latest diff --git a/testdata/config-template/squadron.yaml b/testdata/config-template/squadron.yaml deleted file mode 100644 index 1c8f28e..0000000 --- a/testdata/config-template/squadron.yaml +++ /dev/null @@ -1,43 +0,0 @@ -version: "1.0" - -global: - host: mycompany.com - -squadron: - frontend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - default: - tag: latest - image: docker.mycompany.com/mycomapny/frontend - values: - image: - tag: <% .Squadron.frontend.builds.default.tag %> - repository: <% .Squadron.frontend.builds.default.image %> - env: - ENV: <% env "SHELL" %> - GLOBAL: <% .Global.host %> - BASE64: <% base64 "1234567890" %> - DEFAULT_VALUE: <% "" | default "fallback" %> - DEFAULT_INDEX_VALUE: <% defaultIndex .Global "notexists" "fallback" %> - # ONE_PASSWORD: <% op "ACCOUNT_NAME" "UUID" "FIELD" %> - # ONE_PASSWORD: <% op "ACCOUNT_NAME" "Secret name" "FIELD" %> - # ONE_PASSWORD: <% op "ACCOUNT_NAME" "Secret name wit global {{ .Global.host }}" "FIELD" %> - values: | - <% file "testdata/config-template/values.yaml" | indent 4 %> - frontend-admin: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - default: - tag: latest - image: docker.mycompany.com/mycomapny/frontend-admin - values: - image: - tag: <% .Squadron.frontend_admin.builds.default.tag %> - repository: <% .Squadron.frontend_admin.builds.default.image %> diff --git a/testdata/config-template/squadron.yaml.snapshot b/testdata/config-template/squadron.yaml.snapshot deleted file mode 100644 index b34fd18..0000000 --- a/testdata/config-template/squadron.yaml.snapshot +++ /dev/null @@ -1,44 +0,0 @@ -global: - host: mycompany.com -squadron: - frontend: - builds: - default: - image: docker.mycompany.com/mycomapny/frontend - tag: latest - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.1.0 - values: - env: - BASE64: MTIzNDU2Nzg5MA== - DEFAULT_INDEX_VALUE: fallback - DEFAULT_VALUE: fallback - ENV: /bin/zsh - GLOBAL: mycompany.com - image: - repository: docker.mycompany.com/mycomapny/frontend - tag: latest - values: | - foo: bar - bar: - - foo - - bar - env: /bin/zsh - global: mycompany.com - base64: MTIzNDU2Nzg5MA== - frontend-admin: - builds: - default: - image: docker.mycompany.com/mycomapny/frontend-admin - tag: latest - chart: - name: mychart - repository: http://helm.mycompany.com/repository - version: 0.1.0 - values: - image: - repository: docker.mycompany.com/mycomapny/frontend-admin - tag: latest -version: "1.0" diff --git a/testdata/global/squadron.override.yaml b/testdata/global/squadron.override.yaml new file mode 100644 index 0000000..5bea499 --- /dev/null +++ b/testdata/global/squadron.override.yaml @@ -0,0 +1,6 @@ +version: "2.0" + +global: + foo: "two" + bar: ["two"] + baz: ~ diff --git a/testdata/global/squadron.yaml b/testdata/global/squadron.yaml new file mode 100644 index 0000000..b3e1540 --- /dev/null +++ b/testdata/global/squadron.yaml @@ -0,0 +1,7 @@ +version: "2.0" + +global: + foo: "one" + bar: ["one"] + baz: "one" + diff --git a/testdata/override/squadron.override.yaml b/testdata/override/squadron.override.yaml new file mode 100644 index 0000000..7e1d3ca --- /dev/null +++ b/testdata/override/squadron.override.yaml @@ -0,0 +1,15 @@ +version: "2.0" + +squadron: + storefinder: + frontend: + builds: + default: + # override element + tag: nightly + # append new element to array + args: + - "bar=baz" + - "baz=baz" + # override backend + backend: ~ diff --git a/testdata/override/squadron.yaml b/testdata/override/squadron.yaml new file mode 100644 index 0000000..1c016e1 --- /dev/null +++ b/testdata/override/squadron.yaml @@ -0,0 +1,32 @@ +version: "2.0" + +squadron: + storefinder: + frontend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + builds: + default: + tag: latest + dockerfile: Dockerfile + image: docker.mycompany.com/mycomapny/frontend + args: + - "foo=foo" + - "bar=bar" + values: + image: + tag: <% .Squadron.storefinder.frontend.builds.default.tag %> + repository: <% .Squadron.storefinder.frontend.builds.default.image %> + backend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/backend + builds: + default: + tag: latest + dockerfile: Dockerfile + image: docker.mycompany.com/mycomapny/backend + args: + - "foo=foo" + - "bar=bar" + values: + image: + tag: <% .Squadron.storefinder.backend.builds.default.tag %> + repository: <% .Squadron.storefinder.backend.builds.default.image %> diff --git a/testdata/config-template/values.yaml b/testdata/template/squadron.values.yaml similarity index 100% rename from testdata/config-template/values.yaml rename to testdata/template/squadron.values.yaml diff --git a/testdata/template/squadron.yaml b/testdata/template/squadron.yaml new file mode 100644 index 0000000..6af8c63 --- /dev/null +++ b/testdata/template/squadron.yaml @@ -0,0 +1,38 @@ +version: "2.0" + +global: + host: mycompany.com + +squadron: + storefinder: + frontend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + builds: + default: + tag: latest + image: docker.mycompany.com/mycomapny/frontend + values: + image: + tag: <% .Squadron.storefinder.frontend.builds.default.tag %> + repository: <% .Squadron.storefinder.frontend.builds.default.image %> + env: + ENV: <% env "SHELL" %> + GLOBAL: <% .Global.host %> + BASE64: <% base64 "1234567890" %> + DEFAULT_VALUE: <% "" | default "fallback" %> + DEFAULT_INDEX_VALUE: <% defaultIndex .Global "notexists" "fallback" %> + # ONE_PASSWORD: <% op "ACCOUNT_NAME" "UUID" "FIELD" %> + # ONE_PASSWORD: <% op "ACCOUNT_NAME" "Secret name" "FIELD" %> + # ONE_PASSWORD: <% op "ACCOUNT_NAME" "Secret name wit global {{ .Global.host }}" "FIELD" %> + values: | + <% file "testdata/template/squadron.values.yaml" | indent 5 %> + backend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/backend + builds: + default: + tag: latest + image: docker.mycompany.com/mycomapny/frontend-admin + values: + image: + tag: <% .Squadron.storefinder.backend.builds.default.tag %> + repository: <% .Squadron.storefinder.backend.builds.default.image %> From c0c52b85d9b55a6a80a9b67196a16b1072f1d65a Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 21 Sep 2023 10:25:54 +0200 Subject: [PATCH 05/63] feat: add squadron name to schema --- chart.go | 92 --- cmd/actions/build.go | 95 +-- cmd/actions/config.go | 43 +- cmd/actions/diff.go | 45 + cmd/actions/down.go | 32 +- cmd/actions/generate.go | 44 - cmd/actions/list.go | 44 +- cmd/actions/push.go | 102 +-- cmd/actions/rollback.go | 46 +- cmd/actions/root.go | 43 +- cmd/actions/status.go | 46 +- cmd/actions/template.go | 58 +- cmd/actions/up.go | 147 +--- configuration.go | 38 - go.mod | 29 +- go.sum | 203 +---- init.go | 15 + build.go => internal/config/build.go | 22 +- internal/config/config.go | 31 + internal/config/doc.go | 1 + internal/config/map.go | 93 +++ internal/config/map_test.go | 50 ++ unit.go => internal/config/unit.go | 39 +- internal/config/units.go | 3 + internal/helm/chart.go | 41 + internal/helm/depency.go | 45 + internal/helm/doc.go | 27 + internal/template/default.go | 16 + internal/template/encode.go | 9 + internal/template/env.go | 22 + internal/template/file.go | 23 + internal/template/format.go | 18 + internal/template/git.go | 28 + .../template/onepassword.go | 307 ++----- internal/template/template.go | 35 + internal/template/vars.go | 7 + {tests/utils => internal/testutils}/flag.go | 0 internal/testutils/snapshot.go | 36 + {util => internal/util}/cmd.go | 7 +- {util => internal/util}/docker.go | 0 internal/util/helm.go | 9 + internal/util/highlight.go | 47 ++ {util => internal/util}/kube.go | 0 internal/util/path.go | 23 + internal/util/strings.go | 17 + util/misc.go => internal/util/yaml.go | 22 +- squadron.go | 777 +++++++++--------- squadron_test.go | 151 ++-- testdata/blank/snapshop-config-norender.yaml | 1 + testdata/blank/snapshop-config.yaml | 1 + testdata/blank/snapshop-template.yaml | 0 testdata/blank/squadron.yaml | 1 + testdata/global/snapshop-config-norender.yaml | 7 + testdata/global/snapshop-config.yaml | 7 + testdata/global/snapshop-template.yaml | 0 .../override/snapshop-config-norender.yaml | 22 + testdata/override/snapshop-config.yaml | 22 + testdata/override/snapshop-template.yaml | 49 ++ testdata/simple/snapshop-config-norender.yaml | 12 + testdata/simple/snapshop-config.yaml | 12 + testdata/simple/snapshop-template.yaml | 49 ++ testdata/simple/squadron.yaml | 10 + .../template/snapshop-config-norender.yaml | 39 + testdata/template/snapshop-config.yaml | 45 + testdata/template/snapshop-template.yaml | 98 +++ tests/utils/must.go | 14 - tests/utils/snapshot.go | 34 - units.go | 62 -- util/helm.go | 21 - 69 files changed, 1819 insertions(+), 1715 deletions(-) delete mode 100644 chart.go create mode 100644 cmd/actions/diff.go delete mode 100644 cmd/actions/generate.go delete mode 100644 configuration.go create mode 100644 init.go rename build.go => internal/config/build.go (91%) create mode 100644 internal/config/config.go create mode 100644 internal/config/doc.go create mode 100644 internal/config/map.go create mode 100644 internal/config/map_test.go rename unit.go => internal/config/unit.go (58%) create mode 100644 internal/config/units.go create mode 100644 internal/helm/chart.go create mode 100644 internal/helm/depency.go create mode 100644 internal/helm/doc.go create mode 100644 internal/template/default.go create mode 100644 internal/template/encode.go create mode 100644 internal/template/env.go create mode 100644 internal/template/file.go create mode 100644 internal/template/format.go create mode 100644 internal/template/git.go rename template.go => internal/template/onepassword.go (58%) create mode 100644 internal/template/template.go create mode 100644 internal/template/vars.go rename {tests/utils => internal/testutils}/flag.go (100%) create mode 100644 internal/testutils/snapshot.go rename {util => internal/util}/cmd.go (95%) rename {util => internal/util}/docker.go (100%) create mode 100644 internal/util/helm.go create mode 100644 internal/util/highlight.go rename {util => internal/util}/kube.go (100%) create mode 100644 internal/util/path.go create mode 100644 internal/util/strings.go rename util/misc.go => internal/util/yaml.go (50%) create mode 100644 testdata/blank/snapshop-config-norender.yaml create mode 100644 testdata/blank/snapshop-config.yaml create mode 100644 testdata/blank/snapshop-template.yaml create mode 100644 testdata/blank/squadron.yaml create mode 100644 testdata/global/snapshop-config-norender.yaml create mode 100644 testdata/global/snapshop-config.yaml create mode 100644 testdata/global/snapshop-template.yaml create mode 100644 testdata/override/snapshop-config-norender.yaml create mode 100644 testdata/override/snapshop-config.yaml create mode 100644 testdata/override/snapshop-template.yaml create mode 100644 testdata/simple/snapshop-config-norender.yaml create mode 100644 testdata/simple/snapshop-config.yaml create mode 100644 testdata/simple/snapshop-template.yaml create mode 100644 testdata/simple/squadron.yaml create mode 100644 testdata/template/snapshop-config-norender.yaml create mode 100644 testdata/template/snapshop-config.yaml create mode 100644 testdata/template/snapshop-template.yaml delete mode 100644 tests/utils/must.go delete mode 100644 tests/utils/snapshot.go delete mode 100644 units.go delete mode 100644 util/helm.go diff --git a/chart.go b/chart.go deleted file mode 100644 index a8032b2..0000000 --- a/chart.go +++ /dev/null @@ -1,92 +0,0 @@ -package squadron - -import ( - "context" - "fmt" - "os" - "path" - - "github.com/pkg/errors" - "gopkg.in/yaml.v3" - - "github.com/foomo/squadron/util" -) - -type ChartDependency struct { - Name string `yaml:"name,omitempty"` - Repository string `yaml:"repository,omitempty"` - Version string `yaml:"version,omitempty"` - Alias string `yaml:"alias,omitempty"` -} - -func (cd *ChartDependency) UnmarshalYAML(value *yaml.Node) error { - switch value.Tag { - case TagMap: - type wrapper ChartDependency - return value.Decode((*wrapper)(cd)) - case TagString: - var vString string - if err := value.Decode(&vString); err != nil { - return err - } - vBytes, err := executeFileTemplate(context.Background(), vString, nil, true) - if err != nil { - return errors.Wrap(err, "failed to render chart string") - } - localChart, err := loadChart(path.Join(string(vBytes), chartFile)) - if err != nil { - return fmt.Errorf("failed to load local chart: " + vString) - } - cd.Name = localChart.Name - cd.Repository = fmt.Sprintf("file://%v", vString) - cd.Version = localChart.Version - return nil - default: - return fmt.Errorf("unsupported node tag type for %T: %q", cd, value.Tag) - } -} - -type Chart struct { - APIVersion string `yaml:"apiVersion"` - Name string `yaml:"name,omitempty"` - Description string `yaml:"description,omitempty"` - Type string `yaml:"type,omitempty"` - Version string `yaml:"version,omitempty"` - Dependencies []ChartDependency `yaml:"dependencies,omitempty"` -} - -func newChart(name, version string) *Chart { - return &Chart{ - APIVersion: chartAPIVersionV2, - Name: name, - Description: fmt.Sprintf("A helm parent chart for squadron %v", name), - Type: defaultChartType, - Version: version, - } -} - -func (c *Chart) addDependency(alias string, cd ChartDependency) { - cd.Alias = alias - c.Dependencies = append(c.Dependencies, cd) -} - -func loadChart(path string) (*Chart, error) { - c := Chart{} - file, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("error while opening file: %v", err) - } - if err := yaml.Unmarshal(file, &c); err != nil { - return nil, fmt.Errorf("error while unmarshalling template file: %s", err) - } - return &c, nil -} - -func (c Chart) generate(chartPath string, overrides interface{}) error { - // generate Chart.yaml - if err := util.GenerateYaml(path.Join(chartPath, chartFile), c); err != nil { - return err - } - // generate values.yaml - return util.GenerateYaml(path.Join(chartPath, valuesFile), overrides) -} diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 4d518d6..9016f31 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -1,101 +1,48 @@ package actions import ( - "context" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - "github.com/foomo/squadron" + "github.com/spf13/cobra" ) func init() { buildCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes built squadron units to the registry") buildCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - buildCmd.Flags().StringVar(&flagBuildArgs, "build-args", "", "additional docker buildx build args") - buildCmd.Flags().StringVar(&flagPushArgs, "push-args", "", "additional docker push args") + buildCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") + buildCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") } var buildCmd = &cobra.Command{ - Use: "build [UNIT...]", + Use: "build [SQUADRON.UNIT...]", Short: "build or rebuild squadron units", - Example: " squadron build frontend backend", + Example: " squadron build storefinder frontend backend", Args: cobra.MinimumNArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return build(cmd.Context(), args, cwd, flagFiles, flagPush, flagParallel) - }, -} - -func build(ctx context.Context, args []string, cwd string, files []string, push bool, parallel int) error { - sq := squadron.New(cwd, "", files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } + sq := squadron.New(cwd, "", flagFiles) - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + if err := sq.MergeConfigFiles(); err != nil { return err } - } - if err := sq.RenderConfig(ctx); err != nil { - return err - } - - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } - - { - g, gctx := errgroup.WithContext(ctx) - g.SetLimit(parallel) - - _ = squadron.Units(units).Iterate(func(n string, u *squadron.Unit) error { - name := n - unit := u - g.Go(func() error { - if out, err := unit.Build(gctx, sq.Name(), name, strings.Split(flagBuildArgs, " ")); err != nil { - return errors.Wrap(err, out) - } - return nil - }) - return nil - }) - err := g.Wait() - if err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - if push { - g, gctx := errgroup.WithContext(ctx) - g.SetLimit(parallel) - - _ = squadron.Units(units).Iterate(func(n string, u *squadron.Unit) error { - name := n - unit := u - g.Go(func() error { - if out, err := unit.Push(gctx, sq.Name(), name, strings.Split(flagPushArgs, " ")); err != nil { - return errors.Wrap(err, out) - } - return nil - }) - return nil - }) + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } - if err := g.Wait(); err != nil { + if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { return err } - } - return nil + if flagPush { + if err := sq.Push(cmd.Context(), flagPushArgs, flagParallel); err != nil { + return err + } + } + + return nil + }, } diff --git a/cmd/actions/config.go b/cmd/actions/config.go index be3e2f4..5b6784f 100644 --- a/cmd/actions/config.go +++ b/cmd/actions/config.go @@ -1,9 +1,9 @@ package actions import ( - "context" "fmt" + "github.com/foomo/squadron/internal/util" "github.com/spf13/cobra" "github.com/foomo/squadron" @@ -14,39 +14,30 @@ func init() { } var configCmd = &cobra.Command{ - Use: "config [UNIT...]", + Use: "config [SQUADRON] [UNIT...]", Short: "generate and view the squadron config", - Example: " squadron config --file squadron.yaml --file squadron.override.yaml", + Example: " squadron config storefinder frontend backend", Args: cobra.MinimumNArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return config(cmd.Context(), args, cwd, flagFiles, flagNoRender) - }, -} - -func config(ctx context.Context, args []string, cwd string, files []string, noRender bool) error { - sq := squadron.New(cwd, "", files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } + sq := squadron.New(cwd, "", flagFiles) - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + if err := sq.MergeConfigFiles(); err != nil { return err } - } - if !noRender { - if err := sq.RenderConfig(ctx); err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - fmt.Println(sq.GetConfigYAML()) - return nil + if !flagNoRender { + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } + } + + fmt.Print(util.Highlight(sq.ConfigYAML())) + + return nil + }, } diff --git a/cmd/actions/diff.go b/cmd/actions/diff.go new file mode 100644 index 0000000..8b7ec17 --- /dev/null +++ b/cmd/actions/diff.go @@ -0,0 +1,45 @@ +package actions + +import ( + "github.com/foomo/squadron" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +func init() { + diffCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + diffCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") +} + +var diffCmd = &cobra.Command{ + Use: "diff [SQUADRON] [UNIT...]", + Short: "shows the diff between the installed and local chart", + Example: " squadron diff storefinder frontend backend --namespace demo", + RunE: func(cmd *cobra.Command, args []string) error { + sq := squadron.New(cwd, flagNamespace, flagFiles) + + if err := sq.MergeConfigFiles(); err != nil { + return err + } + + args, helmArgs := parseExtraArgs(args) + + if len(args) > 0 { + if err := sq.Config().Squadrons.Filter(args[0]); err != nil { + return errors.Wrap(err, "invalid SQUADRON argument") + } + } + + if len(args) > 1 { + if err := sq.Config().Squadrons[args[0]].Filter(args[1:]...); err != nil { + return errors.Wrap(err, "invalid UNIT argument") + } + } + + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } + + return sq.Diff(cmd.Context(), helmArgs, flagParallel) + }, +} diff --git a/cmd/actions/down.go b/cmd/actions/down.go index d7f0b8b..34c56ba 100644 --- a/cmd/actions/down.go +++ b/cmd/actions/down.go @@ -1,39 +1,35 @@ package actions import ( - "context" - "github.com/spf13/cobra" "github.com/foomo/squadron" ) func init() { + downCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") downCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "Specifies the namespace") } var downCmd = &cobra.Command{ - Use: "down [UNIT...]", + Use: "down [SQUADRON] [UNIT...]", Short: "uninstalls the squadron or given units", - Example: " squadron down frontend backend --namespace demo", + Example: " squadron down storefinder frontend backend --namespace demo", Args: cobra.MinimumNArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return down(cmd.Context(), args, cwd, flagNamespace, flagFiles) - }, -} + sq := squadron.New(cwd, flagNamespace, flagFiles) -func down(ctx context.Context, args []string, cwd, namespace string, files []string) error { - sq := squadron.New(cwd, namespace, files) + if err := sq.MergeConfigFiles(); err != nil { + return err + } - if err := sq.MergeConfigFiles(); err != nil { - return err - } + args, helmArgs := parseExtraArgs(args) - args, helmArgs := parseExtraArgs(args) - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { + return err + } - return sq.Down(ctx, units, helmArgs) + return sq.Down(cmd.Context(), helmArgs, flagParallel) + }, } diff --git a/cmd/actions/generate.go b/cmd/actions/generate.go deleted file mode 100644 index e325f74..0000000 --- a/cmd/actions/generate.go +++ /dev/null @@ -1,44 +0,0 @@ -package actions - -import ( - "context" - - "github.com/spf13/cobra" - - "github.com/foomo/squadron" -) - -var generateCmd = &cobra.Command{ - Use: "generate [UNIT...]", - Short: "generate and view the squadron or given units charts", - Example: " squadron generate fronted backend", - Args: cobra.MinimumNArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - return generate(cmd.Context(), args, cwd, flagFiles) - }, -} - -func generate(ctx context.Context, args []string, cwd string, files []string) error { - sq := squadron.New(cwd, "", files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } - - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { - return err - } - } - - if err := sq.RenderConfig(ctx); err != nil { - return err - } - - return sq.Generate(ctx, sq.GetConfig().Units) -} diff --git a/cmd/actions/list.go b/cmd/actions/list.go index b16cc1f..28e70b9 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -3,42 +3,36 @@ package actions import ( "fmt" - "github.com/spf13/cobra" - "github.com/foomo/squadron" + "github.com/foomo/squadron/internal/config" + "github.com/spf13/cobra" ) var flagPrefixSquadron bool -func init() { - listCmd.Flags().BoolVar(&flagPrefixSquadron, "prefix-squadron", false, "add squadron prefix") -} - var listCmd = &cobra.Command{ - Use: "list", + Use: "list [SQUADRON]", Short: "list squadron units", - Example: " squadron list", + Example: " squadron list storefinder", Args: cobra.MinimumNArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return list(cwd, flagFiles) - }, -} - -func list(cwd string, files []string) error { - sq := squadron.New(cwd, "", files) + sq := squadron.New(cwd, "", flagFiles) - if err := sq.MergeConfigFiles(); err != nil { - return err - } + if err := sq.MergeConfigFiles(); err != nil { + return err + } - _ = sq.GetConfig().Units.Iterate(func(name string, unit *squadron.Unit) error { - if flagPrefixSquadron { - fmt.Printf("%s/%s\n", sq.Name(), name) - } else { - fmt.Println(name) + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { + return err } - return nil - }) - return nil + return sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + fmt.Println("Squadron:", key) + return value.Iterate(func(k string, v *config.Unit) error { + fmt.Println(" ", k) + return nil + }) + }) + }, } diff --git a/cmd/actions/push.go b/cmd/actions/push.go index 5a00494..10627f1 100644 --- a/cmd/actions/push.go +++ b/cmd/actions/push.go @@ -1,110 +1,44 @@ package actions import ( - "context" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - "golang.org/x/sync/semaphore" - "github.com/foomo/squadron" + "github.com/spf13/cobra" ) func init() { pushCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") pushCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units") pushCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - pushCmd.Flags().StringVar(&flagBuildArgs, "build-args", "", "additional docker buildx build args") - pushCmd.Flags().StringVar(&flagPushArgs, "push-args", "", "additional docker push args") + pushCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") + pushCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") } var pushCmd = &cobra.Command{ - Use: "push [UNIT...]", + Use: "push [SQUADRON] [UNIT...]", Short: "pushes the squadron or given units", - Example: " squadron push frontend backend --namespace demo --build", + Example: " squadron push storefinder frontend backend --namespace demo --build", RunE: func(cmd *cobra.Command, args []string) error { - return push(cmd.Context(), args, cwd, flagNamespace, flagBuild, flagParallel, flagFiles) - }, -} - -func push(ctx context.Context, args []string, cwd, namespace string, build bool, parallel int, files []string) error { - sq := squadron.New(cwd, namespace, files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } + sq := squadron.New(cwd, flagNamespace, flagFiles) - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + if err := sq.MergeConfigFiles(); err != nil { return err } - } - if err := sq.RenderConfig(ctx); err != nil { - return err - } - - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } - - if build { - sem := semaphore.NewWeighted(int64(parallel)) - wg, wgCtx := errgroup.WithContext(ctx) - - _ = squadron.Units(units).Iterate(func(n string, u *squadron.Unit) error { - name := n - unit := u - wg.Go(func() error { - if err := sem.Acquire(wgCtx, 1); err != nil { - return err - } - defer sem.Release(1) - if out, err := unit.Build(wgCtx, sq.Name(), name, strings.Split(flagBuildArgs, " ")); err != nil { - return errors.Wrap(err, out) - } - return nil - }) - return nil - }) - - if err := wg.Wait(); err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - - { - sem := semaphore.NewWeighted(int64(parallel)) - wg, wgCtx := errgroup.WithContext(ctx) - _ = squadron.Units(units).Iterate(func(n string, u *squadron.Unit) error { - name := n - unit := u - wg.Go(func() error { - if err := sem.Acquire(wgCtx, 1); err != nil { - return err - } - defer sem.Release(1) - if out, err := unit.Push(wgCtx, sq.Name(), name, strings.Split(flagPushArgs, " ")); err != nil { - return errors.Wrap(err, out) - } - return nil - }) - return nil - }) - - if err := wg.Wait(); err != nil { + if err := sq.RenderConfig(cmd.Context()); err != nil { return err } - } - return nil + if flagBuild { + if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { + return err + } + } + + return sq.Push(cmd.Context(), flagPushArgs, flagParallel) + }, } diff --git a/cmd/actions/rollback.go b/cmd/actions/rollback.go index e106333..9b6fb90 100644 --- a/cmd/actions/rollback.go +++ b/cmd/actions/rollback.go @@ -1,55 +1,39 @@ package actions import ( - "context" - "github.com/spf13/cobra" "github.com/foomo/squadron" ) func init() { + rollbackCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") rollbackCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") rollbackCmd.Flags().StringVarP(&flagRevision, "revision", "r", "", "specifies the revision to roll back to") } var rollbackCmd = &cobra.Command{ - Use: "rollback [UNIT...]", + Use: "rollback [SQUADRON] [UNIT...]", Short: "rolls back the squadron or given units", - Example: " squadron rollback frontend backend --namespace demo", + Example: " squadron rollback storefinder frontend backend --namespace demo", RunE: func(cmd *cobra.Command, args []string) error { - return rollback(cmd.Context(), args, cwd, flagNamespace, flagRevision, flagFiles) - }, -} + sq := squadron.New(cwd, flagNamespace, flagFiles) -func rollback(ctx context.Context, args []string, cwd, namespace string, revision string, files []string) error { - sq := squadron.New(cwd, namespace, files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - args, helmArgs := parseExtraArgs(args) + if err := sq.MergeConfigFiles(); err != nil { + return err + } - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } + args, helmArgs := parseExtraArgs(args) - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - - if err := sq.RenderConfig(ctx); err != nil { - return err - } - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } - return sq.Rollback(ctx, units, revision, helmArgs) + return sq.Rollback(cmd.Context(), flagRevision, helmArgs, flagParallel) + }, } diff --git a/cmd/actions/root.go b/cmd/actions/root.go index 9f2b5b2..9049b1d 100644 --- a/cmd/actions/root.go +++ b/cmd/actions/root.go @@ -4,13 +4,10 @@ import ( "os" "strings" - "github.com/pkg/errors" + "github.com/foomo/squadron/internal/util" "github.com/pterm/pterm" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - - "github.com/foomo/squadron" - "github.com/foomo/squadron/util" ) var ( @@ -47,8 +44,8 @@ var ( flagBuild bool flagPush bool flagParallel int - flagBuildArgs string - flagPushArgs string + flagBuildArgs []string + flagPushArgs []string flagDiff bool flagFiles []string ) @@ -59,7 +56,7 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "show more output") rootCmd.PersistentFlags().StringSliceVarP(&flagFiles, "file", "f", []string{"squadron.yaml"}, "specify alternative squadron files") - rootCmd.AddCommand(upCmd, downCmd, buildCmd, pushCmd, listCmd, generateCmd, rollbackCmd, statusCmd, configCmd, versionCmd, completionCmd, templateCmd) + rootCmd.AddCommand(upCmd, diffCmd, downCmd, buildCmd, pushCmd, listCmd, rollbackCmd, statusCmd, configCmd, versionCmd, completionCmd, templateCmd) pterm.Info = *pterm.Info.WithPrefix(pterm.Prefix{Text: "INFO", Style: pterm.Info.Prefix.Style}) pterm.Error = *pterm.Info.WithPrefix(pterm.Prefix{Text: "ERROR", Style: pterm.Error.Prefix.Style}) @@ -85,33 +82,15 @@ func parseExtraArgs(args []string) (out []string, extraArgs []string) { return args, nil } -// parseUnitArgs helper -func parseUnitArgs(args []string, units map[string]*squadron.Unit) (map[string]*squadron.Unit, error) { +func parseSquadronAndUnitNames(args []string) (squadron string, units []string) { if len(args) == 0 { - return units, nil + return "", nil } - ret := map[string]*squadron.Unit{} - for _, arg := range args { - if unit, ok := units[arg]; ok { - ret[arg] = unit - } else { - return nil, errors.Errorf("unknown unit name %s", arg) - } + if len(args) > 0 { + squadron = args[0] } - return ret, nil -} - -func parseUnitNames(args []string, units map[string]*squadron.Unit) ([]string, error) { - if len(args) == 0 { - return nil, nil - } - ret := make([]string, 0, len(args)) - for _, arg := range args { - if _, ok := units[arg]; ok { - ret = append(ret, arg) - } else { - return nil, errors.Errorf("unknown unit name %s", arg) - } + if len(args) > 1 { + units = args[1:] } - return ret, nil + return squadron, units } diff --git a/cmd/actions/status.go b/cmd/actions/status.go index c5bcdfc..1ca4b2d 100644 --- a/cmd/actions/status.go +++ b/cmd/actions/status.go @@ -1,54 +1,38 @@ package actions import ( - "context" - "github.com/spf13/cobra" "github.com/foomo/squadron" ) func init() { + statusCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") statusCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") } var statusCmd = &cobra.Command{ - Use: "status [UNIT...]", + Use: "status [SQUADRON] [UNIT...]", Short: "installs the squadron or given units", - Example: " squadron status frontend backend --namespace demo", + Example: " squadron status storefinder frontend backend --namespace demo", RunE: func(cmd *cobra.Command, args []string) error { - return status(cmd.Context(), args, cwd, flagNamespace, flagFiles) - }, -} + sq := squadron.New(cwd, flagNamespace, flagFiles) -func status(ctx context.Context, args []string, cwd, namespace string, files []string) error { - sq := squadron.New(cwd, namespace, files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - args, helmArgs := parseExtraArgs(args) + if err := sq.MergeConfigFiles(); err != nil { + return err + } - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } + args, helmArgs := parseExtraArgs(args) - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - - if err := sq.RenderConfig(ctx); err != nil { - return err - } - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } - return sq.Status(ctx, units, helmArgs) + return sq.Status(cmd.Context(), helmArgs, flagParallel) + }, } diff --git a/cmd/actions/template.go b/cmd/actions/template.go index c820554..4ccd753 100644 --- a/cmd/actions/template.go +++ b/cmd/actions/template.go @@ -1,11 +1,11 @@ package actions import ( - "context" - - "github.com/spf13/cobra" + "fmt" "github.com/foomo/squadron" + "github.com/foomo/squadron/internal/util" + "github.com/spf13/cobra" ) func init() { @@ -13,49 +13,35 @@ func init() { } var templateCmd = &cobra.Command{ - Use: "template [UNIT...]", + Use: "template [SQUADRON] [UNIT...]", Short: "render chart templates locally and display the output", - Example: " squadron template frontend backend --namespace demo", + Example: " squadron template storefinder frontend backend --namespace demo", Args: cobra.MinimumNArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return template(cmd.Context(), args, cwd, flagNamespace, flagFiles) - }, -} - -func template(ctx context.Context, args []string, cwd, namespace string, files []string) error { - sq := squadron.New(cwd, namespace, files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } + sq := squadron.New(cwd, flagNamespace, flagFiles) - args, helmArgs := parseExtraArgs(args) + if err := sq.MergeConfigFiles(); err != nil { + return err + } - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } + args, helmArgs := parseExtraArgs(args) - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - if err := sq.RenderConfig(ctx); err != nil { - return err - } + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } + out, err := sq.Template(cmd.Context(), helmArgs) + if err != nil { + return err + } - if err := sq.Generate(ctx, sq.GetConfig().Units); err != nil { - return err - } else if err := sq.Template(ctx, units, helmArgs); err != nil { - return err - } + fmt.Print(util.Highlight(out)) - return nil + return nil + }, } diff --git a/cmd/actions/up.go b/cmd/actions/up.go index 6602ab0..d0e1d78 100644 --- a/cmd/actions/up.go +++ b/cmd/actions/up.go @@ -1,144 +1,73 @@ package actions import ( - "context" - "fmt" "os/user" "strings" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - "golang.org/x/sync/semaphore" - "github.com/foomo/squadron" - "github.com/foomo/squadron/util" + "github.com/foomo/squadron/internal/util" + "github.com/spf13/cobra" ) func init() { upCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") upCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units") upCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes units to the registry") - upCmd.Flags().BoolVar(&flagDiff, "diff", false, "preview upgrade as a coloured diff") upCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - upCmd.Flags().StringVar(&flagBuildArgs, "build-args", "", "additional docker buildx build args") - upCmd.Flags().StringVar(&flagPushArgs, "push-args", "", "additional docker push args") + upCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") + upCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") } var upCmd = &cobra.Command{ - Use: "up [UNIT...]", + Use: "up [SQUADRON] [UNIT...]", Short: "installs the squadron or given units", - Example: " squadron up frontend backend --namespace demo --build --push -- --dry-run", + Example: " squadron up storefinder frontend backend --namespace demo --build --push -- --dry-run", RunE: func(cmd *cobra.Command, args []string) error { - return up(cmd.Context(), args, cwd, flagNamespace, flagBuild, flagPush, flagDiff, flagParallel, flagFiles) - }, -} + sq := squadron.New(cwd, flagNamespace, flagFiles) -func up(ctx context.Context, args []string, cwd, namespace string, build, push, diff bool, parallel int, files []string) error { - sq := squadron.New(cwd, namespace, files) - - if err := sq.MergeConfigFiles(); err != nil { - return err - } - - args, helmArgs := parseExtraArgs(args) - - unitsNames, err := parseUnitNames(args, sq.GetConfig().Units) - if err != nil { - return err - } - - if unitsNames != nil { - if err := sq.FilterConfig(unitsNames); err != nil { + if err := sq.MergeConfigFiles(); err != nil { return err } - } - - if err := sq.RenderConfig(ctx); err != nil { - return err - } - units, err := parseUnitArgs(args, sq.GetConfig().Units) - if err != nil { - return err - } + args, helmArgs := parseExtraArgs(args) - if build { - sem := semaphore.NewWeighted(int64(parallel)) - wg, wgCtx := errgroup.WithContext(ctx) - - _ = sq.GetConfig().Units.Iterate(func(n string, u *squadron.Unit) error { - name := n - unit := u - wg.Go(func() error { - if err := sem.Acquire(wgCtx, 1); err != nil { - return err - } - defer sem.Release(1) - if out, err := unit.Build(wgCtx, sq.Name(), name, strings.Split(flagBuildArgs, " ")); err != nil { - return errors.Wrap(err, out) - } - return nil - }) - return nil - }) - if err := wg.Wait(); err != nil { + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames); err != nil { return err } - } - - if push { - sem := semaphore.NewWeighted(int64(parallel)) - wg, wgCtx := errgroup.WithContext(ctx) - - _ = sq.GetConfig().Units.Iterate(func(n string, u *squadron.Unit) error { - name := n - unit := u - wg.Go(func() error { - if err := sem.Acquire(wgCtx, 1); err != nil { - return err - } - defer sem.Release(1) - if out, err := unit.Push(wgCtx, sq.Name(), name, strings.Split(flagPushArgs, " ")); err != nil { - return errors.Wrap(err, out) - } - return nil - }) - return nil - }) - if err := wg.Wait(); err != nil { + if err := sq.RenderConfig(cmd.Context()); err != nil { return err } - } - if err := sq.Generate(ctx, units); err != nil { - return err - } + if flagBuild { + if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { + return err + } + } - username := "unknown" - if value, err := util.NewCommand("git").Args("config", "user.name").Run(ctx); err == nil { - username = strings.TrimSpace(value) - } else if value, err := user.Current(); err == nil { - username = strings.TrimSpace(value.Name) - } + if flagPush { + if err := sq.Push(cmd.Context(), flagPushArgs, flagParallel); err != nil { + return err + } + } - branch := "" - if value, err := util.NewCommand("sh").Args("-c", "git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q --short HEAD || git rev-parse --short HEAD").Run(ctx); err == nil { - branch = strings.TrimSpace(value) - } - commit := "" - if value, err := util.NewCommand("sh").Args("-c", "git rev-parse --short HEAD").Run(ctx); err == nil { - commit = strings.TrimSpace(value) - } + username := "unknown" + if value, err := util.NewCommand("git").Args("config", "user.name").Run(cmd.Context()); err == nil { + username = strings.TrimSpace(value) + } else if value, err := user.Current(); err == nil { + username = strings.TrimSpace(value.Name) + } - if !diff { - return sq.Up(ctx, units, helmArgs, username, version, commit, branch, parallel) - } else if out, err := sq.Diff(ctx, units, helmArgs); err != nil { - return err - } else { - fmt.Println(out) - } + branch := "" + if value, err := util.NewCommand("sh").Args("-c", "git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q --short HEAD || git rev-parse --short HEAD").Run(cmd.Context()); err == nil { + branch = strings.TrimSpace(value) + } + commit := "" + if value, err := util.NewCommand("sh").Args("-c", "git rev-parse --short HEAD").Run(cmd.Context()); err == nil { + commit = strings.TrimSpace(value) + } - return nil + return sq.Up(cmd.Context(), helmArgs, username, version, commit, branch, flagParallel) + }, } diff --git a/configuration.go b/configuration.go deleted file mode 100644 index 114ce4b..0000000 --- a/configuration.go +++ /dev/null @@ -1,38 +0,0 @@ -package squadron - -import ( - "fmt" - - "gopkg.in/yaml.v3" -) - -type Configuration struct { - Name string `yaml:"name,omitempty"` - Version string `yaml:"version,omitempty"` - Prefix string `yaml:"prefix,omitempty"` - Unite bool `yaml:"unite,omitempty"` - Global map[string]interface{} `yaml:"global,omitempty"` - Units Units `yaml:"squadron,omitempty"` -} - -// UnmarshalYAML ... -func (c *Configuration) UnmarshalYAML(value *yaml.Node) error { - if value.Tag == TagMap { - type wrapper Configuration - err := value.Decode((*wrapper)(c)) - if err == nil { - // if the decode is successful, remove units that are nil - c.removeNilUnits() - } - return err - } - return fmt.Errorf("unsupported node tag type for %T: %q", c, value.Tag) -} - -func (c *Configuration) removeNilUnits() { - for uName, u := range c.Units { - if u == nil { - delete(c.Units, uName) - } - } -} diff --git a/go.mod b/go.mod index b8abc06..c061045 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,13 @@ module github.com/foomo/squadron -go 1.20 +go 1.21 require ( github.com/1Password/connect-sdk-go v1.5.3 + github.com/alecthomas/chroma v0.10.0 github.com/miracl/conflate v1.2.1 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.65 + github.com/pterm/pterm v0.12.67 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 @@ -14,21 +15,22 @@ require ( golang.org/x/sync v0.3.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.22.2 + k8s.io/api v0.28.2 ) require ( atomicgo.dev/cursor v0.2.0 // indirect atomicgo.dev/keyboard v0.2.9 // indirect - atomicgo.dev/schedule v0.0.2 // indirect + atomicgo.dev/schedule v0.1.0 // indirect github.com/BurntSushi/toml v1.2.0 // indirect github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dlclark/regexp2 v1.4.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/gookit/color v1.5.3 // indirect + github.com/gookit/color v1.5.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect @@ -47,15 +49,14 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + golang.org/x/net v0.13.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/apimachinery v0.27.4 // indirect - k8s.io/klog/v2 v2.90.1 // indirect - k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect + k8s.io/apimachinery v0.28.2 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index f3caa8e..ed4ca1e 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,18 @@ atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= -atomicgo.dev/schedule v0.0.2 h1:2e/4KY6t3wokja01Cyty6qgkQM8MotJzjtqCH70oX2Q= -atomicgo.dev/schedule v0.0.2/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= +atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= github.com/1Password/connect-sdk-go v1.5.3 h1:KyjJ+kCKj6BwB2Y8tPM1Ixg5uIS6HsB0uWA8U38p/Uk= github.com/1Password/connect-sdk-go v1.5.3/go.mod h1:5rSymY4oIYtS4G3t0oMkGAXBeoYiukV3vkqlnEjIDJs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= @@ -20,78 +21,38 @@ github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzX github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= +github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= +github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= -github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE= -github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -100,48 +61,30 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= @@ -149,8 +92,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.65 h1:HNMNCh2Zi6Lk+g5b8pORrFM9Ygz10GZUUcCFUkGpK2Q= -github.com/pterm/pterm v0.12.65/go.mod h1:CpJq+fr0+xKGlPFDhKTkepte2fY3Ydr5bzSJ9di67uI= +github.com/pterm/pterm v0.12.67 h1:5iB7ajIQROYfxYD7+sFJ4+KJhFJ+xn7QOVBm4s6RUF0= +github.com/pterm/pterm v0.12.67/go.mod h1:nFuT9ZVkkCi8o4L1dtWuYPwDQxggLh4C263qG5nTLpQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -166,15 +109,13 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -202,37 +143,22 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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/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= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191125084936-ffdde1057850/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -240,51 +166,36 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -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= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -294,69 +205,33 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= -k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= -k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/init.go b/init.go new file mode 100644 index 0000000..5b1ce6e --- /dev/null +++ b/init.go @@ -0,0 +1,15 @@ +package squadron + +import ( + "github.com/miracl/conflate" + yamlv2 "gopkg.in/yaml.v2" +) + +func init() { + yamlv2.FutureLineWrap() + // define the unmarshallers for the given file extensions, blank extension is the global unmarshaller + conflate.Unmarshallers = conflate.UnmarshallerMap{ + ".yaml": conflate.UnmarshallerFuncs{conflate.YAMLUnmarshal}, + ".yml": conflate.UnmarshallerFuncs{conflate.YAMLUnmarshal}, + } +} diff --git a/build.go b/internal/config/build.go similarity index 91% rename from build.go rename to internal/config/build.go index a004395..d91625c 100644 --- a/build.go +++ b/internal/config/build.go @@ -1,4 +1,4 @@ -package squadron +package config import ( "context" @@ -7,12 +7,7 @@ import ( "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" - "github.com/foomo/squadron/util" -) - -const ( - TagMap = "!!map" - TagString = "!!str" + "github.com/foomo/squadron/internal/util" ) type Build struct { @@ -45,7 +40,6 @@ type Build struct { // ~ Public methods // ------------------------------------------------------------------------------------------------ -// Build ... func (b *Build) Build(ctx context.Context, args []string) (string, error) { logrus.Debugf("running docker build for %q", b.Context) return util.NewDockerCommand().Build(b.Context). @@ -78,24 +72,24 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { Run(ctx) } -// Push ... func (b *Build) Push(ctx context.Context, args []string) (string, error) { logrus.Debugf("running docker push for %s:%s", b.Image, b.Tag) return util.NewDockerCommand().Push(b.Image, b.Tag).Args(args...).Run(ctx) } -// UnmarshalYAML ... func (b *Build) UnmarshalYAML(value *yaml.Node) error { - if value.Tag == TagMap { + switch value.Tag { + case "!!map": type wrapper Build return value.Decode((*wrapper)(b)) - } - if value.Tag == TagString { + case "!!str": var vString string if err := value.Decode(&vString); err != nil { return err } b.Context = vString + return nil + default: + return fmt.Errorf("unsupported node tag type for %T: %q", b, value.Tag) } - return fmt.Errorf("unsupported node tag type for %T: %q", b, value.Tag) } diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..d3c2d7a --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,31 @@ +package config + +import ( + "fmt" + + "gopkg.in/yaml.v3" +) + +type Config struct { + Version string `yaml:"version,omitempty"` + Global map[string]interface{} `yaml:"global,omitempty"` + Squadrons Map[Map[*Unit]] `yaml:"squadron,omitempty"` +} + +func (c *Config) Trim() { + _ = c.Squadrons.Iterate(func(key string, value Map[*Unit]) error { + value.Trim() + return nil + }) + c.Squadrons.Trim() +} + +func (c *Config) UnmarshalYAML(value *yaml.Node) error { + switch value.Tag { + case "!!map": + type wrapper Config + return value.Decode((*wrapper)(c)) + default: + return fmt.Errorf("unsupported node tag type for %T: %q", c, value.Tag) + } +} diff --git a/internal/config/doc.go b/internal/config/doc.go new file mode 100644 index 0000000..d912156 --- /dev/null +++ b/internal/config/doc.go @@ -0,0 +1 @@ +package config diff --git a/internal/config/map.go b/internal/config/map.go new file mode 100644 index 0000000..6b3e71c --- /dev/null +++ b/internal/config/map.go @@ -0,0 +1,93 @@ +package config + +import ( + "reflect" + "slices" + "sort" + + "github.com/pkg/errors" +) + +type Map[T any] map[string]T + +// Trim remove empty entries +func (m Map[T]) Trim() { + for key, value := range m { + val := reflect.ValueOf(value) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + if !val.IsValid() { + delete(m, key) + continue + } + if val.IsZero() { + delete(m, key) + continue + } + + switch val.Kind() { + case reflect.Map, reflect.Slice: + if val.Len() == 0 { + delete(m, key) + continue + } + } + } +} + +// Keys returns the keys as a sorted list +func (m Map[T]) Keys() []string { + if reflect.ValueOf(m).IsZero() { + return nil + } + ret := make([]string, 0, len(m)) + for key := range m { + ret = append(ret, key) + } + sort.Strings(ret) + return ret +} + +// Values returns all values sorted by keys +func (m Map[T]) Values() []T { + if len(m) == 0 { + return nil + } + keys := m.Keys() + ret := make([]T, 0, len(keys)) + for i, key := range keys { + ret[i] = m[key] + } + return ret +} + +func (m Map[T]) Filter(keys ...string) error { + if len(keys) == 0 { + return nil + } + validKeys := m.Keys() + for _, key := range keys { + if !slices.Contains(validKeys, key) { + return errors.Errorf("key not found: `%s`", key) + } + } + for key := range m { + if !slices.Contains(keys, key) { + delete(m, key) + } + } + return nil +} + +func (m Map[T]) Iterate(handler func(key string, value T) error) error { + if len(m) == 0 { + return nil + } + for _, key := range m.Keys() { + if err := handler(key, m[key]); err != nil { + return err + } + } + return nil +} diff --git a/internal/config/map_test.go b/internal/config/map_test.go new file mode 100644 index 0000000..8c1f245 --- /dev/null +++ b/internal/config/map_test.go @@ -0,0 +1,50 @@ +package config_test + +import ( + "testing" + + "github.com/foomo/squadron/internal/config" + "github.com/stretchr/testify/assert" +) + +func TestMap_Trim(t *testing.T) { + tests := []struct { + name string + value config.Map[any] + want int + }{ + { + name: "string", + value: config.Map[any]{ + "foo": "bar", + "baz": "", + }, + want: 1, + }, + { + name: "slice", + value: config.Map[any]{ + "foo": []string{"foo"}, + "baz": []string{}, + "bar": nil, + }, + want: 1, + }, + { + name: "map", + value: config.Map[any]{ + "foo": map[string]string{"foo": "foo"}, + "baz": map[string]string{}, + "bar": nil, + }, + want: 1, + }, + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + test.value.Trim() + assert.Len(tt, test.value, test.want) + }) + } +} diff --git a/unit.go b/internal/config/unit.go similarity index 58% rename from unit.go rename to internal/config/unit.go index 54fa6e1..78c1cf7 100644 --- a/unit.go +++ b/internal/config/unit.go @@ -1,13 +1,19 @@ -package squadron +package config import ( "context" + "os" + "strings" + "github.com/foomo/squadron/internal/helm" + "github.com/foomo/squadron/internal/util" + "github.com/pkg/errors" "github.com/pterm/pterm" + yamlv2 "gopkg.in/yaml.v2" ) type Unit struct { - Chart ChartDependency `yaml:"chart,omitempty"` + Chart helm.Dependency `yaml:"chart,omitempty"` Builds map[string]Build `yaml:"builds,omitempty"` Values map[string]interface{} `yaml:"values,omitempty"` } @@ -16,7 +22,17 @@ type Unit struct { // ~ Public methods // ------------------------------------------------------------------------------------------------ -// Build ... +func (u *Unit) ValuesYAML(global map[string]interface{}) ([]byte, error) { + values := u.Values + if values == nil { + values = map[string]interface{}{} + } + if global != nil { + values["global"] = global + } + return yamlv2.Marshal(values) +} + func (u *Unit) Build(ctx context.Context, squadron, unit string, args []string) (string, error) { var i int for _, build := range u.Builds { @@ -32,7 +48,6 @@ func (u *Unit) Build(ctx context.Context, squadron, unit string, args []string) return "", nil } -// Push ... func (u *Unit) Push(ctx context.Context, squadron, unit string, args []string) (string, error) { var i int for _, build := range u.Builds { @@ -47,3 +62,19 @@ func (u *Unit) Push(ctx context.Context, squadron, unit string, args []string) ( } return "", nil } + +func (u *Unit) DependencyUpdate(ctx context.Context) error { + // update local chart dependencies + // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql + if strings.HasPrefix(u.Chart.Repository, "file:///") { + pterm.Debug.Printfln("running helm dependency update for %s", u.Chart.Repository) + if out, err := util.NewHelmCommand(). + Stdout(os.Stdout). + Args("dependency", "update"). + Cwd(strings.TrimPrefix(u.Chart.Repository, "file://")). + Run(ctx); err != nil { + return errors.Wrap(err, out) + } + } + return nil +} diff --git a/internal/config/units.go b/internal/config/units.go new file mode 100644 index 0000000..2ddd94a --- /dev/null +++ b/internal/config/units.go @@ -0,0 +1,3 @@ +package config + +type Units[T any] Map[T] diff --git a/internal/helm/chart.go b/internal/helm/chart.go new file mode 100644 index 0000000..3186e2a --- /dev/null +++ b/internal/helm/chart.go @@ -0,0 +1,41 @@ +package helm + +import ( + "fmt" + "path" + + "github.com/foomo/squadron/internal/util" +) + +type Chart struct { + APIVersion string `yaml:"apiVersion"` + Name string `yaml:"name,omitempty"` + Description string `yaml:"description,omitempty"` + Type string `yaml:"type,omitempty"` + Version string `yaml:"version,omitempty"` + Dependencies []Dependency `yaml:"dependencies,omitempty"` +} + +func NewChart(name, version string) *Chart { + return &Chart{ + APIVersion: chartAPIVersionV2, + Name: name, + Description: fmt.Sprintf("A helm parent chart for squadron %v", name), + Type: defaultChartType, + Version: version, + } +} + +func (c *Chart) AddDependency(alias string, cd Dependency) { + cd.Alias = alias + c.Dependencies = append(c.Dependencies, cd) +} + +func (c *Chart) Generate(chartPath string, overrides interface{}) error { + // generate Chart.yaml + if err := util.GenerateYaml(path.Join(chartPath, chartFile), c); err != nil { + return err + } + // generate values.yaml + return util.GenerateYaml(path.Join(chartPath, valuesFile), overrides) +} diff --git a/internal/helm/depency.go b/internal/helm/depency.go new file mode 100644 index 0000000..23f1f04 --- /dev/null +++ b/internal/helm/depency.go @@ -0,0 +1,45 @@ +package helm + +import ( + "context" + "fmt" + "path" + + "github.com/foomo/squadron/internal/template" + "github.com/pkg/errors" + "gopkg.in/yaml.v3" +) + +type Dependency struct { + Name string `yaml:"name,omitempty"` + Repository string `yaml:"repository,omitempty"` + Version string `yaml:"version,omitempty"` + Alias string `yaml:"alias,omitempty"` +} + +func (cd *Dependency) UnmarshalYAML(value *yaml.Node) error { + switch value.Tag { + case "!!map": + type wrapper Dependency + return value.Decode((*wrapper)(cd)) + case "!!str": + var vString string + if err := value.Decode(&vString); err != nil { + return err + } + vBytes, err := template.ExecuteFileTemplate(context.Background(), vString, nil, true) + if err != nil { + return errors.Wrap(err, "failed to render chart string") + } + localChart, err := loadChart(path.Join(string(vBytes), chartFile)) + if err != nil { + return fmt.Errorf("failed to load local chart: " + vString) + } + cd.Name = localChart.Name + cd.Repository = fmt.Sprintf("file://%v", vString) + cd.Version = localChart.Version + return nil + default: + return fmt.Errorf("unsupported node tag type for %T: %q", cd, value.Tag) + } +} diff --git a/internal/helm/doc.go b/internal/helm/doc.go new file mode 100644 index 0000000..de7cfab --- /dev/null +++ b/internal/helm/doc.go @@ -0,0 +1,27 @@ +package helm + +import ( + "fmt" + "os" + + "gopkg.in/yaml.v3" +) + +const ( + chartAPIVersionV2 = "v2" + defaultChartType = "application" // application or library + chartFile = "Chart.yaml" + valuesFile = "values.yaml" +) + +func loadChart(path string) (*Chart, error) { + c := Chart{} + file, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error while opening file: %v", err) + } + if err := yaml.Unmarshal(file, &c); err != nil { + return nil, fmt.Errorf("error while unmarshalling template file: %s", err) + } + return &c, nil +} diff --git a/internal/template/default.go b/internal/template/default.go new file mode 100644 index 0000000..100e199 --- /dev/null +++ b/internal/template/default.go @@ -0,0 +1,16 @@ +package template + +func defaultValue(value string, def interface{}) interface{} { + if value == "" { + return def + } + return value +} + +func defaultIndexValue(v map[string]interface{}, index string, def interface{}) interface{} { + var ok bool + if _, ok = v[index]; ok { + return v[index] + } + return def +} diff --git a/internal/template/encode.go b/internal/template/encode.go new file mode 100644 index 0000000..cb0b31b --- /dev/null +++ b/internal/template/encode.go @@ -0,0 +1,9 @@ +package template + +import ( + b64 "encoding/base64" +) + +func base64(v string) string { + return b64.StdEncoding.EncodeToString([]byte(v)) +} diff --git a/internal/template/env.go b/internal/template/env.go new file mode 100644 index 0000000..62055c4 --- /dev/null +++ b/internal/template/env.go @@ -0,0 +1,22 @@ +package template + +import ( + "fmt" + "os" +) + +func env(name string) (string, error) { + if value := os.Getenv(name); value == "" { + return "", fmt.Errorf("env variable %q was empty", name) + } else { + return value, nil + } +} + +func envDefault(name, fallback string) (string, error) { + if value := os.Getenv(name); value == "" { + return fallback, nil + } else { + return value, nil + } +} diff --git a/internal/template/file.go b/internal/template/file.go new file mode 100644 index 0000000..004d885 --- /dev/null +++ b/internal/template/file.go @@ -0,0 +1,23 @@ +package template + +import ( + "bytes" + "context" + "os" + + "github.com/pkg/errors" +) + +func file(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(v string) (string, error) { + return func(v string) (string, error) { + if v == "" { + return "", nil + } else if fileBytes, err := os.ReadFile(v); err != nil { + return "", errors.Wrap(err, "failed to read file") + } else if renderedBytes, err := ExecuteFileTemplate(ctx, string(fileBytes), templateVars, errorOnMissing); err != nil { + return "", errors.Wrap(err, "failed to render file") + } else { + return string(bytes.TrimSpace(renderedBytes)), nil + } + } +} diff --git a/internal/template/format.go b/internal/template/format.go new file mode 100644 index 0000000..804ad80 --- /dev/null +++ b/internal/template/format.go @@ -0,0 +1,18 @@ +package template + +import ( + "strings" +) + +func indent(spaces int, v string) string { + pad := strings.Repeat(" ", spaces) + return strings.ReplaceAll(v, "\n", "\n"+pad) +} + +func quote(v string) string { + return "'" + v + "'" +} + +func replace(old, new, v string) string { + return strings.ReplaceAll(v, old, new) +} diff --git a/internal/template/git.go b/internal/template/git.go new file mode 100644 index 0000000..78aa406 --- /dev/null +++ b/internal/template/git.go @@ -0,0 +1,28 @@ +package template + +import ( + "bytes" + "context" + "os/exec" +) + +func git(ctx context.Context) func(action string) (string, error) { + return func(action string) (string, error) { + cmd := exec.CommandContext(ctx, "git") + + switch action { + case "commitsha": + cmd.Args = append(cmd.Args, "rev-list", "-1", "HEAD") + case "abbrevcommitsha": + cmd.Args = append(cmd.Args, "rev-list", "-1", "HEAD", "--abbrev-commit") + default: + cmd.Args = append(cmd.Args, "describe", "--tags", "--always") + } + res, err := cmd.Output() + if err != nil { + return "", err + } + + return string(bytes.TrimSpace(res)), nil + } +} diff --git a/template.go b/internal/template/onepassword.go similarity index 58% rename from template.go rename to internal/template/onepassword.go index 9048b92..c6f5052 100644 --- a/template.go +++ b/internal/template/onepassword.go @@ -1,9 +1,8 @@ -package squadron +package template import ( "bytes" "context" - b64 "encoding/base64" "encoding/json" "fmt" "io" @@ -15,235 +14,14 @@ import ( "github.com/1Password/connect-sdk-go/connect" "github.com/1Password/connect-sdk-go/onepassword" - "github.com/miracl/conflate" "github.com/pkg/errors" ) -func init() { - // define the unmarshallers for the given file extensions, blank extension is the global unmarshaller - conflate.Unmarshallers = conflate.UnmarshallerMap{ - ".yaml": conflate.UnmarshallerFuncs{conflate.YAMLUnmarshal}, - ".yml": conflate.UnmarshallerFuncs{conflate.YAMLUnmarshal}, - } -} - -type TemplateVars map[string]interface{} - -func (tv *TemplateVars) add(name string, value interface{}) { - (*tv)[name] = value -} - -func executeFileTemplate(ctx context.Context, text string, templateVars interface{}, errorOnMissing bool) ([]byte, error) { - templateFunctions := template.FuncMap{} - templateFunctions["env"] = env - templateFunctions["envDefault"] = envDefault - templateFunctions["op"] = onePassword(ctx, templateVars, errorOnMissing) - templateFunctions["base64"] = base64 - templateFunctions["default"] = defaultValue - templateFunctions["defaultIndex"] = defaultIndexValue - templateFunctions["indent"] = indent - templateFunctions["replace"] = replace - templateFunctions["file"] = file(ctx, templateVars, errorOnMissing) - templateFunctions["git"] = git(ctx) - templateFunctions["quote"] = quote - - tpl, err := template.New("squadron").Delims("<% ", " %>").Funcs(templateFunctions).Parse(text) - if err != nil { - return nil, err - } - out := bytes.NewBuffer([]byte{}) - if errorOnMissing { - tpl = tpl.Option("missingkey=error") - } - if err := tpl.Funcs(templateFunctions).Execute(out, templateVars); err != nil { - return nil, err - } - return out.Bytes(), nil -} - -func env(name string) (string, error) { - if value := os.Getenv(name); value == "" { - return "", fmt.Errorf("env variable %q was empty", name) - } else { - return value, nil - } -} - -func envDefault(name, fallback string) (string, error) { - if value := os.Getenv(name); value == "" { - return fallback, nil - } else { - return value, nil - } -} - -func file(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(v string) (string, error) { - return func(v string) (string, error) { - if v == "" { - return "", nil - } else if fileBytes, err := os.ReadFile(v); err != nil { - return "", errors.Wrap(err, "failed to read file") - } else if renderedBytes, err := executeFileTemplate(ctx, string(fileBytes), templateVars, errorOnMissing); err != nil { - return "", errors.Wrap(err, "failed to render file") - } else { - return string(bytes.TrimSpace(renderedBytes)), nil - } - } -} - -func defaultValue(value string, def interface{}) interface{} { - if value == "" { - return def - } - return value -} - -func defaultIndexValue(v map[string]interface{}, index string, def interface{}) interface{} { - var ok bool - if _, ok = v[index]; ok { - return v[index] - } - return def -} - -func base64(v string) string { - return b64.StdEncoding.EncodeToString([]byte(v)) -} - -func toSnakeCaseKeys(in interface{}) { - if value, ok := in.(map[string]interface{}); ok { - for k, v := range value { - if strings.Contains(k, "-") { - value[strings.ReplaceAll(k, "-", "_")] = v - delete(value, k) - } - toSnakeCaseKeys(v) - } - } -} - -func git(ctx context.Context) func(action string) (string, error) { - return func(action string) (string, error) { - cmd := exec.CommandContext(ctx, "git") - - switch action { - case "commitsha": - cmd.Args = append(cmd.Args, "rev-list", "-1", "HEAD") - case "abbrevcommitsha": - cmd.Args = append(cmd.Args, "rev-list", "-1", "HEAD", "--abbrev-commit") - default: - cmd.Args = append(cmd.Args, "describe", "--tags", "--always") - } - res, err := cmd.Output() - if err != nil { - return "", err - } - - return string(bytes.TrimSpace(res)), nil - } -} - -func indent(spaces int, v string) string { - pad := strings.Repeat(" ", spaces) - return strings.ReplaceAll(v, "\n", "\n"+pad) -} - -func quote(v string) string { - return "'" + v + "'" -} - -func replace(old, new, v string) string { - return strings.ReplaceAll(v, old, new) -} - -func render(name, text string, data interface{}, errorOnMissing bool) (string, error) { - var opts []string - if !errorOnMissing { - opts = append(opts, "missingkey=error") - } - out := bytes.NewBuffer([]byte{}) - if uuidTpl, err := template.New(name).Option(opts...).Parse(text); err != nil { - return "", err - } else if err := uuidTpl.Execute(out, data); err != nil { - return "", err - } - return out.String(), nil -} - var ( onePasswordCache map[string]map[string]string onePasswordUUID = regexp.MustCompile(`^[a-z0-9]{26}$`) ) -func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { - if onePasswordCache == nil { - onePasswordCache = map[string]map[string]string{} - } - return func(account, vaultUUID, itemUUID, field string) (string, error) { - // validate command - if mode := os.Getenv("OP_MODE"); mode == "ci" { - // do nothing - } else if _, err := exec.LookPath("op"); err != nil { - fmt.Println("Your templates includes a call to 1Password, please install it:") - fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") - return "", err - } else if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { - if err := onePasswordSignIn(ctx, account); err != nil { - return "", errors.Wrap(err, "failed to sign in") - } - } - - // render uuid & field params - if value, err := render("op", itemUUID, templateVars, errorOnMissing); err != nil { - return "", err - } else { - itemUUID = value - } - if value, err := render("op", field, templateVars, errorOnMissing); err != nil { - return "", err - } else { - field = value - } - - // create cache key - cacheKey := strings.Join([]string{account, vaultUUID, itemUUID}, "#") - - if mode := os.Getenv("OP_MODE"); mode == "ci" { - if _, ok := onePasswordCache[cacheKey]; !ok { - if client, err := connect.NewClientFromEnvironment(); err != nil { - return "", err - } else if res, err := onePasswordCIGet(client, vaultUUID, itemUUID); err != nil { - return "", err - } else { - onePasswordCache[cacheKey] = res - } - } - } else { - if _, ok := onePasswordCache[cacheKey]; !ok { - if res, err := onePasswordGet(ctx, account, vaultUUID, itemUUID); !errors.Is(err, ErrOnePasswordNotSignedIn) { - if err != nil { - return "", err - } else { - onePasswordCache[cacheKey] = res - } - } else if err := onePasswordSignIn(ctx, account); err != nil { - return "", errors.Wrap(err, "failed to sign in second time") - } else if res, err = onePasswordGet(ctx, account, vaultUUID, itemUUID); err != nil { - return "", err - } else { - onePasswordCache[cacheKey] = res - } - } - } - - if value, ok := onePasswordCache[cacheKey][field]; !ok { - return "", nil - } else { - return value, nil - } - } -} - var ErrOnePasswordNotSignedIn = errors.New("not signed in") func onePasswordCIGet(client connect.Client, vaultUUID, itemUUID string) (map[string]string, error) { @@ -336,3 +114,86 @@ func onePasswordSignIn(ctx context.Context, account string) error { } return nil } + +func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { + if onePasswordCache == nil { + onePasswordCache = map[string]map[string]string{} + } + return func(account, vaultUUID, itemUUID, field string) (string, error) { + // validate command + if mode := os.Getenv("OP_MODE"); mode == "ci" { + // do nothing + } else if _, err := exec.LookPath("op"); err != nil { + fmt.Println("Your templates includes a call to 1Password, please install it:") + fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") + return "", err + } else if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { + if err := onePasswordSignIn(ctx, account); err != nil { + return "", errors.Wrap(err, "failed to sign in") + } + } + + // render uuid & field params + if value, err := onePasswordRender("op", itemUUID, templateVars, errorOnMissing); err != nil { + return "", err + } else { + itemUUID = value + } + if value, err := onePasswordRender("op", field, templateVars, errorOnMissing); err != nil { + return "", err + } else { + field = value + } + + // create cache key + cacheKey := strings.Join([]string{account, vaultUUID, itemUUID}, "#") + + if mode := os.Getenv("OP_MODE"); mode == "ci" { + if _, ok := onePasswordCache[cacheKey]; !ok { + if client, err := connect.NewClientFromEnvironment(); err != nil { + return "", err + } else if res, err := onePasswordCIGet(client, vaultUUID, itemUUID); err != nil { + return "", err + } else { + onePasswordCache[cacheKey] = res + } + } + } else { + if _, ok := onePasswordCache[cacheKey]; !ok { + if res, err := onePasswordGet(ctx, account, vaultUUID, itemUUID); !errors.Is(err, ErrOnePasswordNotSignedIn) { + if err != nil { + return "", err + } else { + onePasswordCache[cacheKey] = res + } + } else if err := onePasswordSignIn(ctx, account); err != nil { + return "", errors.Wrap(err, "failed to sign in second time") + } else if res, err = onePasswordGet(ctx, account, vaultUUID, itemUUID); err != nil { + return "", err + } else { + onePasswordCache[cacheKey] = res + } + } + } + + if value, ok := onePasswordCache[cacheKey][field]; !ok { + return "", nil + } else { + return value, nil + } + } +} + +func onePasswordRender(name, text string, data interface{}, errorOnMissing bool) (string, error) { + var opts []string + if !errorOnMissing { + opts = append(opts, "missingkey=error") + } + out := bytes.NewBuffer([]byte{}) + if uuidTpl, err := template.New(name).Option(opts...).Parse(text); err != nil { + return "", err + } else if err := uuidTpl.Execute(out, data); err != nil { + return "", err + } + return out.String(), nil +} diff --git a/internal/template/template.go b/internal/template/template.go new file mode 100644 index 0000000..01eb483 --- /dev/null +++ b/internal/template/template.go @@ -0,0 +1,35 @@ +package template + +import ( + "bytes" + "context" + "text/template" +) + +func ExecuteFileTemplate(ctx context.Context, text string, templateVars interface{}, errorOnMissing bool) ([]byte, error) { + funcMap := template.FuncMap{ + "env": env, + "envDefault": envDefault, + "op": onePassword(ctx, templateVars, errorOnMissing), + "base64": base64, + "default": defaultValue, + "defaultIndex": defaultIndexValue, + "indent": indent, + "replace": replace, + "file": file(ctx, templateVars, errorOnMissing), + "git": git(ctx), + "quote": quote, + } + tpl, err := template.New("squadron").Delims("<% ", " %>").Funcs(funcMap).Parse(text) + if err != nil { + return nil, err + } + out := bytes.NewBuffer([]byte{}) + if errorOnMissing { + tpl = tpl.Option("missingkey=error") + } + if err := tpl.Funcs(funcMap).Execute(out, templateVars); err != nil { + return nil, err + } + return out.Bytes(), nil +} diff --git a/internal/template/vars.go b/internal/template/vars.go new file mode 100644 index 0000000..f81d37f --- /dev/null +++ b/internal/template/vars.go @@ -0,0 +1,7 @@ +package template + +type Vars map[string]interface{} + +func (tv *Vars) Add(name string, value interface{}) { + (*tv)[name] = value +} diff --git a/tests/utils/flag.go b/internal/testutils/flag.go similarity index 100% rename from tests/utils/flag.go rename to internal/testutils/flag.go diff --git a/internal/testutils/snapshot.go b/internal/testutils/snapshot.go new file mode 100644 index 0000000..34125ee --- /dev/null +++ b/internal/testutils/snapshot.go @@ -0,0 +1,36 @@ +package testutils + +import ( + "os" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Snapshot compares v with its snapshot file +func Snapshot(t *testing.T, name, yaml string) { + t.Helper() + snapshot := readSnapshot(t, name) + if *UpdateFlag || snapshot == "" { + writeSnapshot(t, name, yaml) + } + assert.Equal(t, snapshot, yaml) +} + +// writeSnapshot updates the snapshot file for a given test t. +func writeSnapshot(t *testing.T, name string, content string) { + t.Helper() + require.NoError(t, os.WriteFile(name, []byte(content), 0600), "failed to update snapshot", name) +} + +// readSnapshot reads the snapshot file for a given test t. +func readSnapshot(t *testing.T, name string) string { + t.Helper() + g, err := os.ReadFile(name) + if !errors.Is(err, os.ErrNotExist) { + require.NoError(t, err, "failed reading file", name) + } + return string(g) +} diff --git a/util/cmd.go b/internal/util/cmd.go similarity index 95% rename from util/cmd.go rename to internal/util/cmd.go index b538318..c75effc 100644 --- a/util/cmd.go +++ b/internal/util/cmd.go @@ -8,6 +8,7 @@ import ( "os/exec" "time" + "github.com/pterm/pterm" "github.com/sirupsen/logrus" ) @@ -144,7 +145,7 @@ func (c *Cmd) Run(ctx context.Context) (string, error) { if c.cwd != "" { cmd.Dir = c.cwd } - logrus.Debugf("executing %q", cmd.String()) + pterm.Debug.Printfln("executing %s", cmd.String()) combinedBuf := new(bytes.Buffer) traceWriter := logrus.StandardLogger().WriterLevel(logrus.TraceLevel) @@ -153,7 +154,7 @@ func (c *Cmd) Run(ctx context.Context) (string, error) { cmd.Stderr = io.MultiWriter(append(c.stderrWriters, combinedBuf, traceWriter)...) if c.preStartFunc != nil { - logrus.Debug("executing pre start func") + pterm.Debug.Println("executing pre start func") if err := c.preStartFunc(); err != nil { return combinedBuf.String(), err } @@ -164,7 +165,7 @@ func (c *Cmd) Run(ctx context.Context) (string, error) { } if c.postStartFunc != nil { - logrus.Debug("executing post start func") + pterm.Debug.Println("executing post start func") if err := c.postStartFunc(); err != nil { return combinedBuf.String(), err } diff --git a/util/docker.go b/internal/util/docker.go similarity index 100% rename from util/docker.go rename to internal/util/docker.go diff --git a/internal/util/helm.go b/internal/util/helm.go new file mode 100644 index 0000000..396a2c1 --- /dev/null +++ b/internal/util/helm.go @@ -0,0 +1,9 @@ +package util + +type HelmCmd struct { + Cmd +} + +func NewHelmCommand() *HelmCmd { + return &HelmCmd{*NewCommand("helm")} +} diff --git a/internal/util/highlight.go b/internal/util/highlight.go new file mode 100644 index 0000000..b91fed5 --- /dev/null +++ b/internal/util/highlight.go @@ -0,0 +1,47 @@ +package util + +import ( + "bytes" + + "github.com/alecthomas/chroma" + "github.com/alecthomas/chroma/formatters" + "github.com/alecthomas/chroma/lexers" + "github.com/alecthomas/chroma/styles" + "github.com/pterm/pterm" +) + +func Highlight(source string) string { + var out bytes.Buffer + // Determine lexer. + l := lexers.Get("yaml") + if l == nil { + l = lexers.Analyse(source) + } + if l == nil { + l = lexers.Fallback + } + l = chroma.Coalesce(l) + + // Determine formatter. + f := formatters.Get("terminal256") + if f == nil { + f = formatters.Fallback + } + + // Determine style. + s := styles.Get("monokai") + if s == nil { + s = styles.Fallback + } + + it, err := l.Tokenise(nil, source) + if err != nil { + pterm.Error.Println(err.Error()) + } + err = f.Format(&out, s, it) + if err != nil { + pterm.Error.Println(err.Error()) + } + + return out.String() +} diff --git a/util/kube.go b/internal/util/kube.go similarity index 100% rename from util/kube.go rename to internal/util/kube.go diff --git a/internal/util/path.go b/internal/util/path.go new file mode 100644 index 0000000..26f81a3 --- /dev/null +++ b/internal/util/path.go @@ -0,0 +1,23 @@ +package util + +import ( + "os" + "path" + "path/filepath" +) + +func ValidatePath(wd string, p *string) error { + if !filepath.IsAbs(*p) { + *p = path.Join(wd, *p) + } + absPath, err := filepath.Abs(*p) + if err != nil { + return err + } + _, err = os.Stat(absPath) + if err != nil { + return err + } + *p = absPath + return nil +} diff --git a/internal/util/strings.go b/internal/util/strings.go new file mode 100644 index 0000000..7c85a50 --- /dev/null +++ b/internal/util/strings.go @@ -0,0 +1,17 @@ +package util + +import ( + "strings" +) + +func ToSnakeCaseKeys(in interface{}) { + if value, ok := in.(map[string]interface{}); ok { + for k, v := range value { + if strings.Contains(k, "-") { + value[strings.ReplaceAll(k, "-", "_")] = v + delete(value, k) + } + ToSnakeCaseKeys(v) + } + } +} diff --git a/util/misc.go b/internal/util/yaml.go similarity index 50% rename from util/misc.go rename to internal/util/yaml.go index bb129ac..29f2ce4 100644 --- a/util/misc.go +++ b/internal/util/yaml.go @@ -2,14 +2,12 @@ package util import ( "os" - "path" - "path/filepath" - "gopkg.in/yaml.v3" + yamlv2 "gopkg.in/yaml.v2" ) func GenerateYaml(path string, data interface{}) (err error) { - out, marshalErr := yaml.Marshal(data) + out, marshalErr := yamlv2.Marshal(data) if marshalErr != nil { return marshalErr } @@ -25,19 +23,3 @@ func GenerateYaml(path string, data interface{}) (err error) { _, err = file.Write(out) return } - -func ValidatePath(wd string, p *string) error { - if !filepath.IsAbs(*p) { - *p = path.Join(wd, *p) - } - absPath, err := filepath.Abs(*p) - if err != nil { - return err - } - _, err = os.Stat(absPath) - if err != nil { - return err - } - *p = absPath - return nil -} diff --git a/squadron.go b/squadron.go index d25ce4b..20b67ab 100644 --- a/squadron.go +++ b/squadron.go @@ -7,68 +7,72 @@ import ( "fmt" "os" "os/exec" - "path" - "path/filepath" "strings" + "text/template" + "github.com/foomo/squadron/internal/config" + templatex "github.com/foomo/squadron/internal/template" + "github.com/foomo/squadron/internal/util" "github.com/miracl/conflate" "github.com/pkg/errors" "github.com/pterm/pterm" "github.com/sergi/go-diff/diffmatchpatch" - "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" yamlv2 "gopkg.in/yaml.v2" "gopkg.in/yaml.v3" - - "github.com/foomo/squadron/util" ) -func init() { - yamlv2.FutureLineWrap() -} - const ( - defaultOutputDir = ".squadron" - chartAPIVersionV2 = "v2" - defaultChartType = "application" // application or library - chartFile = "Chart.yaml" - valuesFile = "values.yaml" errHelmReleaseNotFound = "Error: release: not found" ) type Squadron struct { - name string basePath string namespace string files []string config string - c Configuration + c config.Config } func New(basePath, namespace string, files []string) *Squadron { return &Squadron{ - name: filepath.Base(basePath), basePath: basePath, namespace: namespace, files: files, - c: Configuration{}, + c: config.Config{}, } } -func (sq *Squadron) Name() string { - return sq.name +// ------------------------------------------------------------------------------------------------ +// ~ Getter +// ------------------------------------------------------------------------------------------------ + +func (sq *Squadron) Namespace(ctx context.Context, squadron, unit string) (string, error) { + var out bytes.Buffer + t, err := template.New("namespace").Parse(sq.namespace) + if err != nil { + return "", err + } + if err := t.Execute(&out, map[string]string{"Squadron": squadron, "Unit": unit}); err != nil { + return "", err + } + return out.String(), nil } -func (sq *Squadron) GetConfig() Configuration { +func (sq *Squadron) Config() config.Config { return sq.c } -func (sq *Squadron) GetConfigYAML() string { +func (sq *Squadron) ConfigYAML() string { return sq.config } +// ------------------------------------------------------------------------------------------------ +// ~ Public methods +// ------------------------------------------------------------------------------------------------ + func (sq *Squadron) MergeConfigFiles() error { - logrus.Info("merging config files") + pterm.Debug.Println("merging config files") pterm.Debug.Println(strings.Join(append([]string{"using files"}, sq.files...), "\n└ ")) mergedFiles, err := conflate.FromFiles(sq.files...) @@ -82,59 +86,78 @@ func (sq *Squadron) MergeConfigFiles() error { if err := yaml.Unmarshal(fileBytes, &sq.c); err != nil { return err } - sq.config = string(fileBytes) + if sq.c.Version != "2.0" { + return errors.New("Please upgrade your YAML definition to 2.0") + } + + sq.c.Trim() + + value, err := yamlv2.Marshal(sq.c) + if err != nil { + return err + } + + sq.config = string(value) + return nil } -func (sq *Squadron) FilterConfig(units []string) error { - unitsMap := make(map[string]bool, len(units)) - for _, unit := range units { - unitsMap[unit] = true +func (sq *Squadron) FilterConfig(squadron string, units []string) error { + if len(squadron) == 0 { + return nil } - for name := range sq.c.Units { - if _, ok := unitsMap[name]; !ok { - delete(sq.c.Units, name) + if err := sq.Config().Squadrons.Filter(squadron); err != nil { + return err + } + + if len(squadron) > 0 && len(units) > 0 { + if err := sq.Config().Squadrons[squadron].Filter(units...); err != nil { + return err } } - value, err := yaml.Marshal(sq.c) + + value, err := yamlv2.Marshal(sq.c) if err != nil { return err } + sq.config = string(value) + return nil } func (sq *Squadron) RenderConfig(ctx context.Context) error { - logrus.Info("rendering config") - var tv TemplateVars + pterm.Debug.Println("rendering config") + + var tv templatex.Vars var vars map[string]interface{} if err := yaml.Unmarshal([]byte(sq.config), &vars); err != nil { return err } // execute again with loaded template vars - tv = TemplateVars{} + tv = templatex.Vars{} if value, ok := vars["global"]; ok { - toSnakeCaseKeys(value) - tv.add("Global", value) + util.ToSnakeCaseKeys(value) + tv.Add("Global", value) } if value, ok := vars["squadron"]; ok { - toSnakeCaseKeys(value) - tv.add("Squadron", value) + util.ToSnakeCaseKeys(value) + tv.Add("Squadron", value) } // execute without errors to get existing values pterm.Debug.Println("executing file template") // pterm.Debug.Println(sq.config) - out, err := executeFileTemplate(ctx, sq.config, tv, false) + out, err := templatex.ExecuteFileTemplate(ctx, sq.config, tv, false) if err != nil { - return errors.Wrap(err, "failed to execute initial file template") + return errors.Wrapf(err, "failed to execute initial file template\n%s", util.Highlight(sq.config)) } // re-execute for rendering copied values pterm.Debug.Println("re-executing file template") // pterm.Debug.Println(string(out)) - out, err = executeFileTemplate(ctx, string(out), tv, false) + out, err = templatex.ExecuteFileTemplate(ctx, string(out), tv, false) if err != nil { return errors.Wrap(err, "failed to re-execute initial file template") } @@ -146,169 +169,165 @@ func (sq *Squadron) RenderConfig(ctx context.Context) error { } // execute again with loaded template vars - tv = TemplateVars{} + tv = templatex.Vars{} if value, ok := vars["global"]; ok { - toSnakeCaseKeys(value) - tv.add("Global", value) + util.ToSnakeCaseKeys(value) + tv.Add("Global", value) } if value, ok := vars["squadron"]; ok { - toSnakeCaseKeys(value) - tv.add("Squadron", value) + util.ToSnakeCaseKeys(value) + tv.Add("Squadron", value) } pterm.Debug.Println("executing file template") - out, err = executeFileTemplate(ctx, sq.config, tv, true) + out, err = templatex.ExecuteFileTemplate(ctx, sq.config, tv, true) if err != nil { return errors.Wrap(err, "failed to execute second file template") } + pterm.Debug.Println("unmarshalling vars") if err := yaml.Unmarshal(out, &sq.c); err != nil { pterm.Error.Println(string(out)) return errors.Wrap(err, "failed to unmarshal vars") } - sq.config = string(out) - if sq.c.Name != "" { - sq.name = sq.c.Name - } + sq.config = string(out) return nil } -func (sq *Squadron) Generate(ctx context.Context, units Units) error { - logrus.WithField("path", sq.chartPath()).Infof("generating charts") - if err := sq.cleanupOutput(sq.chartPath()); err != nil { - return err - } - if sq.c.Unite { - return sq.generateUmbrellaChart(ctx, units) - } - for _, uName := range units.Keys() { - u := units[uName] - // update local chart dependencies - // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql - if strings.HasPrefix(u.Chart.Repository, "file:///") { - pterm.Debug.Printfln("running helm dependency update for %s", u.Chart.Repository) - if out, err := util.NewHelmCommand(). - Stdout(os.Stdout). - Args("dependency", "update"). - Cwd(strings.TrimPrefix(u.Chart.Repository, "file://")). - Run(ctx); err != nil { - return errors.Wrap(err, out) - } - } +func (sq *Squadron) Push(ctx context.Context, pushArgs []string, parallel int) error { + wg, gctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) - pterm.Debug.Printfln("generating %q value overrides file in %q", uName, sq.chartPath()) - if err := sq.generateValues(u.Values, sq.chartPath(), uName); err != nil { - return err - } - } - return nil -} + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + wg.Go(func() error { + if out, err := v.Push(gctx, key, k, pushArgs); err != nil { + return errors.Wrap(err, out) + } + return nil + }) + return nil + }) + }) -func (sq *Squadron) generateUmbrellaChart(ctx context.Context, units Units) error { - pterm.Debug.Printfln("generating chart %q files in %q", sq.name, sq.chartPath()) - if err := sq.generateChart(units, sq.chartPath(), sq.name, sq.c.Version); err != nil { - return err - } - pterm.Debug.Printfln("running helm dependency update for chart: %v", sq.chartPath()) - if out, err := util.NewHelmCommand().UpdateDependency(ctx, sq.chartPath()); err != nil { - return errors.Wrap(err, out) - } - return nil + return wg.Wait() } -func (sq *Squadron) Package(ctx context.Context) error { - pterm.Debug.Printfln("running helm package for chart: %v", sq.chartPath()) - if out, err := util.NewHelmCommand().Package(ctx, sq.chartPath(), sq.basePath); err != nil { - return errors.Wrap(err, out) - } - return nil +func (sq *Squadron) Build(ctx context.Context, buildArgs []string, parallel int) error { + wg, gctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) + + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + wg.Go(func() error { + if out, err := v.Build(gctx, key, k, buildArgs); err != nil { + return errors.Wrap(err, out) + } + return nil + }) + return nil + }) + }) + + return wg.Wait() } -func (sq *Squadron) Down(ctx context.Context, units Units, helmArgs []string) error { - if sq.c.Unite { - pterm.Debug.Printfln("running helm uninstall for: %s", sq.chartPath()) - stdErr := bytes.NewBuffer([]byte{}) - if out, err := util.NewHelmCommand().Args("uninstall", sq.name). - Stderr(stdErr). - Stdout(os.Stdout). - Args("--namespace", sq.namespace). - Args(helmArgs...). - Run(ctx); err != nil && - string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", sq.name) { - return errors.Wrap(err, out) - } - } - for _, uName := range units.Keys() { - // todo use release prefix on install: squadron name or --name - rName := fmt.Sprintf("%s-%s", sq.name, uName) - pterm.Debug.Printfln("running helm uninstall for: %s", uName) - stdErr := bytes.NewBuffer([]byte{}) - if out, err := util.NewHelmCommand().Args("uninstall", rName). - Stderr(stdErr). - Stdout(os.Stdout). - Args("--namespace", sq.namespace). - Args(helmArgs...). - Run(ctx); err != nil && - string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", rName) { - return errors.Wrap(err, out) - } - } +func (sq *Squadron) Down(ctx context.Context, helmArgs []string, parallel int) error { + wg, ctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) + + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + wg.Go(func() error { + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err + } - return nil + stdErr := bytes.NewBuffer([]byte{}) + pterm.Debug.Printfln("running helm uninstall for: %s", name) + if out, err := util.NewHelmCommand().Args("uninstall", name). + Stderr(stdErr). + Stdout(os.Stdout). + Args("--namespace", namespace). + Args(helmArgs...). + Run(ctx); err != nil && + string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", name) { + return errors.Wrap(err, out) + } + return nil + }) + return nil + }) + }) + + return wg.Wait() } -func (sq *Squadron) Diff(ctx context.Context, units Units, helmArgs []string) (string, error) { - if sq.c.Unite { - pterm.Debug.Printfln("running helm diff for: %s", sq.chartPath()) - manifest, err := exec.CommandContext(ctx, "helm", "get", "manifest", sq.name, "--namespace", sq.namespace).CombinedOutput() //nolint:gosec - if err != nil { - return "", errors.Wrap(err, string(manifest)) - } - cmd := exec.CommandContext(ctx, "helm", "upgrade", sq.name, sq.chartPath(), "--namespace", sq.namespace, "--dry-run") //nolint:gosec - cmd.Args = append(cmd.Args, helmArgs...) - template, err := cmd.CombinedOutput() - if err != nil { - return "", errors.Wrap(err, string(template)) - } - dmp := diffmatchpatch.New() - return dmp.DiffPrettyText(dmp.DiffMain(string(manifest), string(template), false)), nil - } - for _, uName := range units.Keys() { - u := units[uName] - // todo use release prefix on install: squadron name or --name - rName := fmt.Sprintf("%s-%s", sq.name, uName) - pterm.Debug.Printfln("running helm diff for: %s", uName) - manifest, err := exec.CommandContext(ctx, "helm", "get", "manifest", rName, "--namespace", sq.namespace).CombinedOutput() - if err != nil && string(bytes.TrimSpace(manifest)) != errHelmReleaseNotFound { - return "", errors.Wrap(err, string(manifest)) - } - cmd := exec.CommandContext(ctx, "helm", "upgrade", rName, - "--install", - "--namespace", sq.namespace, - "-f", path.Join(sq.chartPath(), uName+".yaml"), - "--set", fmt.Sprintf("squadron=%s,unit=%s", sq.name, uName), - "--dry-run", - ) - if strings.Contains(u.Chart.Repository, "file://") { - cmd.Args = append(cmd.Args, "/"+strings.TrimPrefix(u.Chart.Repository, "file://")) - } else { - cmd.Args = append(cmd.Args, u.Chart.Name, "--repo", u.Chart.Repository, "--version", u.Chart.Version) - } - cmd.Args = append(cmd.Args, helmArgs...) - template, err := cmd.CombinedOutput() - if err != nil { - return "", errors.Wrap(err, string(template)) - } - dmp := diffmatchpatch.New() - _, _ = fmt.Println(dmp.DiffPrettyText(dmp.DiffMain(string(manifest), string(template), false))) +func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) error { + var diff string + wg, ctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) + + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + wg.Go(func() error { + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err + } + valueBytes, err := v.ValuesYAML(sq.c.Global) + if err != nil { + return err + } + + pterm.Debug.Printfln("running helm diff for: %s", k) + manifest, err := exec.CommandContext(ctx, "helm", "get", "manifest", name, "--namespace", sq.namespace).CombinedOutput() + if err != nil && string(bytes.TrimSpace(manifest)) != errHelmReleaseNotFound { + return errors.Wrap(err, string(manifest)) + } + cmd := exec.CommandContext(ctx, "helm", "upgrade", name, + "--install", + "--namespace", namespace, + "--set", fmt.Sprintf("squadron=%s", key), + "--set", fmt.Sprintf("unit=%s", k), + "--values", "-", + "--dry-run", + ) + cmd.Stdin = bytes.NewReader(valueBytes) + if strings.Contains(v.Chart.Repository, "file://") { + cmd.Args = append(cmd.Args, "/"+strings.TrimPrefix(v.Chart.Repository, "file://")) + } else { + cmd.Args = append(cmd.Args, v.Chart.Name, "--repo", v.Chart.Repository, "--version", v.Chart.Version) + } + cmd.Args = append(cmd.Args, helmArgs...) + out, err := cmd.CombinedOutput() + if err != nil { + return errors.Wrap(err, string(out)) + } + + dmp := diffmatchpatch.New() + diff += dmp.DiffPrettyText(dmp.DiffMain(string(manifest), string(out), false)) + return nil + }) + return nil + }) + }) + + if err := wg.Wait(); err != nil { + return err } - return "", nil + fmt.Println(diff) + + return nil } -func (sq *Squadron) Status(ctx context.Context, units Units, helmArgs []string) error { +func (sq *Squadron) Status(ctx context.Context, helmArgs []string, parallel int) error { tbd := pterm.TableData{ {"Name", "Revision", "Status", "Deployed by", "Commit", "Branch", "Last deployed", "Notes"}, } @@ -329,269 +348,209 @@ func (sq *Squadron) Status(ctx context.Context, units Units, helmArgs []string) gitBranch string `json:"-"` } - var status statusType - - if sq.c.Unite { - stdErr := bytes.NewBuffer([]byte{}) - pterm.Debug.Printfln("running helm status for chart: %s", sq.chartPath()) - if out, err := util.NewHelmCommand().Args("status", sq.name). - Stderr(stdErr). - Args("--namespace", sq.namespace, "--output", "json", "--show-desc"). - Args(helmArgs...). - Run(ctx); err != nil && string(bytes.TrimSpace(stdErr.Bytes())) == errHelmReleaseNotFound { - tbd = append(tbd, []string{sq.name, "0", "not installed", "", ""}) - } else if err != nil { - return errors.Wrap(err, out) - } else if err := json.Unmarshal([]byte(out), &status); err != nil { - return errors.Wrap(err, out) - } else { - var notes []string - for _, line := range strings.Split(status.Info.Description, "\n") { - if strings.HasPrefix(line, "Managed-By: ") { - // do nothing - } else if strings.HasPrefix(line, "Deployed-By: ") { - status.deployedBy = strings.TrimPrefix(line, "Deployed-By: ") - } else if strings.HasPrefix(line, "Git-Commit: ") { - status.gitCommit = strings.TrimPrefix(line, "Git-Commit: ") - } else if strings.HasPrefix(line, "Git-Branch: ") { - status.gitBranch = strings.TrimPrefix(line, "Git-Branch: ") - } else { - notes = append(notes, line) - } + wg, ctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) + + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + var status statusType + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err } - tbd = append(tbd, []string{ - status.Name, - fmt.Sprintf("%d", status.Version), - status.Info.Status, - status.deployedBy, - status.gitCommit, - status.gitBranch, - status.Info.LastDeployed, strings.Join(notes, " | "), - }) - } - } - for _, uName := range units.Keys() { - stdErr := bytes.NewBuffer([]byte{}) - // todo use release prefix on install: squadron name or --name - rName := fmt.Sprintf("%s-%s", sq.name, uName) - pterm.Debug.Printfln("running helm status for %s", uName) - if out, err := util.NewHelmCommand().Args("status", rName). - Stderr(stdErr). - Args("--namespace", sq.namespace, "--output", "json", "--show-desc"). - Args(helmArgs...).Run(ctx); err != nil && string(bytes.TrimSpace(stdErr.Bytes())) == errHelmReleaseNotFound { - tbd = append(tbd, []string{rName, "0", "not installed", "", ""}) - } else if err != nil { - return errors.Wrap(err, out) - } else if err := json.Unmarshal([]byte(out), &status); err != nil { - return errors.Wrap(err, out) - } else { - var notes []string - for _, line := range strings.Split(status.Info.Description, "\n") { - if strings.HasPrefix(line, "Managed-By: ") { - // do nothing - } else if strings.HasPrefix(line, "Deployed-By: ") { - status.deployedBy = strings.TrimPrefix(line, "Deployed-By: ") - } else if strings.HasPrefix(line, "Git-Commit: ") { - status.gitCommit = strings.TrimPrefix(line, "Git-Commit: ") - } else if strings.HasPrefix(line, "Git-Branch: ") { - status.gitBranch = strings.TrimPrefix(line, "Git-Branch: ") - } else { - notes = append(notes, line) + + stdErr := bytes.NewBuffer([]byte{}) + pterm.Debug.Printfln("running helm status for %s", name) + if out, err := util.NewHelmCommand().Args("status", name). + Stderr(stdErr). + Args("--namespace", namespace, "--output", "json", "--show-desc"). + Args(helmArgs...).Run(ctx); err != nil && string(bytes.TrimSpace(stdErr.Bytes())) == errHelmReleaseNotFound { + tbd = append(tbd, []string{name, "0", "not installed", "", ""}) + } else if err != nil { + return errors.Wrap(err, out) + } else if err := json.Unmarshal([]byte(out), &status); err != nil { + return errors.Wrap(err, out) + } else { + var notes []string + for _, line := range strings.Split(status.Info.Description, "\n") { + if strings.HasPrefix(line, "Managed-By: ") { + // do nothing + } else if strings.HasPrefix(line, "Deployed-By: ") { + status.deployedBy = strings.TrimPrefix(line, "Deployed-By: ") + } else if strings.HasPrefix(line, "Git-Commit: ") { + status.gitCommit = strings.TrimPrefix(line, "Git-Commit: ") + } else if strings.HasPrefix(line, "Git-Branch: ") { + status.gitBranch = strings.TrimPrefix(line, "Git-Branch: ") + } else { + notes = append(notes, line) + } } + tbd = append(tbd, []string{ + status.Name, + fmt.Sprintf("%d", status.Version), + status.Info.Status, + status.deployedBy, + status.gitCommit, + status.gitBranch, + status.Info.LastDeployed, strings.Join(notes, " | "), + }) } - tbd = append(tbd, []string{ - status.Name, - fmt.Sprintf("%d", status.Version), - status.Info.Status, - status.deployedBy, - status.gitCommit, - status.gitBranch, - status.Info.LastDeployed, strings.Join(notes, " | "), - }) - } + return nil + }) + }) + + if err := wg.Wait(); err != nil { + return err } return pterm.DefaultTable.WithHasHeader().WithData(tbd).Render() } -func (sq *Squadron) Rollback(ctx context.Context, units Units, revision string, helmArgs []string) error { +func (sq *Squadron) Rollback(ctx context.Context, revision string, helmArgs []string, parallel int) error { if revision != "" { helmArgs = append([]string{revision}, helmArgs...) } - if sq.c.Unite { - pterm.Debug.Printfln("running helm rollback for: %s", sq.chartPath()) - stdErr := bytes.NewBuffer([]byte{}) - if out, err := util.NewHelmCommand().Args("rollback", sq.name). - Stderr(stdErr). - Stdout(os.Stdout). - Args(helmArgs...). - Args("--namespace", sq.namespace). - Run(ctx); err != nil && - string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", sq.name) { - return errors.Wrap(err, out) - } - } - for _, uName := range units.Keys() { - // todo use release prefix on install: squadron name or --name - rName := fmt.Sprintf("%s-%s", sq.name, uName) - pterm.Debug.Printfln("running helm uninstall for: %s", uName) - stdErr := bytes.NewBuffer([]byte{}) - if out, err := util.NewHelmCommand().Args("rollback", rName). - Stderr(stdErr). - Stdout(os.Stdout). - Args(helmArgs...). - Args("--namespace", sq.namespace). - Run(ctx); err != nil && - string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", rName) { - return errors.Wrap(err, out) - } - } - return nil -} + wg, ctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) -func (sq *Squadron) Up(ctx context.Context, units Units, helmArgs []string, username, version, commit, branch string, parallel int) error { - description := fmt.Sprintf("\nDeployed-By: %s\nManaged-By: Squadron %s\nGit-Commit: %s\nGit-Branch: %s", username, version, commit, branch) + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err + } - if sq.c.Unite { - pterm.Debug.Printfln("running helm upgrade for chart: %s", sq.chartPath()) - if out, err := util.NewHelmCommand(). - Stdout(os.Stdout). - Args("upgrade", sq.name, sq.chartPath()). - Args("--namespace", sq.namespace). - Args("--dependency-update"). - Args("--description", description). - Args("--install"). - Args(helmArgs...). - Run(ctx); err != nil { - return errors.Wrap(err, out) - } - return nil - } - g, gctx := errgroup.WithContext(ctx) - g.SetLimit(parallel) - - for _, uName := range units.Keys() { - u := units[uName] - // todo use release prefix on install: squadron name or --name - rName := fmt.Sprintf("%s-%s", sq.name, uName) - - // update local chart dependencies - // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql - if strings.HasPrefix(u.Chart.Repository, "file:///") { - pterm.Debug.Printfln("running helm dependency update for %s", u.Chart.Repository) - if out, err := util.NewHelmCommand(). + stdErr := bytes.NewBuffer([]byte{}) + pterm.Debug.Printfln("running helm uninstall for: `%s`", name) + if out, err := util.NewHelmCommand().Args("rollback", name). + Stderr(stdErr). Stdout(os.Stdout). - Args("dependency", "update"). - Cwd(strings.TrimPrefix(u.Chart.Repository, "file://")). - Run(ctx); err != nil { + Args(helmArgs...). + Args("--namespace", namespace). + Run(ctx); err != nil && + string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", name) { return errors.Wrap(err, out) } - } - - // install chart - pterm.Debug.Printfln("running helm upgrade for %s", uName) - cmd := util.NewHelmCommand(). - Stdout(os.Stdout). - Args("upgrade", rName, "--install"). - Args("--set", fmt.Sprintf("squadron=%s,unit=%s", sq.name, uName)). - Args("--description", description). - Args("--namespace", sq.namespace). - Args("--dependency-update"). - Args("--install"). - Args("-f", path.Join(sq.chartPath(), uName+".yaml")). - Args(helmArgs...) - if strings.Contains(u.Chart.Repository, "file://") { - cmd.Args(strings.TrimPrefix(u.Chart.Repository, "file://")) - } else { - cmd.Args(u.Chart.Name, "--repo", u.Chart.Repository, "--version", u.Chart.Version) - } - g.Go(func() error { - if out, err := cmd.Run(gctx); err != nil { - return errors.Wrap(err, out) - } return nil }) - } - return g.Wait() -} + }) -func (sq *Squadron) Template(ctx context.Context, units Units, helmArgs []string) error { - if sq.c.Unite { - pterm.Debug.Printfln("running helm template for chart: %s", sq.chartPath()) - if out, err := util.NewHelmCommand().Args("template", sq.name, sq.chartPath()). - Stdout(os.Stdout). - Args("--dependency-update"). - Args("--namespace", sq.namespace). - Args(helmArgs...). - Run(ctx); err != nil { - return errors.Wrap(err, out) - } - return nil - } - for _, uName := range units.Keys() { - u := units[uName] - // todo use release prefix on install: squadron name or --name - rName := fmt.Sprintf("%s-%s", sq.name, uName) - pterm.Debug.Printfln("running helm template for chart: %s", uName) - cmd := util.NewHelmCommand().Args("template", rName). - Stdout(os.Stdout). - Args("--dependency-update"). - Args("--namespace", sq.namespace). - Args("--set", fmt.Sprintf("squadron=%s,unit=%s", sq.name, uName)). - Args("-f", path.Join(sq.chartPath(), uName+".yaml")). - Args(helmArgs...) - if strings.Contains(u.Chart.Repository, "file://") { - cmd.Args("/" + strings.TrimPrefix(u.Chart.Repository, "file://")) - } else { - cmd.Args(u.Chart.Name, "--repo", u.Chart.Repository, "--version", u.Chart.Version) - } - if out, err := cmd.Run(ctx); err != nil { - return errors.Wrap(err, out) - } - } - return nil + return wg.Wait() } -func (sq *Squadron) chartPath() string { - return path.Join(sq.basePath, defaultOutputDir, sq.name) -} +func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version, commit, branch string, parallel int) error { + description := fmt.Sprintf("\nDeployed-By: %s\nManaged-By: Squadron %s\nGit-Commit: %s\nGit-Branch: %s", username, version, commit, branch) -func (sq *Squadron) cleanupOutput(chartPath string) error { - if _, err := os.Stat(chartPath); err == nil { - if err := os.RemoveAll(chartPath); err != nil { - logrus.Warnf("could not delete chart output directory: %q", err) - } - } - if _, err := os.Stat(chartPath); os.IsNotExist(err) { - if err := os.MkdirAll(chartPath, 0o744); err != nil { - return fmt.Errorf("could not create chart output directory: %w", err) - } - } - return nil -} + wg, gctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) -func (sq *Squadron) generateChart(units Units, chartPath, chartName, version string) error { - chart := newChart(chartName, version) - values := map[string]interface{}{} - if sq.c.Global != nil { - values["global"] = sq.c.Global - } - _ = units.Iterate(func(name string, unit *Unit) error { - chart.addDependency(name, unit.Chart) - values[name] = unit.Values - return nil + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + wg.Go(func() error { + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err + } + valueBytes, err := v.ValuesYAML(sq.c.Global) + if err != nil { + return err + } + + // update local chart dependencies + // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql + if strings.HasPrefix(v.Chart.Repository, "file:///") { + pterm.Debug.Printfln("running helm dependency update for %s", v.Chart.Repository) + if out, err := util.NewHelmCommand(). + Stdout(os.Stdout). + Args("dependency", "update"). + Cwd(strings.TrimPrefix(v.Chart.Repository, "file://")). + Run(ctx); err != nil { + return errors.Wrap(err, out) + } + } + + // install chart + pterm.Debug.Printfln("running helm upgrade for %s", name) + cmd := util.NewHelmCommand(). + Stdin(bytes.NewReader(valueBytes)). + Stdout(os.Stdout). + Args("upgrade", name, "--install"). + Args("--set", fmt.Sprintf("squadron=%s,unit=%s", key, k)). + Args("--description", description). + Args("--namespace", namespace). + Args("--dependency-update"). + Args("--install"). + Args("-values", "-"). + Args(helmArgs...) + + if strings.Contains(v.Chart.Repository, "file://") { + cmd.Args(strings.TrimPrefix(v.Chart.Repository, "file://")) + } else { + cmd.Args(v.Chart.Name, "--repo", v.Chart.Repository, "--version", v.Chart.Version) + } + + if out, err := cmd.Run(gctx); err != nil { + return errors.Wrap(err, out) + } + + return nil + }) + return nil + }) }) - return chart.generate(chartPath, values) + + return wg.Wait() } -func (sq *Squadron) generateValues(values map[string]interface{}, vPath, vName string) error { - if values == nil { - values = map[string]interface{}{} - } - if sq.c.Global != nil { - values["global"] = sq.c.Global +func (sq *Squadron) Template(ctx context.Context, helmArgs []string) (string, error) { + var ret bytes.Buffer + + err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err + } + valueBytes, err := v.ValuesYAML(sq.c.Global) + if err != nil { + return err + } + + pterm.Debug.Printfln("running helm template for chart: %s", name) + cmd := util.NewHelmCommand().Args("template", k). + Stdin(bytes.NewReader(valueBytes)). + Stdout(&ret). + Args("--dependency-update"). + Args("--namespace", namespace). + Args("--set", fmt.Sprintf("squadron=%s", key)). + Args("--set", fmt.Sprintf("unit=%s", k)). + Args("--values", "-"). + Args(helmArgs...) + if strings.Contains(v.Chart.Repository, "file://") { + file := strings.TrimPrefix(v.Chart.Repository, "file://") + if !strings.HasPrefix(file, ".") { + file = "/" + file + } + cmd.Args(file) + } else { + cmd.Args(v.Chart.Name, "--repo", v.Chart.Repository, "--version", v.Chart.Version) + } + if out, err := cmd.Run(ctx); err != nil { + return errors.Wrap(err, out) + } + + return nil + }) + }) + if err != nil { + return "", err } - return util.GenerateYaml(path.Join(vPath, vName+".yaml"), values) + + return ret.String(), nil } diff --git a/squadron_test.go b/squadron_test.go index 54c51b8..6fd48cc 100644 --- a/squadron_test.go +++ b/squadron_test.go @@ -2,121 +2,86 @@ package squadron_test import ( "context" + "os" "path" "testing" "github.com/foomo/squadron" - testutils "github.com/foomo/squadron/tests/utils" - "github.com/foomo/squadron/util" + "github.com/foomo/squadron/internal/testutils" + "github.com/foomo/squadron/internal/util" + "github.com/stretchr/testify/require" ) func TestConfigSimpleSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-simple", "squadron.yaml"), + tests := []struct { + name string + files []string + squadron string + units []string + }{ + { + name: "blank", + files: []string{"squadron.yaml"}, }, - path.Join("testdata", "config-simple", "squadron.yaml.snapshot"), - nil, - true, - ) -} - -func TestConfigNoValuesSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-no-values", "squadron.yaml"), - }, - path.Join("testdata", "config-no-values", "squadron.yaml.snapshot"), - nil, - true, - ) -} - -func TestConfigOverrideSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-override", "squadron.yaml"), - path.Join("testdata", "config-override", "squadron.override.yaml"), + { + name: "simple", + files: []string{"squadron.yaml"}, }, - path.Join("testdata", "config-override", "squadron.yaml.snapshot"), - nil, - true, - ) -} - -func TestConfigGlobalSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-global", "squadron.yaml"), - path.Join("testdata", "config-global", "squadron.override.yaml"), + { + name: "override", + files: []string{"squadron.yaml", "squadron.override.yaml"}, }, - path.Join("testdata", "config-global", "squadron.yaml.snapshot"), - nil, - true, - ) -} - -func TestConfigTemplateSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-template", "squadron.yaml"), + { + name: "global", + files: []string{"squadron.yaml", "squadron.override.yaml"}, }, - path.Join("testdata", "config-template", "squadron.yaml.snapshot"), - nil, - true, - ) -} - -func TestConfigTemplateFrontendSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-template-frontend", "squadron.yaml"), + { + name: "template", + files: []string{"squadron.yaml"}, }, - path.Join("testdata", "config-template-frontend", "squadron.yaml.snapshot"), - []string{"frontend"}, - true, - ) -} - -func TestConfigNoRenderSnapshot(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-no-render", "squadron.yaml"), - }, - path.Join("testdata", "config-no-render", "squadron.yaml.snapshot"), - nil, - false, - ) -} + } -func TestConfigOverrideSnapshotNulled(t *testing.T) { - testConfigSnapshot(t, - []string{ - path.Join("testdata", "config-override-null", "squadron.yaml"), - path.Join("testdata", "config-override-null", "squadron.override.yaml"), - }, - path.Join("testdata", "config-override-null", "squadron.yaml.snapshot"), - nil, - true, - ) + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + config(tt, test.name, test.files, test.squadron, test.units) + }) + } } -func testConfigSnapshot(t *testing.T, configs []string, snapshot string, units []string, render bool) { +func config(t *testing.T, name string, files []string, squadronName string, unitNames []string) { t.Helper() var cwd string - testutils.Must(t, util.ValidatePath(".", &cwd)) + ctx := context.TODO() + require.NoError(t, util.ValidatePath(".", &cwd)) + require.NoError(t, os.Setenv("PROJECT_ROOT", ".")) - sq := squadron.New(cwd, "", configs) + for i, file := range files { + files[i] = path.Join("testdata", name, file) + } + sq := squadron.New(cwd, "default", files) - testutils.Must(t, sq.MergeConfigFiles(), "failed to merge files") + { + require.NoError(t, sq.MergeConfigFiles(), "failed to merge files") + } - if units != nil { - testutils.Must(t, sq.FilterConfig(units), "failed to filter units") + { + require.NoError(t, sq.FilterConfig(squadronName, unitNames), "failed to filter config") + testutils.Snapshot(t, path.Join("testdata", name, "snapshop-config-norender.yaml"), sq.ConfigYAML()) } - if render { - testutils.Must(t, sq.RenderConfig(context.Background()), "failed to render config") + { + require.NoError(t, sq.RenderConfig(ctx), "failed to render config") + testutils.Snapshot(t, path.Join("testdata", name, "snapshop-config.yaml"), sq.ConfigYAML()) } - testutils.MustCheckSnapshot(t, snapshot, sq.GetConfigYAML()) + { + require.NoError(t, sq.RenderConfig(ctx), "failed to render config") + testutils.Snapshot(t, path.Join("testdata", name, "snapshop-config.yaml"), sq.ConfigYAML()) + } + + { + out, err := sq.Template(ctx, nil) + require.NoError(t, err, "failed to render template") + testutils.Snapshot(t, path.Join("testdata", name, "snapshop-template.yaml"), out) + } } diff --git a/testdata/blank/snapshop-config-norender.yaml b/testdata/blank/snapshop-config-norender.yaml new file mode 100644 index 0000000..98eb5e3 --- /dev/null +++ b/testdata/blank/snapshop-config-norender.yaml @@ -0,0 +1 @@ +version: "2.0" diff --git a/testdata/blank/snapshop-config.yaml b/testdata/blank/snapshop-config.yaml new file mode 100644 index 0000000..98eb5e3 --- /dev/null +++ b/testdata/blank/snapshop-config.yaml @@ -0,0 +1 @@ +version: "2.0" diff --git a/testdata/blank/snapshop-template.yaml b/testdata/blank/snapshop-template.yaml new file mode 100644 index 0000000..e69de29 diff --git a/testdata/blank/squadron.yaml b/testdata/blank/squadron.yaml new file mode 100644 index 0000000..98eb5e3 --- /dev/null +++ b/testdata/blank/squadron.yaml @@ -0,0 +1 @@ +version: "2.0" diff --git a/testdata/global/snapshop-config-norender.yaml b/testdata/global/snapshop-config-norender.yaml new file mode 100644 index 0000000..6bcb5e8 --- /dev/null +++ b/testdata/global/snapshop-config-norender.yaml @@ -0,0 +1,7 @@ +version: "2.0" +global: + bar: + - one + - two + baz: null + foo: two diff --git a/testdata/global/snapshop-config.yaml b/testdata/global/snapshop-config.yaml new file mode 100644 index 0000000..6bcb5e8 --- /dev/null +++ b/testdata/global/snapshop-config.yaml @@ -0,0 +1,7 @@ +version: "2.0" +global: + bar: + - one + - two + baz: null + foo: two diff --git a/testdata/global/snapshop-template.yaml b/testdata/global/snapshop-template.yaml new file mode 100644 index 0000000..e69de29 diff --git a/testdata/override/snapshop-config-norender.yaml b/testdata/override/snapshop-config-norender.yaml new file mode 100644 index 0000000..f5016a4 --- /dev/null +++ b/testdata/override/snapshop-config-norender.yaml @@ -0,0 +1,22 @@ +version: "2.0" +squadron: + storefinder: + frontend: + chart: + name: frontend + repository: file://<% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + version: 0.0.1 + builds: + default: + args: + - foo=foo + - bar=bar + - bar=baz + - baz=baz + dockerfile: Dockerfile + image: docker.mycompany.com/mycomapny/frontend + tag: nightly + values: + image: + repository: <% .Squadron.storefinder.frontend.builds.default.image %> + tag: <% .Squadron.storefinder.frontend.builds.default.tag %> diff --git a/testdata/override/snapshop-config.yaml b/testdata/override/snapshop-config.yaml new file mode 100644 index 0000000..c6bb393 --- /dev/null +++ b/testdata/override/snapshop-config.yaml @@ -0,0 +1,22 @@ +version: "2.0" +squadron: + storefinder: + frontend: + chart: + name: frontend + repository: file://./_examples/common/charts/frontend + version: 0.0.1 + builds: + default: + args: + - foo=foo + - bar=bar + - bar=baz + - baz=baz + dockerfile: Dockerfile + image: docker.mycompany.com/mycomapny/frontend + tag: nightly + values: + image: + repository: docker.mycompany.com/mycomapny/frontend + tag: nightly diff --git a/testdata/override/snapshop-template.yaml b/testdata/override/snapshop-template.yaml new file mode 100644 index 0000000..1135a41 --- /dev/null +++ b/testdata/override/snapshop-template.yaml @@ -0,0 +1,49 @@ +--- +# Source: frontend/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + ports: + - name: http + port: 80 +--- +# Source: frontend/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + template: + metadata: + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + spec: + containers: + - name: frontend + image: nginx:latest + ports: + - name: http + protocol: TCP + containerPort: 80 diff --git a/testdata/simple/snapshop-config-norender.yaml b/testdata/simple/snapshop-config-norender.yaml new file mode 100644 index 0000000..93d19a6 --- /dev/null +++ b/testdata/simple/snapshop-config-norender.yaml @@ -0,0 +1,12 @@ +version: "2.0" +squadron: + storefinder: + frontend: + chart: + name: frontend + repository: file://<% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + version: 0.0.1 + values: + image: + repository: nginx + tag: latest diff --git a/testdata/simple/snapshop-config.yaml b/testdata/simple/snapshop-config.yaml new file mode 100644 index 0000000..6cff186 --- /dev/null +++ b/testdata/simple/snapshop-config.yaml @@ -0,0 +1,12 @@ +version: "2.0" +squadron: + storefinder: + frontend: + chart: + name: frontend + repository: file://./_examples/common/charts/frontend + version: 0.0.1 + values: + image: + repository: nginx + tag: latest diff --git a/testdata/simple/snapshop-template.yaml b/testdata/simple/snapshop-template.yaml new file mode 100644 index 0000000..1135a41 --- /dev/null +++ b/testdata/simple/snapshop-template.yaml @@ -0,0 +1,49 @@ +--- +# Source: frontend/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + ports: + - name: http + port: 80 +--- +# Source: frontend/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + template: + metadata: + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + spec: + containers: + - name: frontend + image: nginx:latest + ports: + - name: http + protocol: TCP + containerPort: 80 diff --git a/testdata/simple/squadron.yaml b/testdata/simple/squadron.yaml new file mode 100644 index 0000000..2950ea4 --- /dev/null +++ b/testdata/simple/squadron.yaml @@ -0,0 +1,10 @@ +version: "2.0" + +squadron: + storefinder: + frontend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + values: + image: + tag: latest + repository: nginx diff --git a/testdata/template/snapshop-config-norender.yaml b/testdata/template/snapshop-config-norender.yaml new file mode 100644 index 0000000..f48cf5b --- /dev/null +++ b/testdata/template/snapshop-config-norender.yaml @@ -0,0 +1,39 @@ +version: "2.0" +global: + host: mycompany.com +squadron: + storefinder: + backend: + chart: + name: backend + repository: file://<% env "PROJECT_ROOT" %>/_examples/common/charts/backend + version: 0.0.1 + builds: + default: + image: docker.mycompany.com/mycomapny/frontend-admin + tag: latest + values: + image: + repository: <% .Squadron.storefinder.backend.builds.default.image %> + tag: <% .Squadron.storefinder.backend.builds.default.tag %> + frontend: + chart: + name: frontend + repository: file://<% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + version: 0.0.1 + builds: + default: + image: docker.mycompany.com/mycomapny/frontend + tag: latest + values: + env: + BASE64: <% base64 "1234567890" %> + DEFAULT_INDEX_VALUE: <% defaultIndex .Global "notexists" "fallback" %> + DEFAULT_VALUE: <% "" | default "fallback" %> + ENV: <% env "SHELL" %> + GLOBAL: <% .Global.host %> + image: + repository: <% .Squadron.storefinder.frontend.builds.default.image %> + tag: <% .Squadron.storefinder.frontend.builds.default.tag %> + values: | + <% file "testdata/template/squadron.values.yaml" | indent 5 %> diff --git a/testdata/template/snapshop-config.yaml b/testdata/template/snapshop-config.yaml new file mode 100644 index 0000000..dac7aa5 --- /dev/null +++ b/testdata/template/snapshop-config.yaml @@ -0,0 +1,45 @@ +version: "2.0" +global: + host: mycompany.com +squadron: + storefinder: + backend: + chart: + name: backend + repository: file://./_examples/common/charts/backend + version: 0.0.1 + builds: + default: + image: docker.mycompany.com/mycomapny/frontend-admin + tag: latest + values: + image: + repository: docker.mycompany.com/mycomapny/frontend-admin + tag: latest + frontend: + chart: + name: frontend + repository: file://./_examples/common/charts/frontend + version: 0.0.1 + builds: + default: + image: docker.mycompany.com/mycomapny/frontend + tag: latest + values: + env: + BASE64: MTIzNDU2Nzg5MA== + DEFAULT_INDEX_VALUE: fallback + DEFAULT_VALUE: fallback + ENV: /bin/zsh + GLOBAL: mycompany.com + image: + repository: docker.mycompany.com/mycomapny/frontend + tag: latest + values: | + foo: bar + bar: + - foo + - bar + env: /bin/zsh + global: mycompany.com + base64: MTIzNDU2Nzg5MA== diff --git a/testdata/template/snapshop-template.yaml b/testdata/template/snapshop-template.yaml new file mode 100644 index 0000000..e29f28e --- /dev/null +++ b/testdata/template/snapshop-template.yaml @@ -0,0 +1,98 @@ +--- +# Source: backend/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: backend + labels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: backend-0.0.1 +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + ports: + - name: http + port: 80 +--- +# Source: backend/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend + labels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: backend-0.0.1 +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + template: + metadata: + labels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + spec: + containers: + - name: backend + image: nginx:latest + ports: + - name: http + protocol: TCP + containerPort: 80 +--- +# Source: frontend/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + ports: + - name: http + port: 80 +--- +# Source: frontend/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + template: + metadata: + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + spec: + containers: + - name: frontend + image: nginx:latest + ports: + - name: http + protocol: TCP + containerPort: 80 diff --git a/tests/utils/must.go b/tests/utils/must.go deleted file mode 100644 index 6a4ec96..0000000 --- a/tests/utils/must.go +++ /dev/null @@ -1,14 +0,0 @@ -package testutils - -import ( - "fmt" - "testing" -) - -func Must(t *testing.T, err error, args ...interface{}) { - t.Helper() - if err != nil { - args = append([]interface{}{fmt.Sprintf("err: %s", err)}, args...) - t.Fatal(args...) - } -} diff --git a/tests/utils/snapshot.go b/tests/utils/snapshot.go deleted file mode 100644 index 4456c85..0000000 --- a/tests/utils/snapshot.go +++ /dev/null @@ -1,34 +0,0 @@ -package testutils - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -// MustWriteSnapshot updates the snapshot file for a given test t. -func MustWriteSnapshot(t *testing.T, name string, content string) { - t.Helper() - Must(t, os.WriteFile(name, []byte(content), 0o600), "failed to update snapshot", name) -} - -// MustReadSnapshot reads the snapshot file for a given test t. -func MustReadSnapshot(t *testing.T, name string) string { - t.Helper() - g, err := os.ReadFile(name) - Must(t, err, "failed reading file", name) - return string(g) -} - -// MustCheckSnapshot compares v with its snapshot file -func MustCheckSnapshot(t *testing.T, name, yaml string) { - t.Helper() - if *UpdateFlag { - MustWriteSnapshot(t, name, yaml) - } - snapshot := MustReadSnapshot(t, name) - if !assert.YAMLEq(t, snapshot, yaml) { - t.Fatalf("err: %s not equal to %s", yaml, snapshot) - } -} diff --git a/units.go b/units.go deleted file mode 100644 index 7c74d7f..0000000 --- a/units.go +++ /dev/null @@ -1,62 +0,0 @@ -package squadron - -import ( - "sort" - - "github.com/pkg/errors" -) - -type Units map[string]*Unit - -func (u Units) Keys() []string { - if len(u) == 0 { - return nil - } - ret := make([]string, 0, len(u)) - for name := range u { - ret = append(ret, name) - } - sort.Strings(ret) - return ret -} - -func (u Units) Values() []*Unit { - if len(u) == 0 { - return nil - } - ret := make([]*Unit, len(u)) - for _, name := range u.Keys() { - ret = append(ret, u[name]) - } - return ret -} - -func (u Units) Filter(names []string) (Units, error) { - if len(u) == 0 { - return nil, nil - } - if len(names) == 0 { - return u, nil - } - ret := make(Units, len(u)) - for _, name := range names { - if unit, ok := u[name]; !ok { - return nil, errors.Errorf("unknown unit: %s", name) - } else { - ret[name] = unit - } - } - return ret, nil -} - -func (u Units) Iterate(i func(name string, unit *Unit) error) error { - if len(u) == 0 { - return nil - } - for _, name := range u.Keys() { - if err := i(name, u[name]); err != nil { - return err - } - } - return nil -} diff --git a/util/helm.go b/util/helm.go deleted file mode 100644 index 2b973cb..0000000 --- a/util/helm.go +++ /dev/null @@ -1,21 +0,0 @@ -package util - -import ( - "context" -) - -type HelmCmd struct { - Cmd -} - -func NewHelmCommand() *HelmCmd { - return &HelmCmd{*NewCommand("helm")} -} - -func (c HelmCmd) UpdateDependency(ctx context.Context, chartPath string) (string, error) { - return c.Base().Args("dependency", "update", chartPath).Run(ctx) -} - -func (c HelmCmd) Package(ctx context.Context, chartPath, destPath string) (string, error) { - return c.Base().Args("package", chartPath, "--destination", destPath).Run(ctx) -} From bede368045dc1d96e1881848bb726aa338d02670 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 21 Sep 2023 13:25:18 +0200 Subject: [PATCH 06/63] feat: add tags --- .../squadrons/checkout/backend/squadron.yaml | 1 + .../squadrons/checkout/frontend/squadron.yaml | 1 + .../storefinder/backend/squadron.yaml | 1 + .../storefinder/frontend/squadron.yaml | 1 + cmd/actions/build.go | 3 +- cmd/actions/config.go | 6 +-- cmd/actions/diff.go | 2 +- cmd/actions/down.go | 5 +- cmd/actions/list.go | 6 ++- cmd/actions/push.go | 5 +- cmd/actions/rollback.go | 5 +- cmd/actions/root.go | 1 + cmd/actions/status.go | 5 +- cmd/actions/template.go | 5 +- cmd/actions/up.go | 5 +- internal/config/build.go | 3 +- internal/config/map.go | 9 ++++ internal/config/tag.go | 3 ++ internal/config/unit.go | 1 + squadron.go | 34 ++++++++++--- squadron_test.go | 17 +++++-- testdata/tags/snapshop-config-norender.yaml | 14 ++++++ testdata/tags/snapshop-config.yaml | 14 ++++++ testdata/tags/snapshop-template.yaml | 49 +++++++++++++++++++ testdata/tags/squadron.yaml | 33 +++++++++++++ 25 files changed, 198 insertions(+), 31 deletions(-) create mode 100644 internal/config/tag.go create mode 100644 testdata/tags/snapshop-config-norender.yaml create mode 100644 testdata/tags/snapshop-config.yaml create mode 100644 testdata/tags/snapshop-template.yaml create mode 100644 testdata/tags/squadron.yaml diff --git a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml index df96fcd..7bebf5c 100644 --- a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml +++ b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml @@ -5,6 +5,7 @@ squadron: checkout: backend: chart: <% env "PROJECT_ROOT" %>/../common/charts/backend + tags: [ "backend" ] builds: default: tag: <% .Global.docker.tag | quote %> diff --git a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml index dca1fc0..998cde1 100644 --- a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml +++ b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml @@ -5,6 +5,7 @@ squadron: checkout: frontend: chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend + tags: [ "frontend" ] builds: default: tag: "<% .Global.docker.tag %>" diff --git a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml index 511e809..444f250 100644 --- a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml +++ b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml @@ -5,6 +5,7 @@ squadron: storefinder: backend: chart: <% env "PROJECT_ROOT" %>/../common/charts/backend + tags: [ "backend" ] builds: default: tag: <% .Global.docker.tag | quote %> diff --git a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml index 6eb6297..d211efe 100644 --- a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml +++ b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml @@ -5,6 +5,7 @@ squadron: storefinder: frontend: chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend + tags: [ "frontend" ] builds: default: tag: "<% .Global.docker.tag %>" diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 9016f31..6e8d790 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -8,6 +8,7 @@ import ( func init() { buildCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes built squadron units to the registry") buildCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") + buildCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") buildCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") buildCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") } @@ -25,7 +26,7 @@ var buildCmd = &cobra.Command{ } squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/config.go b/cmd/actions/config.go index 5b6784f..bebf3dd 100644 --- a/cmd/actions/config.go +++ b/cmd/actions/config.go @@ -3,14 +3,14 @@ package actions import ( "fmt" + "github.com/foomo/squadron" "github.com/foomo/squadron/internal/util" "github.com/spf13/cobra" - - "github.com/foomo/squadron" ) func init() { configCmd.Flags().BoolVar(&flagNoRender, "no-render", false, "don't render the config template") + configCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var configCmd = &cobra.Command{ @@ -26,7 +26,7 @@ var configCmd = &cobra.Command{ } squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/diff.go b/cmd/actions/diff.go index 8b7ec17..aad360d 100644 --- a/cmd/actions/diff.go +++ b/cmd/actions/diff.go @@ -7,7 +7,7 @@ import ( ) func init() { - diffCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + diffCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") diffCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") } diff --git a/cmd/actions/down.go b/cmd/actions/down.go index 34c56ba..2ab1813 100644 --- a/cmd/actions/down.go +++ b/cmd/actions/down.go @@ -8,7 +8,8 @@ import ( func init() { downCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - downCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "Specifies the namespace") + downCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") + downCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var downCmd = &cobra.Command{ @@ -26,7 +27,7 @@ var downCmd = &cobra.Command{ args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/list.go b/cmd/actions/list.go index 28e70b9..59cbc24 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -10,6 +10,10 @@ import ( var flagPrefixSquadron bool +func init() { + listCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") +} + var listCmd = &cobra.Command{ Use: "list [SQUADRON]", Short: "list squadron units", @@ -23,7 +27,7 @@ var listCmd = &cobra.Command{ } squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/push.go b/cmd/actions/push.go index 10627f1..41e48f8 100644 --- a/cmd/actions/push.go +++ b/cmd/actions/push.go @@ -6,11 +6,12 @@ import ( ) func init() { - pushCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + pushCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") pushCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units") pushCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") pushCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") pushCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") + pushCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var pushCmd = &cobra.Command{ @@ -25,7 +26,7 @@ var pushCmd = &cobra.Command{ } squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/rollback.go b/cmd/actions/rollback.go index 9b6fb90..aa333fb 100644 --- a/cmd/actions/rollback.go +++ b/cmd/actions/rollback.go @@ -8,8 +8,9 @@ import ( func init() { rollbackCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - rollbackCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + rollbackCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") rollbackCmd.Flags().StringVarP(&flagRevision, "revision", "r", "", "specifies the revision to roll back to") + rollbackCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var rollbackCmd = &cobra.Command{ @@ -26,7 +27,7 @@ var rollbackCmd = &cobra.Command{ args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/root.go b/cmd/actions/root.go index 9049b1d..7bfd6ed 100644 --- a/cmd/actions/root.go +++ b/cmd/actions/root.go @@ -46,6 +46,7 @@ var ( flagParallel int flagBuildArgs []string flagPushArgs []string + flagTags []string flagDiff bool flagFiles []string ) diff --git a/cmd/actions/status.go b/cmd/actions/status.go index 1ca4b2d..d83e47e 100644 --- a/cmd/actions/status.go +++ b/cmd/actions/status.go @@ -8,7 +8,8 @@ import ( func init() { statusCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - statusCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + statusCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") + statusCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var statusCmd = &cobra.Command{ @@ -25,7 +26,7 @@ var statusCmd = &cobra.Command{ args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/template.go b/cmd/actions/template.go index 4ccd753..e411c2d 100644 --- a/cmd/actions/template.go +++ b/cmd/actions/template.go @@ -9,7 +9,8 @@ import ( ) func init() { - templateCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + templateCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") + templateCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var templateCmd = &cobra.Command{ @@ -27,7 +28,7 @@ var templateCmd = &cobra.Command{ args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/cmd/actions/up.go b/cmd/actions/up.go index d0e1d78..27c36ff 100644 --- a/cmd/actions/up.go +++ b/cmd/actions/up.go @@ -10,12 +10,13 @@ import ( ) func init() { - upCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace") + upCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") upCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units") upCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes units to the registry") upCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") upCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") upCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") + upCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var upCmd = &cobra.Command{ @@ -32,7 +33,7 @@ var upCmd = &cobra.Command{ args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) - if err := sq.FilterConfig(squadronName, unitNames); err != nil { + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { return err } diff --git a/internal/config/build.go b/internal/config/build.go index d91625c..1128cff 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -4,10 +4,9 @@ import ( "context" "fmt" + "github.com/foomo/squadron/internal/util" "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" - - "github.com/foomo/squadron/internal/util" ) type Build struct { diff --git a/internal/config/map.go b/internal/config/map.go index 6b3e71c..9b0c0e5 100644 --- a/internal/config/map.go +++ b/internal/config/map.go @@ -80,6 +80,15 @@ func (m Map[T]) Filter(keys ...string) error { return nil } +func (m Map[T]) FilterFn(handler func(key string, value T) bool) error { + for key, value := range m { + if !handler(key, value) { + delete(m, key) + } + } + return nil +} + func (m Map[T]) Iterate(handler func(key string, value T) error) error { if len(m) == 0 { return nil diff --git a/internal/config/tag.go b/internal/config/tag.go new file mode 100644 index 0000000..5493bd5 --- /dev/null +++ b/internal/config/tag.go @@ -0,0 +1,3 @@ +package config + +type Tag string diff --git a/internal/config/unit.go b/internal/config/unit.go index 78c1cf7..4b5ee9b 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -14,6 +14,7 @@ import ( type Unit struct { Chart helm.Dependency `yaml:"chart,omitempty"` + Tags []Tag `yaml:"tags,omitempty"` Builds map[string]Build `yaml:"builds,omitempty"` Values map[string]interface{} `yaml:"values,omitempty"` } diff --git a/squadron.go b/squadron.go index 20b67ab..bbfa986 100644 --- a/squadron.go +++ b/squadron.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "os/exec" + "slices" "strings" "text/template" @@ -102,13 +103,11 @@ func (sq *Squadron) MergeConfigFiles() error { return nil } -func (sq *Squadron) FilterConfig(squadron string, units []string) error { - if len(squadron) == 0 { - return nil - } - - if err := sq.Config().Squadrons.Filter(squadron); err != nil { - return err +func (sq *Squadron) FilterConfig(squadron string, units, tags []string) error { + if len(squadron) > 0 { + if err := sq.Config().Squadrons.Filter(squadron); err != nil { + return err + } } if len(squadron) > 0 && len(units) > 0 { @@ -117,6 +116,27 @@ func (sq *Squadron) FilterConfig(squadron string, units []string) error { } } + if len(tags) > 0 { + if err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.FilterFn(func(k string, v *config.Unit) bool { + for _, tag := range tags { + if strings.HasPrefix(tag, "-") { + if slices.Contains(v.Tags, config.Tag(strings.TrimPrefix(tag, "-"))) { + return false + } + } else if !slices.Contains(v.Tags, config.Tag(tag)) { + return false + } + } + return true + }) + }); err != nil { + return err + } + } + + sq.c.Trim() + value, err := yamlv2.Marshal(sq.c) if err != nil { return err diff --git a/squadron_test.go b/squadron_test.go index 6fd48cc..f50cdad 100644 --- a/squadron_test.go +++ b/squadron_test.go @@ -9,15 +9,20 @@ import ( "github.com/foomo/squadron" "github.com/foomo/squadron/internal/testutils" "github.com/foomo/squadron/internal/util" + "github.com/pterm/pterm" "github.com/stretchr/testify/require" ) func TestConfigSimpleSnapshot(t *testing.T) { + pterm.EnableDebugMessages() + require.NoError(t, os.Setenv("PROJECT_ROOT", ".")) + tests := []struct { name string files []string squadron string units []string + tags []string }{ { name: "blank", @@ -39,21 +44,25 @@ func TestConfigSimpleSnapshot(t *testing.T) { name: "template", files: []string{"squadron.yaml"}, }, + { + name: "tags", + tags: []string{"backend", "-skip"}, + files: []string{"squadron.yaml"}, + }, } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { - config(tt, test.name, test.files, test.squadron, test.units) + config(tt, test.name, test.files, test.squadron, test.units, test.tags) }) } } -func config(t *testing.T, name string, files []string, squadronName string, unitNames []string) { +func config(t *testing.T, name string, files []string, squadronName string, unitNames, tags []string) { t.Helper() var cwd string ctx := context.TODO() require.NoError(t, util.ValidatePath(".", &cwd)) - require.NoError(t, os.Setenv("PROJECT_ROOT", ".")) for i, file := range files { files[i] = path.Join("testdata", name, file) @@ -65,7 +74,7 @@ func config(t *testing.T, name string, files []string, squadronName string, unit } { - require.NoError(t, sq.FilterConfig(squadronName, unitNames), "failed to filter config") + require.NoError(t, sq.FilterConfig(squadronName, unitNames, tags), "failed to filter config") testutils.Snapshot(t, path.Join("testdata", name, "snapshop-config-norender.yaml"), sq.ConfigYAML()) } diff --git a/testdata/tags/snapshop-config-norender.yaml b/testdata/tags/snapshop-config-norender.yaml new file mode 100644 index 0000000..4242767 --- /dev/null +++ b/testdata/tags/snapshop-config-norender.yaml @@ -0,0 +1,14 @@ +version: "2.0" +squadron: + checkout: + backend: + chart: + name: backend + repository: file://<% env "PROJECT_ROOT" %>/_examples/common/charts/backend + version: 0.0.1 + tags: + - backend + values: + image: + repository: nginx + tag: latest diff --git a/testdata/tags/snapshop-config.yaml b/testdata/tags/snapshop-config.yaml new file mode 100644 index 0000000..8627480 --- /dev/null +++ b/testdata/tags/snapshop-config.yaml @@ -0,0 +1,14 @@ +version: "2.0" +squadron: + checkout: + backend: + chart: + name: backend + repository: file://./_examples/common/charts/backend + version: 0.0.1 + tags: + - backend + values: + image: + repository: nginx + tag: latest diff --git a/testdata/tags/snapshop-template.yaml b/testdata/tags/snapshop-template.yaml new file mode 100644 index 0000000..16d3567 --- /dev/null +++ b/testdata/tags/snapshop-template.yaml @@ -0,0 +1,49 @@ +--- +# Source: backend/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: backend + labels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: backend-0.0.1 +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + ports: + - name: http + port: 80 +--- +# Source: backend/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend + labels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: backend-0.0.1 +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + template: + metadata: + labels: + app.kubernetes.io/name: backend + app.kubernetes.io/component: backend + spec: + containers: + - name: backend + image: nginx:latest + ports: + - name: http + protocol: TCP + containerPort: 80 diff --git a/testdata/tags/squadron.yaml b/testdata/tags/squadron.yaml new file mode 100644 index 0000000..4a95ee3 --- /dev/null +++ b/testdata/tags/squadron.yaml @@ -0,0 +1,33 @@ +version: "2.0" + +squadron: + storefinder: + frontend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + tags: ["frontend"] + values: + image: + tag: latest + repository: nginx + backend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/backend + tags: ["backend", "skip"] + values: + image: + tag: latest + repository: nginx + checkout: + frontend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend + tags: ["frontend"] + values: + image: + tag: latest + repository: nginx + backend: + chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/backend + tags: ["backend"] + values: + image: + tag: latest + repository: nginx From 442323c93feb06ee27b50b61ee5df1653aa5024c Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Sep 2023 10:04:00 +0200 Subject: [PATCH 07/63] feat: add builds for dependencies --- .../common/docker/backend-base.Dockerfile | 1 + _examples/common/docker/backend.Dockerfile | 6 +- .../common/docker/frontend-base.Dockerfile | 1 + _examples/common/docker/frontend.Dockerfile | 4 +- _examples/monorepo/Makefile | 2 +- .../squadrons/checkout/backend/go.mod | 4 +- .../squadrons/checkout/backend/squadron.yaml | 4 + .../squadrons/checkout/frontend/index.html | 2 +- .../squadrons/checkout/frontend/squadron.yaml | 4 + _examples/monorepo/squadrons/squadron.yaml | 10 ++ .../squadrons/storefinder/backend/go.mod | 2 +- .../storefinder/backend/squadron.yaml | 4 + .../storefinder/frontend/squadron.yaml | 4 + cmd/actions/list.go | 20 +++- internal/config/build.go | 102 +++++++++++++----- internal/config/config.go | 37 ++++++- internal/util/cmd.go | 9 -- squadron.go | 29 +++++ .../override/snapshop-config-norender.yaml | 2 +- testdata/override/snapshop-config.yaml | 2 +- .../template/snapshop-config-norender.yaml | 4 +- testdata/template/snapshop-config.yaml | 4 +- 22 files changed, 201 insertions(+), 56 deletions(-) create mode 100644 _examples/common/docker/backend-base.Dockerfile create mode 100644 _examples/common/docker/frontend-base.Dockerfile diff --git a/_examples/common/docker/backend-base.Dockerfile b/_examples/common/docker/backend-base.Dockerfile new file mode 100644 index 0000000..718b186 --- /dev/null +++ b/_examples/common/docker/backend-base.Dockerfile @@ -0,0 +1 @@ +FROM golang:alpine diff --git a/_examples/common/docker/backend.Dockerfile b/_examples/common/docker/backend.Dockerfile index 23b8a3b..6973d30 100644 --- a/_examples/common/docker/backend.Dockerfile +++ b/_examples/common/docker/backend.Dockerfile @@ -1,4 +1,6 @@ -FROM golang:alpine as builder +ARG BASE_IMAGE=golang +ARG BASE_IMAGE_TAG=alpine +FROM ${BASE_IMAGE}:${BASE_IMAGE_TAG} as builder ENV CGO_ENABLED=0 @@ -8,7 +10,7 @@ WORKDIR /src RUN go build -ldflags "-w -s" -trimpath -o /go/bin/service . -FROM alpine:latest as development +FROM alpine:latest COPY --from=builder /go/bin/service /usr/local/bin/service diff --git a/_examples/common/docker/frontend-base.Dockerfile b/_examples/common/docker/frontend-base.Dockerfile new file mode 100644 index 0000000..5861e3d --- /dev/null +++ b/_examples/common/docker/frontend-base.Dockerfile @@ -0,0 +1 @@ +FROM nginx:latest diff --git a/_examples/common/docker/frontend.Dockerfile b/_examples/common/docker/frontend.Dockerfile index 4989ead..693d9e1 100644 --- a/_examples/common/docker/frontend.Dockerfile +++ b/_examples/common/docker/frontend.Dockerfile @@ -1,3 +1,5 @@ -FROM nginx:latest +ARG BASE_IMAGE=nginx +ARG BASE_IMAGE_TAG=latest +FROM ${BASE_IMAGE}:${BASE_IMAGE_TAG} COPY ./index.html /etc/nginx/templates/. diff --git a/_examples/monorepo/Makefile b/_examples/monorepo/Makefile index 21164a4..c922eff 100644 --- a/_examples/monorepo/Makefile +++ b/_examples/monorepo/Makefile @@ -9,7 +9,7 @@ files=$(shell find . -name 'squadron.yaml' | tail -r | xargs echo -n | tr " ", " .PHONY: list ## Show config list: - @go run ../../cmd/main.go -f ${files} list + @go run ../../cmd/main.go -f ${files} list --builds .PHONY: config ## Show config diff --git a/_examples/monorepo/squadrons/checkout/backend/go.mod b/_examples/monorepo/squadrons/checkout/backend/go.mod index d7d1b45..fa598b7 100644 --- a/_examples/monorepo/squadrons/checkout/backend/go.mod +++ b/_examples/monorepo/squadrons/checkout/backend/go.mod @@ -1,3 +1,3 @@ -module github.com/foomo/squadron/exmpale/monorepo/storefinder/backend +module github.com/foomo/squadron/exmpale/monorepo/checkout/backend -go 1.16 +go 1.21 diff --git a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml index 7bebf5c..a1bf711 100644 --- a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml +++ b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml @@ -12,6 +12,10 @@ squadron: image: <% .Global.docker.registry %>/checkout-backend context: <% env "PROJECT_ROOT" %>/squadrons/checkout/backend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile + dependencies: [ "backend-base" ] + args: + - "BASE_IMAGE=<% .Global.docker.registry %>/backend-base" + - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" values: image: tag: <% .Global.docker.tag | quote %> diff --git a/_examples/monorepo/squadrons/checkout/frontend/index.html b/_examples/monorepo/squadrons/checkout/frontend/index.html index f712531..23f366f 100644 --- a/_examples/monorepo/squadrons/checkout/frontend/index.html +++ b/_examples/monorepo/squadrons/checkout/frontend/index.html @@ -7,6 +7,6 @@ Document -

Storefinder

+

Checkout

diff --git a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml index 998cde1..00cd478 100644 --- a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml +++ b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml @@ -12,6 +12,10 @@ squadron: image: <% .Global.docker.registry %>/checkout-frontend context: <% env "PROJECT_ROOT" %>/squadrons/checkout/frontend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend.Dockerfile + dependencies: [ "frontend-base" ] + args: + - "BASE_IMAGE=<% .Global.docker.registry %>/frontend-base" + - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" values: image: tag: "<% .Global.docker.tag %>" diff --git a/_examples/monorepo/squadrons/squadron.yaml b/_examples/monorepo/squadrons/squadron.yaml index 51b00a1..3e901c0 100644 --- a/_examples/monorepo/squadrons/squadron.yaml +++ b/_examples/monorepo/squadrons/squadron.yaml @@ -4,3 +4,13 @@ global: docker: tag: "230101.0" registry: monorepo + +builds: + backend-base: + tag: <% .Global.docker.tag | quote %> + image: <% .Global.docker.registry %>/backend-base + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend-base.Dockerfile + frontend-base: + tag: <% .Global.docker.tag | quote %> + image: <% .Global.docker.registry %>/frontend-base + dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend-base.Dockerfile diff --git a/_examples/monorepo/squadrons/storefinder/backend/go.mod b/_examples/monorepo/squadrons/storefinder/backend/go.mod index d7d1b45..3e912e9 100644 --- a/_examples/monorepo/squadrons/storefinder/backend/go.mod +++ b/_examples/monorepo/squadrons/storefinder/backend/go.mod @@ -1,3 +1,3 @@ module github.com/foomo/squadron/exmpale/monorepo/storefinder/backend -go 1.16 +go 1.21 diff --git a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml index 444f250..391448c 100644 --- a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml +++ b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml @@ -12,6 +12,10 @@ squadron: image: <% .Global.docker.registry %>/storefinder-backend context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/backend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile + dependencies: [ "backend-base" ] + args: + - "BASE_IMAGE=<% .Global.docker.registry %>/backend-base" + - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" values: image: tag: <% .Global.docker.tag | quote %> diff --git a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml index d211efe..e6018ef 100644 --- a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml +++ b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml @@ -12,6 +12,10 @@ squadron: image: <% .Global.docker.registry %>/storefinder-frontend context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/frontend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend.Dockerfile + dependencies: [ "frontend-base" ] + args: + - "BASE_IMAGE=<% .Global.docker.registry %>/frontend-base" + - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" values: image: tag: "<% .Global.docker.tag %>" diff --git a/cmd/actions/list.go b/cmd/actions/list.go index 59cbc24..b306b94 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -8,10 +8,13 @@ import ( "github.com/spf13/cobra" ) -var flagPrefixSquadron bool +var ( + flagBuilds bool +) func init() { listCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") + listCmd.Flags().BoolVar(&flagBuilds, "builds", false, "include builds") } var listCmd = &cobra.Command{ @@ -31,12 +34,23 @@ var listCmd = &cobra.Command{ return err } - return sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + // List squadrons + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { fmt.Println("Squadron:", key) return value.Iterate(func(k string, v *config.Unit) error { - fmt.Println(" ", k) + fmt.Println(" " + k) + if flagBuilds { + for name, build := range v.Builds { + fmt.Println(" " + name) + for _, dependency := range build.Dependencies { + fmt.Println(" " + dependency) + } + } + } return nil }) }) + + return nil }, } diff --git a/internal/config/build.go b/internal/config/build.go index 1128cff..907353a 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -5,34 +5,71 @@ import ( "fmt" "github.com/foomo/squadron/internal/util" - "github.com/sirupsen/logrus" + "github.com/pterm/pterm" "gopkg.in/yaml.v3" ) type Build struct { - Args []string `yaml:"args,omitempty"` - Builder string `yaml:"builder,omitempty"` - CacheFrom string `yaml:"cache_from,omitempty"` - CacheTo string `yaml:"cache_to,omitempty"` - Context string `yaml:"context,omitempty"` - Dockerfile string `yaml:"dockerfile,omitempty"` - ExtraHosts []string `yaml:"extra_hosts,omitempty"` - Image string `yaml:"image,omitempty"` - IIDFile string `yaml:"iidfile,omitempty"` - Labels []string `yaml:"labels,omitempty"` - Load bool `yaml:"load,omitempty"` - MetadataFile string `yaml:"metadata_file,omitempty"` - Network string `yaml:"network,omitempty"` - NoCache bool `yaml:"no_cache,omitempty"` - Output string `yaml:"output,omitempty"` - Platform string `yaml:"platform,omitempty"` - Platforms []string `yaml:"platforms,omitempty"` - Secrets []string `yaml:"secrets,omitempty"` - ShmSize string `yaml:"shm_size,omitempty"` - SSH string `yaml:"ssh,omitempty"` - Tag string `yaml:"tag,omitempty"` - Target string `yaml:"target,omitempty"` - ULimit string `yaml:"ulimit,omitempty"` + Context string `yaml:"context,omitempty"` + // AddHost add a custom host-to-IP mapping (format: "host:ip") + AddHost []string `yaml:"add_host,omitempty"` + ExtraHost []string `yaml:"extra_hosts,omitempty"` // TODO deprecate use AddHost + // Allow extra privileged entitlement (e.g., "network.host", "security.insecure") + Allow []string `yaml:"allow,omitempty"` + // Attest parameters (format: "type=sbom,generator=image") + Attest []string `yaml:"attest,omitempty"` + // BuildArg set build-time variables + BuildArg []string `yaml:"build_arg,omitempty"` + Args []string `yaml:"args,omitempty"` // TODO deprecate use BuildArg + // BuildContext additional build contexts (e.g., name=path) + BuildContext []string `yaml:"build_context,omitempty"` + // Builder override the configured builder instance + Builder string `yaml:"builder,omitempty"` + // CacheFrom external cache sources (e.g., "user/app:cache", "type=local,src=path/to/dir") + CacheFrom string `yaml:"cache_from,omitempty"` + // CacheTo cache export destinations (e.g., "user/app:cache", "type=local,dest=path/to/dir") + CacheTo string `yaml:"cache_to,omitempty"` + // CGroupParent optional parent cgroup for the container + CGroupParent string `yaml:"cgroup_parent,omitempty"` + // File name of the Dockerfile (default: "PATH/Dockerfile") + File string `yaml:"file,omitempty"` + Dockerfile string `yaml:"dockerfile,omitempty"` // TODO deprecate use File + // IIDFile write the image ID to the file + IIDFile string `yaml:"iidfile,omitempty"` + // Label wet metadata for an image + Label []string `yaml:"label,omitempty"` + Labels []string `yaml:"labels,omitempty"` // TODO deprecate use Label + // Load shorthand for "--output=type=docker" + Load bool `yaml:"load,omitempty"` + // MetadataFile write build result metadata to the file + MetadataFile string `yaml:"metadata_file,omitempty"` + // Network set the networking mode for the "RUN" instructions during build (default "default") + Network string `yaml:"network,omitempty"` + // NoCache do not use cache when building the image + NoCache bool `yaml:"no_cache,omitempty"` + // NoCacheFilter do not cache specified stages + NoCacheFilter []string `yaml:"no_cache_filter,omitempty"` + // Output destination (format: "type=local,dest=path") + Output string `yaml:"output,omitempty"` + // Platform set target platform for build + Platform string `yaml:"platform,omitempty"` + Platforms []string `yaml:"platforms,omitempty"` // TODO deprecate use Platform + // Secret to expose to the build (format: "id=mysecret[,src=/local/secret]") + Secret []string `yaml:"secret,omitempty"` + Secrets []string `yaml:"secrets,omitempty"` // TODO deprecate use Secret + // ShmSize size of "/dev/shm" + ShmSize string `yaml:"shm_size,omitempty"` + // SSH agent socket or keys to expose to the build (format: "default|[=|[,]]") + SSH string `yaml:"ssh,omitempty"` + // Tag name and optionally a tag (format: "name:tag") + Tag string `yaml:"tag,omitempty"` + Image string `yaml:"image,omitempty"` + // Target set the target build stage to build + Target string `yaml:"target,omitempty"` + // ULimit ulimit options (default [] + ULimit string `yaml:"ulimit,omitempty"` + // Dependencies list of build names defined in the squadron configuration + Dependencies []string `yaml:"dependencies,omitempty"` } // ------------------------------------------------------------------------------------------------ @@ -40,27 +77,38 @@ type Build struct { // ------------------------------------------------------------------------------------------------ func (b *Build) Build(ctx context.Context, args []string) (string, error) { - logrus.Debugf("running docker build for %q", b.Context) + pterm.Debug.Printfln("running docker build for %q", b.Context) return util.NewDockerCommand().Build(b.Context). - ListArg("--add-host", b.ExtraHosts). + ListArg("--add-host", b.ExtraHost). + ListArg("--add-host", b.AddHost). + ListArg("--allow", b.Allow). + ListArg("--attest", b.Attest). ListArg("--build-arg", b.Args). + ListArg("--build-arg", b.BuildArg). + ListArg("--build-contet", b.BuildContext). Arg("--builder", b.Builder). Arg("--cache-from", b.CacheFrom). Arg("--cache-to", b.CacheTo). + Arg("--cgroup-parent", b.Dockerfile). + Arg("--file", b.File). Arg("--file", b.Dockerfile). Arg("--iidfile", b.IIDFile). + ListArg("--label", b.Label). ListArg("--label", b.Labels). BoolArg("--load", b.Load). Arg("--metadata-file", b.MetadataFile). Arg("--network", b.Network). BoolArg("--no-cache", b.NoCache). + ListArg("--noe-cache-filter", b.NoCacheFilter). Arg("--output", b.Output). Arg("--platform", b.Platform). ListArg("--platform", b.Platforms). // Arg("--progress", xxx). + // Arg("--provenance", xxx). // Arg("--push", xxx). // Arg("--pull", xxx). // Arg("--quiet", xxx). + ListArg("--secret", b.Secret). ListArg("--secret", b.Secrets). Arg("--shm-size", b.ShmSize). Arg("--ssh", b.SSH). @@ -72,7 +120,7 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { } func (b *Build) Push(ctx context.Context, args []string) (string, error) { - logrus.Debugf("running docker push for %s:%s", b.Image, b.Tag) + pterm.Debug.Printfln("running docker push for %s:%s", b.Image, b.Tag) return util.NewDockerCommand().Push(b.Image, b.Tag).Args(args...).Run(ctx) } diff --git a/internal/config/config.go b/internal/config/config.go index d3c2d7a..32426d4 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,15 +3,45 @@ package config import ( "fmt" + "github.com/pkg/errors" "gopkg.in/yaml.v3" ) type Config struct { - Version string `yaml:"version,omitempty"` - Global map[string]interface{} `yaml:"global,omitempty"` - Squadrons Map[Map[*Unit]] `yaml:"squadron,omitempty"` + // Version of the schema + Version string `yaml:"version,omitempty"` + // Global values to be injected into all squadron values + Global map[string]interface{} `yaml:"global,omitempty"` + // Global builds that can be referenced as dependencies + Builds map[string]Build `yaml:"builds,omitempty"` + // Squadron definitions + Squadrons Map[Map[*Unit]] `yaml:"squadron,omitempty"` } +// BuildDependencies returns a map of requested build dependencies +func (c *Config) BuildDependencies() map[string]Build { + ret := map[string]Build{} + _ = c.Squadrons.Iterate(func(key string, value Map[*Unit]) error { + return value.Iterate(func(k string, v *Unit) error { + for _, build := range v.Builds { + for _, dependency := range build.Dependencies { + b, ok := c.Builds[dependency] + if !ok { + return errors.Errorf("missing build dependency `%s`", dependency) + } + ret[dependency] = b + } + } + return nil + }) + }) + if len(ret) > 0 { + return ret + } + return nil +} + +// Trim delete empty squadron recursively func (c *Config) Trim() { _ = c.Squadrons.Iterate(func(key string, value Map[*Unit]) error { value.Trim() @@ -20,6 +50,7 @@ func (c *Config) Trim() { c.Squadrons.Trim() } +// UnmarshalYAML interface method func (c *Config) UnmarshalYAML(value *yaml.Node) error { switch value.Tag { case "!!map": diff --git a/internal/util/cmd.go b/internal/util/cmd.go index c75effc..03ceb96 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -35,15 +35,6 @@ func NewCommand(name string) *Cmd { } } -func (c Cmd) Base() *Cmd { - c.command = []string{c.command[0]} - return &c -} - -func (c Cmd) Command() []string { - return c.command -} - func (c *Cmd) Args(args ...string) *Cmd { for _, arg := range args { if arg == "" { diff --git a/squadron.go b/squadron.go index bbfa986..d9946af 100644 --- a/squadron.go +++ b/squadron.go @@ -235,7 +235,36 @@ func (sq *Squadron) Push(ctx context.Context, pushArgs []string, parallel int) e return wg.Wait() } +func (sq *Squadron) BuildDependencies(ctx context.Context, buildArgs []string, parallel int) error { + wg, gctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) + + var i int + dependencies := sq.c.BuildDependencies() + for name, dependency := range dependencies { + i := i + 1 + name := name + dependency := dependency + wg.Go(func() error { + pterm.Info.Printfln("[%d/%d] Building dependency `%s`", i, len(dependencies), name) + pterm.FgGray.Printfln("└ %s:%s", dependency.Image, dependency.Tag) + if out, err := dependency.Build(gctx, buildArgs); err != nil { + pterm.Error.Printfln("[%d/%d] Failed to build dependency `%s`", i, len(dependencies), name) + pterm.FgGray.Printfln("└ %s:%s", dependency.Image, dependency.Tag) + return errors.Wrap(err, out) + } + return nil + }) + } + + return wg.Wait() +} + func (sq *Squadron) Build(ctx context.Context, buildArgs []string, parallel int) error { + if err := sq.BuildDependencies(ctx, buildArgs, parallel); err != nil { + return err + } + wg, gctx := errgroup.WithContext(ctx) wg.SetLimit(parallel) diff --git a/testdata/override/snapshop-config-norender.yaml b/testdata/override/snapshop-config-norender.yaml index f5016a4..f9ac5bb 100644 --- a/testdata/override/snapshop-config-norender.yaml +++ b/testdata/override/snapshop-config-norender.yaml @@ -14,8 +14,8 @@ squadron: - bar=baz - baz=baz dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend tag: nightly + image: docker.mycompany.com/mycomapny/frontend values: image: repository: <% .Squadron.storefinder.frontend.builds.default.image %> diff --git a/testdata/override/snapshop-config.yaml b/testdata/override/snapshop-config.yaml index c6bb393..5003b09 100644 --- a/testdata/override/snapshop-config.yaml +++ b/testdata/override/snapshop-config.yaml @@ -14,8 +14,8 @@ squadron: - bar=baz - baz=baz dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend tag: nightly + image: docker.mycompany.com/mycomapny/frontend values: image: repository: docker.mycompany.com/mycomapny/frontend diff --git a/testdata/template/snapshop-config-norender.yaml b/testdata/template/snapshop-config-norender.yaml index f48cf5b..2542250 100644 --- a/testdata/template/snapshop-config-norender.yaml +++ b/testdata/template/snapshop-config-norender.yaml @@ -10,8 +10,8 @@ squadron: version: 0.0.1 builds: default: - image: docker.mycompany.com/mycomapny/frontend-admin tag: latest + image: docker.mycompany.com/mycomapny/frontend-admin values: image: repository: <% .Squadron.storefinder.backend.builds.default.image %> @@ -23,8 +23,8 @@ squadron: version: 0.0.1 builds: default: - image: docker.mycompany.com/mycomapny/frontend tag: latest + image: docker.mycompany.com/mycomapny/frontend values: env: BASE64: <% base64 "1234567890" %> diff --git a/testdata/template/snapshop-config.yaml b/testdata/template/snapshop-config.yaml index dac7aa5..f19196f 100644 --- a/testdata/template/snapshop-config.yaml +++ b/testdata/template/snapshop-config.yaml @@ -10,8 +10,8 @@ squadron: version: 0.0.1 builds: default: - image: docker.mycompany.com/mycomapny/frontend-admin tag: latest + image: docker.mycompany.com/mycomapny/frontend-admin values: image: repository: docker.mycompany.com/mycomapny/frontend-admin @@ -23,8 +23,8 @@ squadron: version: 0.0.1 builds: default: - image: docker.mycompany.com/mycomapny/frontend tag: latest + image: docker.mycompany.com/mycomapny/frontend values: env: BASE64: MTIzNDU2Nzg5MA== From ff880ac35608f96ec282c52dca5ff62c2a60db7f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Sep 2023 11:40:01 +0200 Subject: [PATCH 08/63] refactor: update diff --- cmd/actions/diff.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/cmd/actions/diff.go b/cmd/actions/diff.go index aad360d..fd98dc2 100644 --- a/cmd/actions/diff.go +++ b/cmd/actions/diff.go @@ -2,7 +2,6 @@ package actions import ( "github.com/foomo/squadron" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -24,16 +23,9 @@ var diffCmd = &cobra.Command{ args, helmArgs := parseExtraArgs(args) - if len(args) > 0 { - if err := sq.Config().Squadrons.Filter(args[0]); err != nil { - return errors.Wrap(err, "invalid SQUADRON argument") - } - } - - if len(args) > 1 { - if err := sq.Config().Squadrons[args[0]].Filter(args[1:]...); err != nil { - return errors.Wrap(err, "invalid UNIT argument") - } + squadronName, unitNames := parseSquadronAndUnitNames(args) + if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { + return err } if err := sq.RenderConfig(cmd.Context()); err != nil { From 730882665225763e437ad9ab66cca8428c56e7c7 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 27 Sep 2023 06:38:33 +0200 Subject: [PATCH 09/63] feat: add charts to list --- _examples/monorepo/Makefile | 2 +- cmd/actions/list.go | 27 ++++++++++++++++++++------- go.mod | 2 +- go.sum | 4 ++-- internal/helm/depency.go | 16 ++++++++++------ 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/_examples/monorepo/Makefile b/_examples/monorepo/Makefile index c922eff..259e4e3 100644 --- a/_examples/monorepo/Makefile +++ b/_examples/monorepo/Makefile @@ -9,7 +9,7 @@ files=$(shell find . -name 'squadron.yaml' | tail -r | xargs echo -n | tr " ", " .PHONY: list ## Show config list: - @go run ../../cmd/main.go -f ${files} list --builds + @go run ../../cmd/main.go -f ${files} list --builds --charts .PHONY: config ## Show config diff --git a/cmd/actions/list.go b/cmd/actions/list.go index b306b94..46a9bd5 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -1,19 +1,21 @@ package actions import ( - "fmt" - "github.com/foomo/squadron" "github.com/foomo/squadron/internal/config" + "github.com/pterm/pterm" + "github.com/pterm/pterm/putils" "github.com/spf13/cobra" ) var ( flagBuilds bool + flagCharts bool ) func init() { listCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") + listCmd.Flags().BoolVar(&flagCharts, "charts", false, "include charts") listCmd.Flags().BoolVar(&flagBuilds, "builds", false, "include builds") } @@ -34,16 +36,25 @@ var listCmd = &cobra.Command{ return err } + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } + + var list pterm.LeveledList + // List squadrons _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { - fmt.Println("Squadron:", key) + list = append(list, pterm.LeveledListItem{Level: 0, Text: key}) return value.Iterate(func(k string, v *config.Unit) error { - fmt.Println(" " + k) + list = append(list, pterm.LeveledListItem{Level: 1, Text: k}) + if flagCharts { + list = append(list, pterm.LeveledListItem{Level: 2, Text: "📑: " + v.Chart.String()}) + } if flagBuilds { for name, build := range v.Builds { - fmt.Println(" " + name) + list = append(list, pterm.LeveledListItem{Level: 2, Text: "📦: " + name}) for _, dependency := range build.Dependencies { - fmt.Println(" " + dependency) + list = append(list, pterm.LeveledListItem{Level: 3, Text: "🗃️: " + dependency}) } } } @@ -51,6 +62,8 @@ var listCmd = &cobra.Command{ }) }) - return nil + root := putils.TreeFromLeveledList(list) + root.Text = "Squadron" + return pterm.DefaultTree.WithRoot(root).Render() }, } diff --git a/go.mod b/go.mod index c061045..1d11905 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/miracl/conflate v1.2.1 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.67 + github.com/pterm/pterm v0.12.69 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 diff --git a/go.sum b/go.sum index ed4ca1e..da983a4 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.67 h1:5iB7ajIQROYfxYD7+sFJ4+KJhFJ+xn7QOVBm4s6RUF0= -github.com/pterm/pterm v0.12.67/go.mod h1:nFuT9ZVkkCi8o4L1dtWuYPwDQxggLh4C263qG5nTLpQ= +github.com/pterm/pterm v0.12.69 h1:fBCKnB8dSLAl8FlYRQAWYGp2WTI/Xm/tKJ21Hyo9USw= +github.com/pterm/pterm v0.12.69/go.mod h1:wl06ko9MHnqxz4oDV++IORDpjCzw6+mfrvf0MPj6fdk= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= diff --git a/internal/helm/depency.go b/internal/helm/depency.go index 23f1f04..133cbb7 100644 --- a/internal/helm/depency.go +++ b/internal/helm/depency.go @@ -17,11 +17,11 @@ type Dependency struct { Alias string `yaml:"alias,omitempty"` } -func (cd *Dependency) UnmarshalYAML(value *yaml.Node) error { +func (d *Dependency) UnmarshalYAML(value *yaml.Node) error { switch value.Tag { case "!!map": type wrapper Dependency - return value.Decode((*wrapper)(cd)) + return value.Decode((*wrapper)(d)) case "!!str": var vString string if err := value.Decode(&vString); err != nil { @@ -35,11 +35,15 @@ func (cd *Dependency) UnmarshalYAML(value *yaml.Node) error { if err != nil { return fmt.Errorf("failed to load local chart: " + vString) } - cd.Name = localChart.Name - cd.Repository = fmt.Sprintf("file://%v", vString) - cd.Version = localChart.Version + d.Name = localChart.Name + d.Repository = fmt.Sprintf("file://%v", vString) + d.Version = localChart.Version return nil default: - return fmt.Errorf("unsupported node tag type for %T: %q", cd, value.Tag) + return fmt.Errorf("unsupported node tag type for %T: %q", d, value.Tag) } } + +func (d Dependency) String() string { + return fmt.Sprintf("%s/%s:%s", d.Repository, d.Name, d.Version) +} From 80a9de238bba4f2fc66d13f6933c8c46a2fd3ec5 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 27 Sep 2023 10:02:55 +0200 Subject: [PATCH 10/63] feat: fix race conditions --- .../charts/backend/templates/deployment.yaml | 2 +- .../charts/backend/templates/service.yaml | 1 + .../charts/frontend/templates/deployment.yaml | 2 +- .../charts/frontend/templates/ingress.yaml | 26 ++++++ .../charts/frontend/templates/service.yaml | 1 + cmd/actions/template.go | 3 +- go.mod | 3 +- go.sum | 5 ++ internal/config/unit.go | 31 +++++++ squadron.go | 86 +++++++++++-------- squadron_test.go | 2 +- testdata/override/snapshop-template.yaml | 31 ++++++- testdata/simple/snapshop-template.yaml | 31 ++++++- testdata/tags/snapshop-template.yaml | 3 +- testdata/template/snapshop-template.yaml | 34 +++++++- 15 files changed, 213 insertions(+), 48 deletions(-) create mode 100644 _examples/common/charts/frontend/templates/ingress.yaml diff --git a/_examples/common/charts/backend/templates/deployment.yaml b/_examples/common/charts/backend/templates/deployment.yaml index 6e2bfee..3937b4b 100644 --- a/_examples/common/charts/backend/templates/deployment.yaml +++ b/_examples/common/charts/backend/templates/deployment.yaml @@ -7,8 +7,8 @@ metadata: app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + namespace: {{ .Release.Namespace }} spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: {{ .Release.Name }} diff --git a/_examples/common/charts/backend/templates/service.yaml b/_examples/common/charts/backend/templates/service.yaml index 62043c5..5d76459 100644 --- a/_examples/common/charts/backend/templates/service.yaml +++ b/_examples/common/charts/backend/templates/service.yaml @@ -7,6 +7,7 @@ metadata: app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + namespace: {{ .Release.Namespace }} spec: type: ClusterIP selector: diff --git a/_examples/common/charts/frontend/templates/deployment.yaml b/_examples/common/charts/frontend/templates/deployment.yaml index 6e2bfee..3937b4b 100644 --- a/_examples/common/charts/frontend/templates/deployment.yaml +++ b/_examples/common/charts/frontend/templates/deployment.yaml @@ -7,8 +7,8 @@ metadata: app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + namespace: {{ .Release.Namespace }} spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: {{ .Release.Name }} diff --git a/_examples/common/charts/frontend/templates/ingress.yaml b/_examples/common/charts/frontend/templates/ingress.yaml new file mode 100644 index 0000000..746a9f8 --- /dev/null +++ b/_examples/common/charts/frontend/templates/ingress.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }} + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: {{ .Chart.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + namespace: {{ .Release.Namespace }} +spec: + tls: + - hosts: [ "foo.com" ] + secretName: foo-com-cert + rules: + - host: foo.com + http: + paths: + - pathType: Prefix + path: / + backend: + service: + name: {{ $.Release.Name }} + port: + name: http + number: 80 diff --git a/_examples/common/charts/frontend/templates/service.yaml b/_examples/common/charts/frontend/templates/service.yaml index 62043c5..5d76459 100644 --- a/_examples/common/charts/frontend/templates/service.yaml +++ b/_examples/common/charts/frontend/templates/service.yaml @@ -7,6 +7,7 @@ metadata: app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + namespace: {{ .Release.Namespace }} spec: type: ClusterIP selector: diff --git a/cmd/actions/template.go b/cmd/actions/template.go index e411c2d..cd5a3ed 100644 --- a/cmd/actions/template.go +++ b/cmd/actions/template.go @@ -9,6 +9,7 @@ import ( ) func init() { + templateCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") templateCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") templateCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } @@ -36,7 +37,7 @@ var templateCmd = &cobra.Command{ return err } - out, err := sq.Template(cmd.Context(), helmArgs) + out, err := sq.Template(cmd.Context(), helmArgs, flagParallel) if err != nil { return err } diff --git a/go.mod b/go.mod index 1d11905..79615ae 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.28.2 + k8s.io/apimachinery v0.28.2 ) require ( @@ -54,11 +55,11 @@ require ( golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/apimachinery v0.28.2 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace github.com/miracl/conflate v1.2.1 => github.com/runz0rd/conflate v1.2.2-0.20210920145208-fa48576ef06d diff --git a/go.sum b/go.sum index da983a4..67b5e1b 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,8 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -163,6 +165,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= @@ -205,6 +208,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/internal/config/unit.go b/internal/config/unit.go index 4b5ee9b..adaf03d 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -1,8 +1,11 @@ package config import ( + "bytes" "context" + "fmt" "os" + "path" "strings" "github.com/foomo/squadron/internal/helm" @@ -64,6 +67,34 @@ func (u *Unit) Push(ctx context.Context, squadron, unit string, args []string) ( return "", nil } +func (u *Unit) Template(ctx context.Context, squadron, unit, namespace string, global map[string]interface{}, helmArgs []string) ([]byte, error) { + var ret bytes.Buffer + valueBytes, err := u.ValuesYAML(global) + if err != nil { + return nil, err + } + + cmd := util.NewHelmCommand().Args("template", unit). + Stdin(bytes.NewReader(valueBytes)). + Stdout(&ret). + Args("--dependency-update"). + Args("--namespace", namespace). + Args("--set", fmt.Sprintf("squadron=%s", squadron)). + Args("--set", fmt.Sprintf("unit=%s", unit)). + Args("--values", "-"). + Args(helmArgs...) + if strings.HasPrefix(u.Chart.Repository, "file://") { + cmd.Args(path.Clean(strings.TrimPrefix(u.Chart.Repository, "file://"))) + } else { + cmd.Args(u.Chart.Name, "--repo", u.Chart.Repository, "--version", u.Chart.Version) + } + if out, err := cmd.Run(ctx); err != nil { + return nil, errors.Wrap(err, out) + } + + return ret.Bytes(), nil +} + func (u *Unit) DependencyUpdate(ctx context.Context) error { // update local chart dependencies // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql diff --git a/squadron.go b/squadron.go index d9946af..0cb36ea 100644 --- a/squadron.go +++ b/squadron.go @@ -9,6 +9,7 @@ import ( "os/exec" "slices" "strings" + "sync" "text/template" "github.com/foomo/squadron/internal/config" @@ -49,6 +50,9 @@ func New(basePath, namespace string, files []string) *Squadron { // ------------------------------------------------------------------------------------------------ func (sq *Squadron) Namespace(ctx context.Context, squadron, unit string) (string, error) { + if sq.namespace == "" { + return "default", nil + } var out bytes.Buffer t, err := template.New("namespace").Parse(sq.namespace) if err != nil { @@ -317,7 +321,14 @@ func (sq *Squadron) Down(ctx context.Context, helmArgs []string, parallel int) e } func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) error { - var diff string + var m sync.Mutex + var ret string + write := func(b string) { + m.Lock() + defer m.Unlock() + ret += b + } + wg, ctx := errgroup.WithContext(ctx) wg.SetLimit(parallel) @@ -360,7 +371,7 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e } dmp := diffmatchpatch.New() - diff += dmp.DiffPrettyText(dmp.DiffMain(string(manifest), string(out), false)) + write(dmp.DiffPrettyText(dmp.DiffMain(string(manifest), string(out), false))) return nil }) return nil @@ -371,16 +382,21 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e return err } - fmt.Println(diff) + fmt.Println(ret) return nil } func (sq *Squadron) Status(ctx context.Context, helmArgs []string, parallel int) error { + var m sync.Mutex tbd := pterm.TableData{ {"Name", "Revision", "Status", "Deployed by", "Commit", "Branch", "Last deployed", "Notes"}, } - + write := func(b []string) { + m.Lock() + defer m.Unlock() + tbd = append(tbd, b) + } type statusType struct { Name string `json:"name"` Version int `json:"version"` @@ -435,7 +451,7 @@ func (sq *Squadron) Status(ctx context.Context, helmArgs []string, parallel int) notes = append(notes, line) } } - tbd = append(tbd, []string{ + write([]string{ status.Name, fmt.Sprintf("%d", status.Version), status.Info.Status, @@ -556,48 +572,42 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version return wg.Wait() } -func (sq *Squadron) Template(ctx context.Context, helmArgs []string) (string, error) { +func (sq *Squadron) Template(ctx context.Context, helmArgs []string, parallel int) (string, error) { + var m sync.Mutex var ret bytes.Buffer + write := func(b []byte) error { + m.Lock() + defer m.Unlock() + _, err := ret.Write(b) + return err + } + + wg, gctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) - err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + _ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { return value.Iterate(func(k string, v *config.Unit) error { - name := fmt.Sprintf("%s-%s", key, k) - namespace, err := sq.Namespace(ctx, key, k) - if err != nil { - return err - } - valueBytes, err := v.ValuesYAML(sq.c.Global) - if err != nil { - return err - } + wg.Go(func() error { + name := fmt.Sprintf("%s-%s", key, k) + namespace, err := sq.Namespace(ctx, key, k) + if err != nil { + return err + } - pterm.Debug.Printfln("running helm template for chart: %s", name) - cmd := util.NewHelmCommand().Args("template", k). - Stdin(bytes.NewReader(valueBytes)). - Stdout(&ret). - Args("--dependency-update"). - Args("--namespace", namespace). - Args("--set", fmt.Sprintf("squadron=%s", key)). - Args("--set", fmt.Sprintf("unit=%s", k)). - Args("--values", "-"). - Args(helmArgs...) - if strings.Contains(v.Chart.Repository, "file://") { - file := strings.TrimPrefix(v.Chart.Repository, "file://") - if !strings.HasPrefix(file, ".") { - file = "/" + file + pterm.Debug.Printfln("running helm template for chart: %s", name) + out, err := v.Template(gctx, key, k, namespace, sq.c.Global, helmArgs) + if err != nil { + return err } - cmd.Args(file) - } else { - cmd.Args(v.Chart.Name, "--repo", v.Chart.Repository, "--version", v.Chart.Version) - } - if out, err := cmd.Run(ctx); err != nil { - return errors.Wrap(err, out) - } + + return write(out) + }) return nil }) }) - if err != nil { + + if err := wg.Wait(); err != nil { return "", err } diff --git a/squadron_test.go b/squadron_test.go index f50cdad..2a9365b 100644 --- a/squadron_test.go +++ b/squadron_test.go @@ -89,7 +89,7 @@ func config(t *testing.T, name string, files []string, squadronName string, unit } { - out, err := sq.Template(ctx, nil) + out, err := sq.Template(ctx, nil, 1) require.NoError(t, err, "failed to render template") testutils.Snapshot(t, path.Join("testdata", name, "snapshop-template.yaml"), out) } diff --git a/testdata/override/snapshop-template.yaml b/testdata/override/snapshop-template.yaml index 1135a41..3a8cfe9 100644 --- a/testdata/override/snapshop-template.yaml +++ b/testdata/override/snapshop-template.yaml @@ -9,6 +9,7 @@ metadata: app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: frontend-0.0.1 + namespace: default spec: type: ClusterIP selector: @@ -28,8 +29,8 @@ metadata: app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: frontend-0.0.1 + namespace: default spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: frontend @@ -47,3 +48,31 @@ spec: - name: http protocol: TCP containerPort: 80 +--- +# Source: frontend/templates/ingress.yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 + namespace: default +spec: + tls: + - hosts: [ "foo.com" ] + secretName: foo-com-cert + rules: + - host: foo.com + http: + paths: + - pathType: Prefix + path: / + backend: + service: + name: frontend + port: + name: http + number: 80 diff --git a/testdata/simple/snapshop-template.yaml b/testdata/simple/snapshop-template.yaml index 1135a41..3a8cfe9 100644 --- a/testdata/simple/snapshop-template.yaml +++ b/testdata/simple/snapshop-template.yaml @@ -9,6 +9,7 @@ metadata: app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: frontend-0.0.1 + namespace: default spec: type: ClusterIP selector: @@ -28,8 +29,8 @@ metadata: app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: frontend-0.0.1 + namespace: default spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: frontend @@ -47,3 +48,31 @@ spec: - name: http protocol: TCP containerPort: 80 +--- +# Source: frontend/templates/ingress.yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 + namespace: default +spec: + tls: + - hosts: [ "foo.com" ] + secretName: foo-com-cert + rules: + - host: foo.com + http: + paths: + - pathType: Prefix + path: / + backend: + service: + name: frontend + port: + name: http + number: 80 diff --git a/testdata/tags/snapshop-template.yaml b/testdata/tags/snapshop-template.yaml index 16d3567..930863d 100644 --- a/testdata/tags/snapshop-template.yaml +++ b/testdata/tags/snapshop-template.yaml @@ -9,6 +9,7 @@ metadata: app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: backend-0.0.1 + namespace: default spec: type: ClusterIP selector: @@ -28,8 +29,8 @@ metadata: app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: backend-0.0.1 + namespace: default spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: backend diff --git a/testdata/template/snapshop-template.yaml b/testdata/template/snapshop-template.yaml index e29f28e..419055f 100644 --- a/testdata/template/snapshop-template.yaml +++ b/testdata/template/snapshop-template.yaml @@ -9,6 +9,7 @@ metadata: app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: backend-0.0.1 + namespace: default spec: type: ClusterIP selector: @@ -28,8 +29,8 @@ metadata: app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: backend-0.0.1 + namespace: default spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: backend @@ -58,6 +59,7 @@ metadata: app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: frontend-0.0.1 + namespace: default spec: type: ClusterIP selector: @@ -77,8 +79,8 @@ metadata: app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: frontend-0.0.1 + namespace: default spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: frontend @@ -96,3 +98,31 @@ spec: - name: http protocol: TCP containerPort: 80 +--- +# Source: frontend/templates/ingress.yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: frontend + labels: + app.kubernetes.io/name: frontend + app.kubernetes.io/component: frontend + app.kubernetes.io/managed-by: Helm + helm.sh/chart: frontend-0.0.1 + namespace: default +spec: + tls: + - hosts: [ "foo.com" ] + secretName: foo-com-cert + rules: + - host: foo.com + http: + paths: + - pathType: Prefix + path: / + backend: + service: + name: frontend + port: + name: http + number: 80 From 1d00f57bd47a6c4e19432f9080e9160e53a090c7 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 20 Dec 2023 16:26:40 +0100 Subject: [PATCH 11/63] feat: update versions --- _examples/common/charts/backend/Chart.yaml | 4 ++-- _examples/common/charts/frontend/Chart.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_examples/common/charts/backend/Chart.yaml b/_examples/common/charts/backend/Chart.yaml index 5899fae..577d722 100644 --- a/_examples/common/charts/backend/Chart.yaml +++ b/_examples/common/charts/backend/Chart.yaml @@ -1,4 +1,4 @@ -apiVersion: v1 -appVersion: "1.0" +apiVersion: v2 +appVersion: 0.0.1 name: backend version: 0.0.1 diff --git a/_examples/common/charts/frontend/Chart.yaml b/_examples/common/charts/frontend/Chart.yaml index cf9d50b..d04d1b7 100644 --- a/_examples/common/charts/frontend/Chart.yaml +++ b/_examples/common/charts/frontend/Chart.yaml @@ -1,4 +1,4 @@ -apiVersion: v1 -appVersion: "1.0" +apiVersion: v2 +appVersion: 0.0.1 name: frontend version: 0.0.1 From e33a9195707af938dfac7dfc5e235f677919410f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 20 Dec 2023 16:26:59 +0100 Subject: [PATCH 12/63] feat: add yamllint --- .gitignore | 1 + .yamllint.yaml | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 .yamllint.yaml diff --git a/.gitignore b/.gitignore index 4549d20..e99ac8f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ !.golangci.yml !.goreleaser.yml !.husky.yaml +!.yamllint.yaml /bin/ /coverage.out /coverage.html diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..669c864 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,5 @@ +extends: default + +rules: + line-length: disable + document-start: disable From bd1211bf67e75e54a02fe3282588977d8e32b553 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 20 Dec 2023 16:27:11 +0100 Subject: [PATCH 13/63] feat: bump deps --- go.mod | 18 +++++++++--------- go.sum | 43 +++++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 79615ae..cbf2c17 100644 --- a/go.mod +++ b/go.mod @@ -7,16 +7,16 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/miracl/conflate v1.2.1 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.69 + github.com/pterm/pterm v0.12.71 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - golang.org/x/sync v0.3.0 + golang.org/x/sync v0.5.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.28.2 - k8s.io/apimachinery v0.28.2 + k8s.io/api v0.28.4 + k8s.io/apimachinery v0.28.4 ) require ( @@ -50,10 +50,10 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/net v0.13.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect diff --git a/go.sum b/go.sum index 67b5e1b..e1b2548 100644 --- a/go.sum +++ b/go.sum @@ -27,7 +27,7 @@ github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQq github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -40,8 +40,6 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -94,8 +92,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.69 h1:fBCKnB8dSLAl8FlYRQAWYGp2WTI/Xm/tKJ21Hyo9USw= -github.com/pterm/pterm v0.12.69/go.mod h1:wl06ko9MHnqxz4oDV++IORDpjCzw6+mfrvf0MPj6fdk= +github.com/pterm/pterm v0.12.71 h1:KcEJ98EiVCbzDkFbktJ2gMlr4pn8IzyGb9bwK6ffkuA= +github.com/pterm/pterm v0.12.71/go.mod h1:SUAcoZjRt+yjPWlWba+/Fd8zJJ2lSXBQWf0Z0HbFiIQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -109,8 +107,8 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -159,16 +157,15 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -182,22 +179,22 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -208,8 +205,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -226,10 +221,10 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= +k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= From 793d3deb31404c8271770823b8ec93504cb3f370 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 20 Dec 2023 16:27:19 +0100 Subject: [PATCH 14/63] feat: remove deprecations --- internal/config/build.go | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/internal/config/build.go b/internal/config/build.go index 907353a..bec27b9 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -12,15 +12,13 @@ import ( type Build struct { Context string `yaml:"context,omitempty"` // AddHost add a custom host-to-IP mapping (format: "host:ip") - AddHost []string `yaml:"add_host,omitempty"` - ExtraHost []string `yaml:"extra_hosts,omitempty"` // TODO deprecate use AddHost + AddHost []string `yaml:"add_host,omitempty"` // Allow extra privileged entitlement (e.g., "network.host", "security.insecure") Allow []string `yaml:"allow,omitempty"` // Attest parameters (format: "type=sbom,generator=image") Attest []string `yaml:"attest,omitempty"` // BuildArg set build-time variables BuildArg []string `yaml:"build_arg,omitempty"` - Args []string `yaml:"args,omitempty"` // TODO deprecate use BuildArg // BuildContext additional build contexts (e.g., name=path) BuildContext []string `yaml:"build_context,omitempty"` // Builder override the configured builder instance @@ -32,13 +30,11 @@ type Build struct { // CGroupParent optional parent cgroup for the container CGroupParent string `yaml:"cgroup_parent,omitempty"` // File name of the Dockerfile (default: "PATH/Dockerfile") - File string `yaml:"file,omitempty"` - Dockerfile string `yaml:"dockerfile,omitempty"` // TODO deprecate use File + File string `yaml:"file,omitempty"` // IIDFile write the image ID to the file IIDFile string `yaml:"iidfile,omitempty"` // Label wet metadata for an image - Label []string `yaml:"label,omitempty"` - Labels []string `yaml:"labels,omitempty"` // TODO deprecate use Label + Label []string `yaml:"label,omitempty"` // Load shorthand for "--output=type=docker" Load bool `yaml:"load,omitempty"` // MetadataFile write build result metadata to the file @@ -52,11 +48,9 @@ type Build struct { // Output destination (format: "type=local,dest=path") Output string `yaml:"output,omitempty"` // Platform set target platform for build - Platform string `yaml:"platform,omitempty"` - Platforms []string `yaml:"platforms,omitempty"` // TODO deprecate use Platform + Platform string `yaml:"platform,omitempty"` // Secret to expose to the build (format: "id=mysecret[,src=/local/secret]") - Secret []string `yaml:"secret,omitempty"` - Secrets []string `yaml:"secrets,omitempty"` // TODO deprecate use Secret + Secret []string `yaml:"secret,omitempty"` // ShmSize size of "/dev/shm" ShmSize string `yaml:"shm_size,omitempty"` // SSH agent socket or keys to expose to the build (format: "default|[=|[,]]") @@ -79,22 +73,17 @@ type Build struct { func (b *Build) Build(ctx context.Context, args []string) (string, error) { pterm.Debug.Printfln("running docker build for %q", b.Context) return util.NewDockerCommand().Build(b.Context). - ListArg("--add-host", b.ExtraHost). ListArg("--add-host", b.AddHost). ListArg("--allow", b.Allow). ListArg("--attest", b.Attest). - ListArg("--build-arg", b.Args). ListArg("--build-arg", b.BuildArg). ListArg("--build-contet", b.BuildContext). Arg("--builder", b.Builder). Arg("--cache-from", b.CacheFrom). Arg("--cache-to", b.CacheTo). - Arg("--cgroup-parent", b.Dockerfile). Arg("--file", b.File). - Arg("--file", b.Dockerfile). Arg("--iidfile", b.IIDFile). ListArg("--label", b.Label). - ListArg("--label", b.Labels). BoolArg("--load", b.Load). Arg("--metadata-file", b.MetadataFile). Arg("--network", b.Network). @@ -102,14 +91,12 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { ListArg("--noe-cache-filter", b.NoCacheFilter). Arg("--output", b.Output). Arg("--platform", b.Platform). - ListArg("--platform", b.Platforms). // Arg("--progress", xxx). // Arg("--provenance", xxx). // Arg("--push", xxx). // Arg("--pull", xxx). // Arg("--quiet", xxx). ListArg("--secret", b.Secret). - ListArg("--secret", b.Secrets). Arg("--shm-size", b.ShmSize). Arg("--ssh", b.SSH). Arg("--tag", fmt.Sprintf("%s:%s", b.Image, b.Tag)). From 527b0ac827ad307786315ef82f583e1aa3aefeff Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 20 Dec 2023 16:27:27 +0100 Subject: [PATCH 15/63] docs: update todos --- TODO.md | 87 ++++----------------------------------------------------- 1 file changed, 6 insertions(+), 81 deletions(-) diff --git a/TODO.md b/TODO.md index 097d9c3..d2e4ec0 100644 --- a/TODO.md +++ b/TODO.md @@ -1,119 +1,44 @@ # TODO -- [x] `down` fails if a release doesn't exists - -- [ ] specify output dir (param and env var) - - -## General - -- [ ] update README.md - -- [ ] update examples folder - -- [x] test `completion` command - -- [ ] provide full example YAML - - ## Configuration (squadron.yaml) -- [x] provide warning where usage of `${ENV_VAR}` is not supported! Or implement it. => not implementing it yet - -- [x] test `op` template func - -- [x] test `base64` template func - - [ ] check release name if merged - [ ] check `default` template func ## Commands -## config - -- [x] specifying the config file should override the default - - ```bash - $ squadron config -f ${PWD}/squadrons/storefinder/squadron.yaml - > Error: open ${PWD}/squadron.yaml: no such file or directory - ``` - -- [x] send `squadron config` to stdout i.e. for `squadron config | bat` - -- [x] provide `tag:` policies (git hash | timestamp | env ) @see scaffold => using template var - -## build - -- [x] not using `--files` flag - ### up - [ ] pass on `--verbose` flag to helm (`--debug`) -- [x] add `--no-generate` flag to skip re-generation of chart => use your own helm - ### down - [ ] pass on `--verbose` flag helm (`--debug`) -## Ideas - -- [x] provide a way to add standard resources e.g. `secrets` as templates (to prevent sth like `shared`) - - -## Questions - -- [x] Namespaces are still referenced in the code? => can be removed - -- [x] what is the example data needed for? => remove - -- [x] should we refactor it to see charts separately? Or if name provided? ‼️ -- [x] concept: is it a good idea to up | generate only specific units? (chart will change depending on specified units) ‼️ - -- [x] is `units` the correct name? => check naval lingo ... ship, unit, battleship => unit is fine - -- [x] do we want to re-support the `--data` parameter? => try it with overrides and ENV first - -- [x] verbose flag `-v` doesn't really output more? => add logging to commands - ## Backlog -- [ ] add `status` command to to check what is currently installed/orphaned on clusters. +- [ ] add `status` command to to check what is currently installed/orphaned on clusters. This might require to somehow store meta data through helm. -- [x] add separate `push` command - -- [x] add `global` variables within `squadron.yaml` as chart's `global`. - -- [x] support `helm diff` plugin - - [ ] define reuse-able flags like `--namespace` -- [x] remove comments before passing to go template - -- [x] improve 1Password integration: `export OP_SESSION_account_alias="XXX" | op signin account_alias --raw` - - [ ] pretty print template errors e.g. like zeus does -- [x] add initial tests - - [ ] add `lint` command to check valid yaml and pass it to helm -- [x] add `template` command to check valid yaml and pass it to helm - - [ ] provide some release information commands via helm e.g. `list`, `status`, ... - [ ] check `helm get ...` commands - + - [ ] check `helm history ...` commands - + - [ ] check `helm rollback ...` commands - + - [ ] check `helm template ...` commands - + - [ ] add YAML schema - [ ] colorized output @@ -126,4 +51,4 @@ - [ ] add validation check to prevent `global` squadron name (collides with vars)! -- [ ] support parallel `build` and `push` with context canceling \ No newline at end of file +- [ ] support parallel `build` and `push` with context canceling From e6738a53a8c0b14b341e152a8565109f6d008e89 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:03:36 +0100 Subject: [PATCH 16/63] style: format code --- .yamllint.yaml | 3 +++ .../charts/backend/templates/deployment.yaml | 4 ++-- .../common/charts/backend/templates/service.yaml | 2 +- .../charts/frontend/templates/deployment.yaml | 4 ++-- .../common/charts/frontend/templates/ingress.yaml | 6 +++--- .../common/charts/frontend/templates/service.yaml | 2 +- _examples/helloworld/squadron.yaml | 2 +- .../squadrons/checkout/backend/squadron.yaml | 10 +++++----- .../squadrons/checkout/frontend/squadron.yaml | 14 +++++++------- _examples/monorepo/squadrons/squadron.yaml | 4 ++-- .../squadrons/storefinder/backend/squadron.yaml | 10 +++++----- .../squadrons/storefinder/frontend/squadron.yaml | 14 +++++++------- 12 files changed, 39 insertions(+), 36 deletions(-) diff --git a/.yamllint.yaml b/.yamllint.yaml index 669c864..3b31050 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -3,3 +3,6 @@ extends: default rules: line-length: disable document-start: disable + quoted-strings: + quote-type: single + required: false diff --git a/_examples/common/charts/backend/templates/deployment.yaml b/_examples/common/charts/backend/templates/deployment.yaml index 3937b4b..b9fa4b8 100644 --- a/_examples/common/charts/backend/templates/deployment.yaml +++ b/_examples/common/charts/backend/templates/deployment.yaml @@ -6,7 +6,7 @@ metadata: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + helm.sh/chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' namespace: {{ .Release.Namespace }} spec: selector: @@ -21,7 +21,7 @@ spec: spec: containers: - name: {{ .Release.Name }} - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: http protocol: TCP diff --git a/_examples/common/charts/backend/templates/service.yaml b/_examples/common/charts/backend/templates/service.yaml index 5d76459..8961e7a 100644 --- a/_examples/common/charts/backend/templates/service.yaml +++ b/_examples/common/charts/backend/templates/service.yaml @@ -6,7 +6,7 @@ metadata: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + helm.sh/chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' namespace: {{ .Release.Namespace }} spec: type: ClusterIP diff --git a/_examples/common/charts/frontend/templates/deployment.yaml b/_examples/common/charts/frontend/templates/deployment.yaml index 3937b4b..b9fa4b8 100644 --- a/_examples/common/charts/frontend/templates/deployment.yaml +++ b/_examples/common/charts/frontend/templates/deployment.yaml @@ -6,7 +6,7 @@ metadata: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + helm.sh/chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' namespace: {{ .Release.Namespace }} spec: selector: @@ -21,7 +21,7 @@ spec: spec: containers: - name: {{ .Release.Name }} - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: http protocol: TCP diff --git a/_examples/common/charts/frontend/templates/ingress.yaml b/_examples/common/charts/frontend/templates/ingress.yaml index 746a9f8..c0ab328 100644 --- a/_examples/common/charts/frontend/templates/ingress.yaml +++ b/_examples/common/charts/frontend/templates/ingress.yaml @@ -6,14 +6,14 @@ metadata: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + helm.sh/chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' namespace: {{ .Release.Namespace }} spec: tls: - - hosts: [ "foo.com" ] + - hosts: ['foo.com'] secretName: foo-com-cert rules: - - host: foo.com + - host: foo.com http: paths: - pathType: Prefix diff --git a/_examples/common/charts/frontend/templates/service.yaml b/_examples/common/charts/frontend/templates/service.yaml index 5d76459..8961e7a 100644 --- a/_examples/common/charts/frontend/templates/service.yaml +++ b/_examples/common/charts/frontend/templates/service.yaml @@ -6,7 +6,7 @@ metadata: app.kubernetes.io/name: {{ .Release.Name }} app.kubernetes.io/component: {{ .Chart.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + helm.sh/chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' namespace: {{ .Release.Namespace }} spec: type: ClusterIP diff --git a/_examples/helloworld/squadron.yaml b/_examples/helloworld/squadron.yaml index 2a096fb..5e975fd 100644 --- a/_examples/helloworld/squadron.yaml +++ b/_examples/helloworld/squadron.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: diff --git a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml index a1bf711..2883852 100644 --- a/_examples/monorepo/squadrons/checkout/backend/squadron.yaml +++ b/_examples/monorepo/squadrons/checkout/backend/squadron.yaml @@ -1,21 +1,21 @@ # Schema version -version: "2.0" +version: '2.0' squadron: checkout: backend: chart: <% env "PROJECT_ROOT" %>/../common/charts/backend - tags: [ "backend" ] + tags: ['backend'] builds: default: tag: <% .Global.docker.tag | quote %> image: <% .Global.docker.registry %>/checkout-backend context: <% env "PROJECT_ROOT" %>/squadrons/checkout/backend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile - dependencies: [ "backend-base" ] + dependencies: ['backend-base'] args: - - "BASE_IMAGE=<% .Global.docker.registry %>/backend-base" - - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" + - 'BASE_IMAGE=<% .Global.docker.registry %>/backend-base' + - 'BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>' values: image: tag: <% .Global.docker.tag | quote %> diff --git a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml index 00cd478..aceb400 100644 --- a/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml +++ b/_examples/monorepo/squadrons/checkout/frontend/squadron.yaml @@ -1,22 +1,22 @@ # Schema version -version: "2.0" +version: '2.0' squadron: checkout: frontend: chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend - tags: [ "frontend" ] + tags: ['frontend'] builds: default: - tag: "<% .Global.docker.tag %>" + tag: <% .Global.docker.tag | quote %> image: <% .Global.docker.registry %>/checkout-frontend context: <% env "PROJECT_ROOT" %>/squadrons/checkout/frontend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend.Dockerfile - dependencies: [ "frontend-base" ] + dependencies: ['frontend-base'] args: - - "BASE_IMAGE=<% .Global.docker.registry %>/frontend-base" - - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" + - 'BASE_IMAGE=<% .Global.docker.registry %>/frontend-base' + - 'BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>' values: image: - tag: "<% .Global.docker.tag %>" + tag: <% .Global.docker.tag | quote %> repository: <% .Squadron.checkout.frontend.builds.default.image %> diff --git a/_examples/monorepo/squadrons/squadron.yaml b/_examples/monorepo/squadrons/squadron.yaml index 3e901c0..167215f 100644 --- a/_examples/monorepo/squadrons/squadron.yaml +++ b/_examples/monorepo/squadrons/squadron.yaml @@ -1,8 +1,8 @@ -version: "2.0" +version: '2.0' global: docker: - tag: "230101.0" + tag: '230101.0' registry: monorepo builds: diff --git a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml index 391448c..bfe4059 100644 --- a/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml +++ b/_examples/monorepo/squadrons/storefinder/backend/squadron.yaml @@ -1,21 +1,21 @@ # Schema version -version: "2.0" +version: '2.0' squadron: storefinder: backend: chart: <% env "PROJECT_ROOT" %>/../common/charts/backend - tags: [ "backend" ] + tags: ['backend'] builds: default: tag: <% .Global.docker.tag | quote %> image: <% .Global.docker.registry %>/storefinder-backend context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/backend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/backend.Dockerfile - dependencies: [ "backend-base" ] + dependencies: ['backend-base'] args: - - "BASE_IMAGE=<% .Global.docker.registry %>/backend-base" - - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" + - 'BASE_IMAGE=<% .Global.docker.registry %>/backend-base' + - 'BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>' values: image: tag: <% .Global.docker.tag | quote %> diff --git a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml index e6018ef..5ffa94b 100644 --- a/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml +++ b/_examples/monorepo/squadrons/storefinder/frontend/squadron.yaml @@ -1,22 +1,22 @@ # Schema version -version: "2.0" +version: '2.0' squadron: storefinder: frontend: chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend - tags: [ "frontend" ] + tags: ['frontend'] builds: default: - tag: "<% .Global.docker.tag %>" + tag: <% .Global.docker.tag | quote %> image: <% .Global.docker.registry %>/storefinder-frontend context: <% env "PROJECT_ROOT" %>/squadrons/storefinder/frontend dockerfile: <% env "PROJECT_ROOT" %>/../common/docker/frontend.Dockerfile - dependencies: [ "frontend-base" ] + dependencies: ['frontend-base'] args: - - "BASE_IMAGE=<% .Global.docker.registry %>/frontend-base" - - "BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>" + - 'BASE_IMAGE=<% .Global.docker.registry %>/frontend-base' + - 'BASE_IMAGE_TAG=<% .Global.docker.tag | quote %>' values: image: - tag: "<% .Global.docker.tag %>" + tag: <% .Global.docker.tag | quote %> repository: <% .Squadron.storefinder.frontend.builds.default.image %> From 65b9a534bfa0044770d4858b7d99f4bc98b3b247 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:03:55 +0100 Subject: [PATCH 17/63] feat: add tags --- cmd/actions/diff.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/actions/diff.go b/cmd/actions/diff.go index fd98dc2..6394edf 100644 --- a/cmd/actions/diff.go +++ b/cmd/actions/diff.go @@ -8,6 +8,7 @@ import ( func init() { diffCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") diffCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") + diffCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var diffCmd = &cobra.Command{ From d034c0a73bfdb5331fbc2bd428965aa1830b459e Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:04:12 +0100 Subject: [PATCH 18/63] feat: only show output if not empty --- cmd/actions/list.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/actions/list.go b/cmd/actions/list.go index 46a9bd5..ef02f1e 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -62,8 +62,12 @@ var listCmd = &cobra.Command{ }) }) - root := putils.TreeFromLeveledList(list) - root.Text = "Squadron" - return pterm.DefaultTree.WithRoot(root).Render() + if len(list) > 0 { + root := putils.TreeFromLeveledList(list) + root.Text = "Squadron" + return pterm.DefaultTree.WithRoot(root).Render() + } + + return nil }, } From 740a5659c01355d5813ca498b197cb5a5bb0ac8f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:04:32 +0100 Subject: [PATCH 19/63] refactor: use pointer --- internal/helm/depency.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/helm/depency.go b/internal/helm/depency.go index 133cbb7..de46194 100644 --- a/internal/helm/depency.go +++ b/internal/helm/depency.go @@ -44,6 +44,6 @@ func (d *Dependency) UnmarshalYAML(value *yaml.Node) error { } } -func (d Dependency) String() string { +func (d *Dependency) String() string { return fmt.Sprintf("%s/%s:%s", d.Repository, d.Name, d.Version) } From 684859a1fa13c39db973c0d7a78925c8d4fab67d Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:04:42 +0100 Subject: [PATCH 20/63] feat: set stdin --- internal/util/cmd.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/util/cmd.go b/internal/util/cmd.go index 03ceb96..c994aaf 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -141,6 +141,9 @@ func (c *Cmd) Run(ctx context.Context) (string, error) { combinedBuf := new(bytes.Buffer) traceWriter := logrus.StandardLogger().WriterLevel(logrus.TraceLevel) + if c.stdin != nil { + cmd.Stdin = c.stdin + } cmd.Stdout = io.MultiWriter(append(c.stdoutWriters, combinedBuf, traceWriter)...) cmd.Stderr = io.MultiWriter(append(c.stderrWriters, combinedBuf, traceWriter)...) From d65d946812f0f49011a594ac04baf213b26c2a97 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:04:55 +0100 Subject: [PATCH 21/63] feat: update dependencies --- squadron.go | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/squadron.go b/squadron.go index 0cb36ea..2d86144 100644 --- a/squadron.go +++ b/squadron.go @@ -345,8 +345,13 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e return err } + // update local chart dependencies + if err := v.DependencyUpdate(ctx); err != nil { + return err + } + pterm.Debug.Printfln("running helm diff for: %s", k) - manifest, err := exec.CommandContext(ctx, "helm", "get", "manifest", name, "--namespace", sq.namespace).CombinedOutput() + manifest, err := exec.CommandContext(ctx, "helm", "get", "manifest", name, "--namespace", namespace).CombinedOutput() if err != nil && string(bytes.TrimSpace(manifest)) != errHelmReleaseNotFound { return errors.Wrap(err, string(manifest)) } @@ -527,16 +532,8 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version } // update local chart dependencies - // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql - if strings.HasPrefix(v.Chart.Repository, "file:///") { - pterm.Debug.Printfln("running helm dependency update for %s", v.Chart.Repository) - if out, err := util.NewHelmCommand(). - Stdout(os.Stdout). - Args("dependency", "update"). - Cwd(strings.TrimPrefix(v.Chart.Repository, "file://")). - Run(ctx); err != nil { - return errors.Wrap(err, out) - } + if err := v.DependencyUpdate(ctx); err != nil { + return err } // install chart @@ -594,6 +591,11 @@ func (sq *Squadron) Template(ctx context.Context, helmArgs []string, parallel in return err } + // update local chart dependencies + if err := v.DependencyUpdate(ctx); err != nil { + return err + } + pterm.Debug.Printfln("running helm template for chart: %s", name) out, err := v.Template(gctx, key, k, namespace, sq.c.Global, helmArgs) if err != nil { From f72cf48a68950e136a47d263c1c7ecbc2275e61b Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:05:27 +0100 Subject: [PATCH 22/63] style: format code --- testdata/blank/snapshop-config-norender.yaml | 2 +- testdata/blank/snapshop-config.yaml | 2 +- testdata/blank/squadron.yaml | 2 +- testdata/global/snapshop-config-norender.yaml | 2 +- testdata/global/snapshop-config.yaml | 6 +++--- testdata/global/squadron.override.yaml | 2 +- testdata/global/squadron.yaml | 2 +- testdata/override/snapshop-config-norender.yaml | 2 +- testdata/override/snapshop-config.yaml | 2 +- testdata/override/squadron.override.yaml | 2 +- testdata/override/squadron.yaml | 2 +- testdata/simple/snapshop-config-norender.yaml | 2 +- testdata/simple/snapshop-config.yaml | 2 +- testdata/simple/squadron.yaml | 2 +- testdata/tags/snapshop-config-norender.yaml | 2 +- testdata/tags/snapshop-config.yaml | 2 +- testdata/tags/squadron.yaml | 2 +- testdata/template/snapshop-config-norender.yaml | 2 +- testdata/template/snapshop-config.yaml | 2 +- testdata/template/squadron.yaml | 2 +- 20 files changed, 22 insertions(+), 22 deletions(-) diff --git a/testdata/blank/snapshop-config-norender.yaml b/testdata/blank/snapshop-config-norender.yaml index 98eb5e3..745b1fd 100644 --- a/testdata/blank/snapshop-config-norender.yaml +++ b/testdata/blank/snapshop-config-norender.yaml @@ -1 +1 @@ -version: "2.0" +version: '2.0' diff --git a/testdata/blank/snapshop-config.yaml b/testdata/blank/snapshop-config.yaml index 98eb5e3..745b1fd 100644 --- a/testdata/blank/snapshop-config.yaml +++ b/testdata/blank/snapshop-config.yaml @@ -1 +1 @@ -version: "2.0" +version: '2.0' diff --git a/testdata/blank/squadron.yaml b/testdata/blank/squadron.yaml index 98eb5e3..745b1fd 100644 --- a/testdata/blank/squadron.yaml +++ b/testdata/blank/squadron.yaml @@ -1 +1 @@ -version: "2.0" +version: '2.0' diff --git a/testdata/global/snapshop-config-norender.yaml b/testdata/global/snapshop-config-norender.yaml index 6bcb5e8..242c792 100644 --- a/testdata/global/snapshop-config-norender.yaml +++ b/testdata/global/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' global: bar: - one diff --git a/testdata/global/snapshop-config.yaml b/testdata/global/snapshop-config.yaml index 6bcb5e8..aa70f41 100644 --- a/testdata/global/snapshop-config.yaml +++ b/testdata/global/snapshop-config.yaml @@ -1,7 +1,7 @@ -version: "2.0" +version: '2.0' global: bar: - - one - - two + - one + - two baz: null foo: two diff --git a/testdata/global/squadron.override.yaml b/testdata/global/squadron.override.yaml index 5bea499..5857de5 100644 --- a/testdata/global/squadron.override.yaml +++ b/testdata/global/squadron.override.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' global: foo: "two" diff --git a/testdata/global/squadron.yaml b/testdata/global/squadron.yaml index b3e1540..52aa8b1 100644 --- a/testdata/global/squadron.yaml +++ b/testdata/global/squadron.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' global: foo: "one" diff --git a/testdata/override/snapshop-config-norender.yaml b/testdata/override/snapshop-config-norender.yaml index f9ac5bb..4507528 100644 --- a/testdata/override/snapshop-config-norender.yaml +++ b/testdata/override/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: frontend: diff --git a/testdata/override/snapshop-config.yaml b/testdata/override/snapshop-config.yaml index 5003b09..cd9073d 100644 --- a/testdata/override/snapshop-config.yaml +++ b/testdata/override/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: frontend: diff --git a/testdata/override/squadron.override.yaml b/testdata/override/squadron.override.yaml index 7e1d3ca..584cc0b 100644 --- a/testdata/override/squadron.override.yaml +++ b/testdata/override/squadron.override.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: diff --git a/testdata/override/squadron.yaml b/testdata/override/squadron.yaml index 1c016e1..0e85b7d 100644 --- a/testdata/override/squadron.yaml +++ b/testdata/override/squadron.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: diff --git a/testdata/simple/snapshop-config-norender.yaml b/testdata/simple/snapshop-config-norender.yaml index 93d19a6..f6b2b20 100644 --- a/testdata/simple/snapshop-config-norender.yaml +++ b/testdata/simple/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: frontend: diff --git a/testdata/simple/snapshop-config.yaml b/testdata/simple/snapshop-config.yaml index 6cff186..759989a 100644 --- a/testdata/simple/snapshop-config.yaml +++ b/testdata/simple/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: frontend: diff --git a/testdata/simple/squadron.yaml b/testdata/simple/squadron.yaml index 2950ea4..efbd463 100644 --- a/testdata/simple/squadron.yaml +++ b/testdata/simple/squadron.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: diff --git a/testdata/tags/snapshop-config-norender.yaml b/testdata/tags/snapshop-config-norender.yaml index 4242767..11d904e 100644 --- a/testdata/tags/snapshop-config-norender.yaml +++ b/testdata/tags/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: checkout: backend: diff --git a/testdata/tags/snapshop-config.yaml b/testdata/tags/snapshop-config.yaml index 8627480..128a8f3 100644 --- a/testdata/tags/snapshop-config.yaml +++ b/testdata/tags/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: checkout: backend: diff --git a/testdata/tags/squadron.yaml b/testdata/tags/squadron.yaml index 4a95ee3..73b1e6d 100644 --- a/testdata/tags/squadron.yaml +++ b/testdata/tags/squadron.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' squadron: storefinder: diff --git a/testdata/template/snapshop-config-norender.yaml b/testdata/template/snapshop-config-norender.yaml index 2542250..58e1ccb 100644 --- a/testdata/template/snapshop-config-norender.yaml +++ b/testdata/template/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' global: host: mycompany.com squadron: diff --git a/testdata/template/snapshop-config.yaml b/testdata/template/snapshop-config.yaml index f19196f..4a0abd2 100644 --- a/testdata/template/snapshop-config.yaml +++ b/testdata/template/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' global: host: mycompany.com squadron: diff --git a/testdata/template/squadron.yaml b/testdata/template/squadron.yaml index 6af8c63..0c89c18 100644 --- a/testdata/template/squadron.yaml +++ b/testdata/template/squadron.yaml @@ -1,4 +1,4 @@ -version: "2.0" +version: '2.0' global: host: mycompany.com From f5aaffc19981fc50def2c78de2bcc9b4068bcee0 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:05:41 +0100 Subject: [PATCH 23/63] feat: add debug --- internal/config/unit.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/internal/config/unit.go b/internal/config/unit.go index adaf03d..6398ddb 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "os" "path" "strings" @@ -32,7 +31,9 @@ func (u *Unit) ValuesYAML(global map[string]interface{}) ([]byte, error) { values = map[string]interface{}{} } if global != nil { - values["global"] = global + if _, ok := values["global"]; !ok { + values["global"] = global + } } return yamlv2.Marshal(values) } @@ -79,6 +80,7 @@ func (u *Unit) Template(ctx context.Context, squadron, unit, namespace string, g Stdout(&ret). Args("--dependency-update"). Args("--namespace", namespace). + Args("--debug"). Args("--set", fmt.Sprintf("squadron=%s", squadron)). Args("--set", fmt.Sprintf("unit=%s", unit)). Args("--values", "-"). @@ -100,12 +102,13 @@ func (u *Unit) DependencyUpdate(ctx context.Context) error { // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql if strings.HasPrefix(u.Chart.Repository, "file:///") { pterm.Debug.Printfln("running helm dependency update for %s", u.Chart.Repository) - if out, err := util.NewHelmCommand(). - Stdout(os.Stdout). - Args("dependency", "update"). + sh := util.NewHelmCommand(). Cwd(strings.TrimPrefix(u.Chart.Repository, "file://")). - Run(ctx); err != nil { + Args("dependency", "update", "--skip-refresh", "--debug") + if out, err := sh.Run(ctx); err != nil { return errors.Wrap(err, out) + } else { + pterm.Debug.Println(out) } } return nil From 761faaca1a2a479327cbd8522762bba167b81379 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:52:12 +0100 Subject: [PATCH 24/63] refactor: simplify --- internal/util/cmd.go | 83 +++++--------------------------------------- 1 file changed, 8 insertions(+), 75 deletions(-) diff --git a/internal/util/cmd.go b/internal/util/cmd.go index c994aaf..6ef21ad 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -6,7 +6,6 @@ import ( "io" "os" "os/exec" - "time" "github.com/pterm/pterm" "github.com/sirupsen/logrus" @@ -20,18 +19,13 @@ type Cmd struct { stdin io.Reader stdoutWriters []io.Writer stderrWriters []io.Writer - wait bool - timeout time.Duration - preStartFunc func() error - postStartFunc func() error - postEndFunc func() error } func NewCommand(name string) *Cmd { return &Cmd{ command: []string{name}, - wait: true, - env: os.Environ(), + //wait: true, + env: os.Environ(), } } @@ -105,31 +99,6 @@ func (c *Cmd) Stderr(w io.Writer) *Cmd { return c } -func (c *Cmd) Timeout(t time.Duration) *Cmd { - c.timeout = t - return c -} - -func (c *Cmd) NoWait() *Cmd { - c.wait = false - return c -} - -func (c *Cmd) PreStart(f func() error) *Cmd { - c.preStartFunc = f - return c -} - -func (c *Cmd) PostStart(f func() error) *Cmd { - c.postStartFunc = f - return c -} - -func (c *Cmd) PostEnd(f func() error) *Cmd { - c.postEndFunc = f - return c -} - func (c *Cmd) Run(ctx context.Context) (string, error) { cmd := exec.CommandContext(ctx, c.command[0], c.command[1:]...) //nolint:gosec cmd.Env = append(os.Environ(), c.env...) @@ -138,52 +107,16 @@ func (c *Cmd) Run(ctx context.Context) (string, error) { } pterm.Debug.Printfln("executing %s", cmd.String()) - combinedBuf := new(bytes.Buffer) + var stdout bytes.Buffer + var stderr bytes.Buffer traceWriter := logrus.StandardLogger().WriterLevel(logrus.TraceLevel) if c.stdin != nil { cmd.Stdin = c.stdin } - cmd.Stdout = io.MultiWriter(append(c.stdoutWriters, combinedBuf, traceWriter)...) - cmd.Stderr = io.MultiWriter(append(c.stderrWriters, combinedBuf, traceWriter)...) - - if c.preStartFunc != nil { - pterm.Debug.Println("executing pre start func") - if err := c.preStartFunc(); err != nil { - return combinedBuf.String(), err - } - } - - if err := cmd.Start(); err != nil { - return combinedBuf.String(), err - } - - if c.postStartFunc != nil { - pterm.Debug.Println("executing post start func") - if err := c.postStartFunc(); err != nil { - return combinedBuf.String(), err - } - } - - if c.wait { - if c.timeout != 0 { - timer := time.AfterFunc(c.timeout, func() { - _ = cmd.Process.Kill() - }) - defer timer.Stop() - } - - if err := cmd.Wait(); err != nil { - if c.timeout == 0 { - return combinedBuf.String(), err - } - } - if c.postEndFunc != nil { - if err := c.postEndFunc(); err != nil { - return combinedBuf.String(), err - } - } - } + cmd.Stdout = io.MultiWriter(append(c.stdoutWriters, &stdout, traceWriter)...) + cmd.Stderr = io.MultiWriter(append(c.stderrWriters, &stderr, traceWriter)...) - return combinedBuf.String(), nil + err := cmd.Run() + return stdout.String() + stderr.String(), err } From 626a5f5dd1c853b5e4b0902abfff60c5e94e6d01 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:52:24 +0100 Subject: [PATCH 25/63] test: update snapshots --- testdata/blank/snapshop-config-norender.yaml | 2 +- testdata/blank/snapshop-config.yaml | 2 +- testdata/blank/squadron.yaml | 2 +- testdata/global/snapshop-config-norender.yaml | 2 +- testdata/global/snapshop-config.yaml | 6 +++--- testdata/global/squadron.override.yaml | 2 +- testdata/global/squadron.yaml | 2 +- .../override/snapshop-config-norender.yaml | 6 +++--- testdata/override/snapshop-config.yaml | 6 +++--- testdata/override/snapshop-template.yaml | 12 ++++++------ testdata/override/squadron.override.yaml | 4 ++-- testdata/override/squadron.yaml | 10 +++++----- testdata/simple/snapshop-config-norender.yaml | 2 +- testdata/simple/snapshop-config.yaml | 2 +- testdata/simple/snapshop-template.yaml | 12 ++++++------ testdata/simple/squadron.yaml | 2 +- testdata/tags/snapshop-config-norender.yaml | 2 +- testdata/tags/snapshop-config.yaml | 2 +- testdata/tags/snapshop-template.yaml | 6 +++--- testdata/tags/squadron.yaml | 2 +- .../template/snapshop-config-norender.yaml | 2 +- testdata/template/snapshop-config.yaml | 2 +- testdata/template/snapshop-template.yaml | 18 +++++++++--------- testdata/template/squadron.yaml | 2 +- 24 files changed, 55 insertions(+), 55 deletions(-) diff --git a/testdata/blank/snapshop-config-norender.yaml b/testdata/blank/snapshop-config-norender.yaml index 745b1fd..98eb5e3 100644 --- a/testdata/blank/snapshop-config-norender.yaml +++ b/testdata/blank/snapshop-config-norender.yaml @@ -1 +1 @@ -version: '2.0' +version: "2.0" diff --git a/testdata/blank/snapshop-config.yaml b/testdata/blank/snapshop-config.yaml index 745b1fd..98eb5e3 100644 --- a/testdata/blank/snapshop-config.yaml +++ b/testdata/blank/snapshop-config.yaml @@ -1 +1 @@ -version: '2.0' +version: "2.0" diff --git a/testdata/blank/squadron.yaml b/testdata/blank/squadron.yaml index 745b1fd..98eb5e3 100644 --- a/testdata/blank/squadron.yaml +++ b/testdata/blank/squadron.yaml @@ -1 +1 @@ -version: '2.0' +version: "2.0" diff --git a/testdata/global/snapshop-config-norender.yaml b/testdata/global/snapshop-config-norender.yaml index 242c792..6bcb5e8 100644 --- a/testdata/global/snapshop-config-norender.yaml +++ b/testdata/global/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" global: bar: - one diff --git a/testdata/global/snapshop-config.yaml b/testdata/global/snapshop-config.yaml index aa70f41..6bcb5e8 100644 --- a/testdata/global/snapshop-config.yaml +++ b/testdata/global/snapshop-config.yaml @@ -1,7 +1,7 @@ -version: '2.0' +version: "2.0" global: bar: - - one - - two + - one + - two baz: null foo: two diff --git a/testdata/global/squadron.override.yaml b/testdata/global/squadron.override.yaml index 5857de5..5bea499 100644 --- a/testdata/global/squadron.override.yaml +++ b/testdata/global/squadron.override.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" global: foo: "two" diff --git a/testdata/global/squadron.yaml b/testdata/global/squadron.yaml index 52aa8b1..b3e1540 100644 --- a/testdata/global/squadron.yaml +++ b/testdata/global/squadron.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" global: foo: "one" diff --git a/testdata/override/snapshop-config-norender.yaml b/testdata/override/snapshop-config-norender.yaml index 4507528..80c2505 100644 --- a/testdata/override/snapshop-config-norender.yaml +++ b/testdata/override/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: frontend: @@ -8,12 +8,12 @@ squadron: version: 0.0.1 builds: default: - args: + build_arg: - foo=foo - bar=bar - bar=baz - baz=baz - dockerfile: Dockerfile + file: Dockerfile tag: nightly image: docker.mycompany.com/mycomapny/frontend values: diff --git a/testdata/override/snapshop-config.yaml b/testdata/override/snapshop-config.yaml index cd9073d..4ff7918 100644 --- a/testdata/override/snapshop-config.yaml +++ b/testdata/override/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: frontend: @@ -8,12 +8,12 @@ squadron: version: 0.0.1 builds: default: - args: + build_arg: - foo=foo - bar=bar - bar=baz - baz=baz - dockerfile: Dockerfile + file: Dockerfile tag: nightly image: docker.mycompany.com/mycomapny/frontend values: diff --git a/testdata/override/snapshop-template.yaml b/testdata/override/snapshop-template.yaml index 3a8cfe9..1791dda 100644 --- a/testdata/override/snapshop-template.yaml +++ b/testdata/override/snapshop-template.yaml @@ -8,7 +8,7 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: type: ClusterIP @@ -28,7 +28,7 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: selector: @@ -43,7 +43,7 @@ spec: spec: containers: - name: frontend - image: nginx:latest + image: 'docker.mycompany.com/mycomapny/frontend:nightly' ports: - name: http protocol: TCP @@ -58,14 +58,14 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: tls: - - hosts: [ "foo.com" ] + - hosts: ['foo.com'] secretName: foo-com-cert rules: - - host: foo.com + - host: foo.com http: paths: - pathType: Prefix diff --git a/testdata/override/squadron.override.yaml b/testdata/override/squadron.override.yaml index 584cc0b..0812155 100644 --- a/testdata/override/squadron.override.yaml +++ b/testdata/override/squadron.override.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: @@ -8,7 +8,7 @@ squadron: # override element tag: nightly # append new element to array - args: + build_arg: - "bar=baz" - "baz=baz" # override backend diff --git a/testdata/override/squadron.yaml b/testdata/override/squadron.yaml index 0e85b7d..c4979e9 100644 --- a/testdata/override/squadron.yaml +++ b/testdata/override/squadron.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: @@ -7,9 +7,9 @@ squadron: builds: default: tag: latest - dockerfile: Dockerfile + file: Dockerfile image: docker.mycompany.com/mycomapny/frontend - args: + build_arg: - "foo=foo" - "bar=bar" values: @@ -21,9 +21,9 @@ squadron: builds: default: tag: latest - dockerfile: Dockerfile + file: Dockerfile image: docker.mycompany.com/mycomapny/backend - args: + build_arg: - "foo=foo" - "bar=bar" values: diff --git a/testdata/simple/snapshop-config-norender.yaml b/testdata/simple/snapshop-config-norender.yaml index f6b2b20..93d19a6 100644 --- a/testdata/simple/snapshop-config-norender.yaml +++ b/testdata/simple/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: frontend: diff --git a/testdata/simple/snapshop-config.yaml b/testdata/simple/snapshop-config.yaml index 759989a..6cff186 100644 --- a/testdata/simple/snapshop-config.yaml +++ b/testdata/simple/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: frontend: diff --git a/testdata/simple/snapshop-template.yaml b/testdata/simple/snapshop-template.yaml index 3a8cfe9..d8dd981 100644 --- a/testdata/simple/snapshop-template.yaml +++ b/testdata/simple/snapshop-template.yaml @@ -8,7 +8,7 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: type: ClusterIP @@ -28,7 +28,7 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: selector: @@ -43,7 +43,7 @@ spec: spec: containers: - name: frontend - image: nginx:latest + image: 'nginx:latest' ports: - name: http protocol: TCP @@ -58,14 +58,14 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: tls: - - hosts: [ "foo.com" ] + - hosts: ['foo.com'] secretName: foo-com-cert rules: - - host: foo.com + - host: foo.com http: paths: - pathType: Prefix diff --git a/testdata/simple/squadron.yaml b/testdata/simple/squadron.yaml index efbd463..2950ea4 100644 --- a/testdata/simple/squadron.yaml +++ b/testdata/simple/squadron.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: diff --git a/testdata/tags/snapshop-config-norender.yaml b/testdata/tags/snapshop-config-norender.yaml index 11d904e..4242767 100644 --- a/testdata/tags/snapshop-config-norender.yaml +++ b/testdata/tags/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: checkout: backend: diff --git a/testdata/tags/snapshop-config.yaml b/testdata/tags/snapshop-config.yaml index 128a8f3..8627480 100644 --- a/testdata/tags/snapshop-config.yaml +++ b/testdata/tags/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: checkout: backend: diff --git a/testdata/tags/snapshop-template.yaml b/testdata/tags/snapshop-template.yaml index 930863d..3b22b7f 100644 --- a/testdata/tags/snapshop-template.yaml +++ b/testdata/tags/snapshop-template.yaml @@ -8,7 +8,7 @@ metadata: app.kubernetes.io/name: backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm - helm.sh/chart: backend-0.0.1 + helm.sh/chart: 'backend-0.0.1' namespace: default spec: type: ClusterIP @@ -28,7 +28,7 @@ metadata: app.kubernetes.io/name: backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm - helm.sh/chart: backend-0.0.1 + helm.sh/chart: 'backend-0.0.1' namespace: default spec: selector: @@ -43,7 +43,7 @@ spec: spec: containers: - name: backend - image: nginx:latest + image: 'nginx:latest' ports: - name: http protocol: TCP diff --git a/testdata/tags/squadron.yaml b/testdata/tags/squadron.yaml index 73b1e6d..4a95ee3 100644 --- a/testdata/tags/squadron.yaml +++ b/testdata/tags/squadron.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" squadron: storefinder: diff --git a/testdata/template/snapshop-config-norender.yaml b/testdata/template/snapshop-config-norender.yaml index 58e1ccb..2542250 100644 --- a/testdata/template/snapshop-config-norender.yaml +++ b/testdata/template/snapshop-config-norender.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" global: host: mycompany.com squadron: diff --git a/testdata/template/snapshop-config.yaml b/testdata/template/snapshop-config.yaml index 4a0abd2..f19196f 100644 --- a/testdata/template/snapshop-config.yaml +++ b/testdata/template/snapshop-config.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" global: host: mycompany.com squadron: diff --git a/testdata/template/snapshop-template.yaml b/testdata/template/snapshop-template.yaml index 419055f..44d6b21 100644 --- a/testdata/template/snapshop-template.yaml +++ b/testdata/template/snapshop-template.yaml @@ -8,7 +8,7 @@ metadata: app.kubernetes.io/name: backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm - helm.sh/chart: backend-0.0.1 + helm.sh/chart: 'backend-0.0.1' namespace: default spec: type: ClusterIP @@ -28,7 +28,7 @@ metadata: app.kubernetes.io/name: backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm - helm.sh/chart: backend-0.0.1 + helm.sh/chart: 'backend-0.0.1' namespace: default spec: selector: @@ -43,7 +43,7 @@ spec: spec: containers: - name: backend - image: nginx:latest + image: 'docker.mycompany.com/mycomapny/frontend-admin:latest' ports: - name: http protocol: TCP @@ -58,7 +58,7 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: type: ClusterIP @@ -78,7 +78,7 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: selector: @@ -93,7 +93,7 @@ spec: spec: containers: - name: frontend - image: nginx:latest + image: 'docker.mycompany.com/mycomapny/frontend:latest' ports: - name: http protocol: TCP @@ -108,14 +108,14 @@ metadata: app.kubernetes.io/name: frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm - helm.sh/chart: frontend-0.0.1 + helm.sh/chart: 'frontend-0.0.1' namespace: default spec: tls: - - hosts: [ "foo.com" ] + - hosts: ['foo.com'] secretName: foo-com-cert rules: - - host: foo.com + - host: foo.com http: paths: - pathType: Prefix diff --git a/testdata/template/squadron.yaml b/testdata/template/squadron.yaml index 0c89c18..6af8c63 100644 --- a/testdata/template/squadron.yaml +++ b/testdata/template/squadron.yaml @@ -1,4 +1,4 @@ -version: '2.0' +version: "2.0" global: host: mycompany.com From 17cf94c0513165b90118f267ba95c675866a68d9 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 3 Jan 2024 17:52:46 +0100 Subject: [PATCH 26/63] style: cleanup --- internal/util/cmd.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/util/cmd.go b/internal/util/cmd.go index 6ef21ad..e3f8a61 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -12,7 +12,6 @@ import ( ) type Cmd struct { - // cmd *exec.Cmd command []string cwd string env []string @@ -24,8 +23,7 @@ type Cmd struct { func NewCommand(name string) *Cmd { return &Cmd{ command: []string{name}, - //wait: true, - env: os.Environ(), + env: os.Environ(), } } From a596b9ade025b5892112d7779fc3999f64440026 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 4 Jan 2024 09:15:18 +0100 Subject: [PATCH 27/63] chore: bump deps --- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d70963f..389f426 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -25,7 +25,7 @@ jobs: check-latest: true go-version-file: 'go.mod' - - uses: goreleaser/goreleaser-action@v4 + - uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cf52121..5e379a0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: From be02a24a8a16a470ce05e143411e9d3477046f76 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 4 Jan 2024 09:15:26 +0100 Subject: [PATCH 28/63] chore: bump deps --- go.mod | 8 ++++---- go.sum | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index cbf2c17..1ee5827 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/miracl/conflate v1.2.1 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.71 + github.com/pterm/pterm v0.12.74 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 @@ -51,9 +51,9 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/atomic v1.10.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect diff --git a/go.sum b/go.sum index e1b2548..a5c7cc9 100644 --- a/go.sum +++ b/go.sum @@ -94,6 +94,8 @@ github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5b github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/pterm/pterm v0.12.71 h1:KcEJ98EiVCbzDkFbktJ2gMlr4pn8IzyGb9bwK6ffkuA= github.com/pterm/pterm v0.12.71/go.mod h1:SUAcoZjRt+yjPWlWba+/Fd8zJJ2lSXBQWf0Z0HbFiIQ= +github.com/pterm/pterm v0.12.74 h1:fPsds9KisCyJh4NyY6bv8QJt3FLHceb5DxI6W0An9cc= +github.com/pterm/pterm v0.12.74/go.mod h1:+M33aZWQVpmLmLbvjykyGZ4gAfeebznRo8JMbabaxQU= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -181,6 +183,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -188,6 +192,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -195,6 +201,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= From f625c2184e6541b7fc90c9f2a8dad687df88ee86 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 4 Jan 2024 09:15:36 +0100 Subject: [PATCH 29/63] fix: values --- squadron.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/squadron.go b/squadron.go index 2d86144..b830134 100644 --- a/squadron.go +++ b/squadron.go @@ -547,7 +547,7 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version Args("--namespace", namespace). Args("--dependency-update"). Args("--install"). - Args("-values", "-"). + Args("--values", "-"). Args(helmArgs...) if strings.Contains(v.Chart.Repository, "file://") { From 0c124cdca65a0896b009e89df833219fcc0ba18b Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 4 Jan 2024 09:17:33 +0100 Subject: [PATCH 30/63] chore: set prerelease to auto --- .goreleaser.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 1ffc920..d68d19e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -19,6 +19,9 @@ builds: ldflags: - -s -w -X github.com/foomo/squadron/cmd/actions.version={{.Version}} +release: + prerelease: auto + archives: - format: tar.gz format_overrides: From fc81affa3dc0f815568755c3874a7c031bf07561 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 12 Jan 2024 13:56:39 +0100 Subject: [PATCH 31/63] fix: pass name to template --- internal/config/unit.go | 4 ++-- squadron.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/config/unit.go b/internal/config/unit.go index 6398ddb..cf378ce 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -68,14 +68,14 @@ func (u *Unit) Push(ctx context.Context, squadron, unit string, args []string) ( return "", nil } -func (u *Unit) Template(ctx context.Context, squadron, unit, namespace string, global map[string]interface{}, helmArgs []string) ([]byte, error) { +func (u *Unit) Template(ctx context.Context, name, squadron, unit, namespace string, global map[string]interface{}, helmArgs []string) ([]byte, error) { var ret bytes.Buffer valueBytes, err := u.ValuesYAML(global) if err != nil { return nil, err } - cmd := util.NewHelmCommand().Args("template", unit). + cmd := util.NewHelmCommand().Args("template", name). Stdin(bytes.NewReader(valueBytes)). Stdout(&ret). Args("--dependency-update"). diff --git a/squadron.go b/squadron.go index b830134..4ab7bd6 100644 --- a/squadron.go +++ b/squadron.go @@ -597,7 +597,7 @@ func (sq *Squadron) Template(ctx context.Context, helmArgs []string, parallel in } pterm.Debug.Printfln("running helm template for chart: %s", name) - out, err := v.Template(gctx, key, k, namespace, sq.c.Global, helmArgs) + out, err := v.Template(gctx, name, key, k, namespace, sq.c.Global, helmArgs) if err != nil { return err } From 5fed842cf1ff3e7f6e45b3def480f37a90b171ae Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 24 Jan 2024 15:15:58 +0100 Subject: [PATCH 32/63] feat: only render config if needed --- cmd/actions/build.go | 4 ---- cmd/actions/list.go | 4 ---- cmd/actions/push.go | 4 ---- cmd/actions/rollback.go | 4 ---- cmd/actions/status.go | 4 ---- 5 files changed, 20 deletions(-) diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 6e8d790..25a1ecb 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -30,10 +30,6 @@ var buildCmd = &cobra.Command{ return err } - if err := sq.RenderConfig(cmd.Context()); err != nil { - return err - } - if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { return err } diff --git a/cmd/actions/list.go b/cmd/actions/list.go index ef02f1e..6975fd4 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -36,10 +36,6 @@ var listCmd = &cobra.Command{ return err } - if err := sq.RenderConfig(cmd.Context()); err != nil { - return err - } - var list pterm.LeveledList // List squadrons diff --git a/cmd/actions/push.go b/cmd/actions/push.go index 41e48f8..d6f3af6 100644 --- a/cmd/actions/push.go +++ b/cmd/actions/push.go @@ -30,10 +30,6 @@ var pushCmd = &cobra.Command{ return err } - if err := sq.RenderConfig(cmd.Context()); err != nil { - return err - } - if flagBuild { if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { return err diff --git a/cmd/actions/rollback.go b/cmd/actions/rollback.go index aa333fb..81bf8f4 100644 --- a/cmd/actions/rollback.go +++ b/cmd/actions/rollback.go @@ -31,10 +31,6 @@ var rollbackCmd = &cobra.Command{ return err } - if err := sq.RenderConfig(cmd.Context()); err != nil { - return err - } - return sq.Rollback(cmd.Context(), flagRevision, helmArgs, flagParallel) }, } diff --git a/cmd/actions/status.go b/cmd/actions/status.go index d83e47e..a3314e6 100644 --- a/cmd/actions/status.go +++ b/cmd/actions/status.go @@ -30,10 +30,6 @@ var statusCmd = &cobra.Command{ return err } - if err := sq.RenderConfig(cmd.Context()); err != nil { - return err - } - return sq.Status(cmd.Context(), helmArgs, flagParallel) }, } From ef88b139fcc45c28b8875211f61d9de118343f50 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 25 Jan 2024 06:21:49 +0100 Subject: [PATCH 33/63] revert: only render config if needed --- cmd/actions/build.go | 4 ++++ cmd/actions/push.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 25a1ecb..6e8d790 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -30,6 +30,10 @@ var buildCmd = &cobra.Command{ return err } + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } + if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { return err } diff --git a/cmd/actions/push.go b/cmd/actions/push.go index d6f3af6..41e48f8 100644 --- a/cmd/actions/push.go +++ b/cmd/actions/push.go @@ -30,6 +30,10 @@ var pushCmd = &cobra.Command{ return err } + if err := sq.RenderConfig(cmd.Context()); err != nil { + return err + } + if flagBuild { if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { return err From 04b8fe6e9ea56c3102b6b7b13e4ea6848ae109a1 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Sat, 27 Jan 2024 00:17:15 +0100 Subject: [PATCH 34/63] feat: add kustomize --- cmd/actions/postrenderer.go | 38 +++++++++++++++++++++++++++++++++++++ cmd/actions/root.go | 3 +-- internal/config/unit.go | 22 +++++++++++++++++---- squadron.go | 1 + 4 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 cmd/actions/postrenderer.go diff --git a/cmd/actions/postrenderer.go b/cmd/actions/postrenderer.go new file mode 100644 index 0000000..1b66f3e --- /dev/null +++ b/cmd/actions/postrenderer.go @@ -0,0 +1,38 @@ +package actions + +import ( + "io" + "os" + "os/exec" + "path" + + "github.com/spf13/cobra" +) + +func init() { +} + +var postRendererCmd = &cobra.Command{ + Use: "post-renderer [PATH]", + Hidden: true, + Short: "render chart templates locally and display the output", + Example: " squadron template storefinder frontend backend --namespace demo", + Args: cobra.MinimumNArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + + // this does the trick + r, err := io.ReadAll(cmd.InOrStdin()) + if err != nil { + return err + } + + err = os.WriteFile(path.Join(args[0], ".chart.yaml"), r, 0644) + if err != nil { + return err + } + + c := exec.CommandContext(cmd.Context(), "kustomize", "build", args[0]) + c.Stdout = os.Stdout + return c.Run() + }, +} diff --git a/cmd/actions/root.go b/cmd/actions/root.go index 7bfd6ed..2c7ecd0 100644 --- a/cmd/actions/root.go +++ b/cmd/actions/root.go @@ -47,7 +47,6 @@ var ( flagBuildArgs []string flagPushArgs []string flagTags []string - flagDiff bool flagFiles []string ) @@ -57,7 +56,7 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "show more output") rootCmd.PersistentFlags().StringSliceVarP(&flagFiles, "file", "f", []string{"squadron.yaml"}, "specify alternative squadron files") - rootCmd.AddCommand(upCmd, diffCmd, downCmd, buildCmd, pushCmd, listCmd, rollbackCmd, statusCmd, configCmd, versionCmd, completionCmd, templateCmd) + rootCmd.AddCommand(upCmd, diffCmd, downCmd, buildCmd, pushCmd, listCmd, rollbackCmd, statusCmd, configCmd, versionCmd, completionCmd, templateCmd, postRendererCmd) pterm.Info = *pterm.Info.WithPrefix(pterm.Prefix{Text: "INFO", Style: pterm.Info.Prefix.Style}) pterm.Error = *pterm.Info.WithPrefix(pterm.Prefix{Text: "ERROR", Style: pterm.Error.Prefix.Style}) diff --git a/internal/config/unit.go b/internal/config/unit.go index cf378ce..36745b0 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -15,10 +15,11 @@ import ( ) type Unit struct { - Chart helm.Dependency `yaml:"chart,omitempty"` - Tags []Tag `yaml:"tags,omitempty"` - Builds map[string]Build `yaml:"builds,omitempty"` - Values map[string]interface{} `yaml:"values,omitempty"` + Chart helm.Dependency `yaml:"chart,omitempty"` + Kustomize string `yaml:"kustomize,omitempty"` + Tags []Tag `yaml:"tags,omitempty"` + Builds map[string]Build `yaml:"builds,omitempty"` + Values map[string]interface{} `yaml:"values,omitempty"` } // ------------------------------------------------------------------------------------------------ @@ -83,6 +84,7 @@ func (u *Unit) Template(ctx context.Context, name, squadron, unit, namespace str Args("--debug"). Args("--set", fmt.Sprintf("squadron=%s", squadron)). Args("--set", fmt.Sprintf("unit=%s", unit)). + Args(u.PostRendererArgs()...). Args("--values", "-"). Args(helmArgs...) if strings.HasPrefix(u.Chart.Repository, "file://") { @@ -113,3 +115,15 @@ func (u *Unit) DependencyUpdate(ctx context.Context) error { } return nil } + +func (u *Unit) PostRendererArgs() []string { + var ret []string + if u.Kustomize != "" { + ret = append(ret, + "--post-renderer", "squadron", + "--post-renderer-args", "post-renderer", + "--post-renderer-args", u.Kustomize, + ) + } + return ret +} diff --git a/squadron.go b/squadron.go index 4ab7bd6..d22cec5 100644 --- a/squadron.go +++ b/squadron.go @@ -546,6 +546,7 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version Args("--description", description). Args("--namespace", namespace). Args("--dependency-update"). + Args(v.PostRendererArgs()...). Args("--install"). Args("--values", "-"). Args(helmArgs...) From 5e8747e8aa67f494aa0387d29d3d82ff262dd642 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Sat, 27 Jan 2024 00:19:34 +0100 Subject: [PATCH 35/63] docs: update readme --- README.md | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 88405ef..b3c7e82 100644 --- a/README.md +++ b/README.md @@ -16,24 +16,38 @@ Configure your squadron ```yaml # squadron.yaml -version: "1.0" +version: '2.0' squadron: - frontend: - chart: - name: mychart - version: 0.1.0 - repository: http://helm.mycompany.com/repository - builds: - service: - tag: latest - dockerfile: Dockerfile - image: docker.mycompany.com/mycomapny/frontend - args: - - "foo=foo" - - "bar=bar" - values: - image: docker.mycompany.com/mycomapny/frontend:latest + site: + frontend: + chart: + name: mychart + version: 0.1.0 + repository: http://helm.mycompany.com/repository + builds: + service: + tag: latest + dockerfile: Dockerfile + image: docker.mycompany.com/mycomapny/frontend + args: + - "foo=foo" + - "bar=bar" + values: + image: docker.mycompany.com/mycomapny/frontend:latest + backend: + chart: <% env "PROJECT_ROOT" %>/path/to/chart + kustomize: <% env "PROJECT_ROOT" %>/path/to/kustomize + builds: + service: + tag: latest + dockerfile: Dockerfile + image: docker.mycompany.com/mycomapny/backend + args: + - "foo=foo" + - "bar=bar" + values: + image: docker.mycompany.com/mycomapny/backend:latest ``` Install the squadron squadron and namespace: From 18271677d6d2b8894eb3a5ec32ce06f2642bff56 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 29 Jan 2024 11:41:13 +0100 Subject: [PATCH 36/63] feat: split up chart args --- squadron.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/squadron.go b/squadron.go index d22cec5..7ea1342 100644 --- a/squadron.go +++ b/squadron.go @@ -554,7 +554,13 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version if strings.Contains(v.Chart.Repository, "file://") { cmd.Args(strings.TrimPrefix(v.Chart.Repository, "file://")) } else { - cmd.Args(v.Chart.Name, "--repo", v.Chart.Repository, "--version", v.Chart.Version) + cmd.Args(v.Chart.Name) + if v.Chart.Repository != "" { + cmd.Args("--repo", v.Chart.Repository) + } + if v.Chart.Version != "" { + cmd.Args("--version", v.Chart.Version) + } } if out, err := cmd.Run(gctx); err != nil { From 454121b303204bc5416cee8600fdb424b0f12471 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Jan 2024 13:32:34 +0100 Subject: [PATCH 37/63] feat: add with-tags --- cmd/actions/list.go | 17 +++++++++++------ internal/config/tag.go | 4 ++++ internal/config/tags.go | 30 ++++++++++++++++++++++++++++++ internal/config/unit.go | 2 +- 4 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 internal/config/tags.go diff --git a/cmd/actions/list.go b/cmd/actions/list.go index 6975fd4..e27cfe8 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -9,14 +9,16 @@ import ( ) var ( - flagBuilds bool - flagCharts bool + flagWithBuilds bool + flagWithCharts bool + flagWithTags bool ) func init() { listCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") - listCmd.Flags().BoolVar(&flagCharts, "charts", false, "include charts") - listCmd.Flags().BoolVar(&flagBuilds, "builds", false, "include builds") + listCmd.Flags().BoolVar(&flagWithTags, "with-tags", false, "include tags") + listCmd.Flags().BoolVar(&flagWithCharts, "with-charts", false, "include charts") + listCmd.Flags().BoolVar(&flagWithBuilds, "with-builds", false, "include builds") } var listCmd = &cobra.Command{ @@ -43,10 +45,13 @@ var listCmd = &cobra.Command{ list = append(list, pterm.LeveledListItem{Level: 0, Text: key}) return value.Iterate(func(k string, v *config.Unit) error { list = append(list, pterm.LeveledListItem{Level: 1, Text: k}) - if flagCharts { + if flagWithTags && len(v.Tags) > 0 { + list = append(list, pterm.LeveledListItem{Level: 2, Text: "🔖: " + v.Tags.SortedString()}) + } + if flagWithCharts && len(v.Chart.String()) > 0 { list = append(list, pterm.LeveledListItem{Level: 2, Text: "📑: " + v.Chart.String()}) } - if flagBuilds { + if flagWithBuilds && len(v.Builds) > 0 { for name, build := range v.Builds { list = append(list, pterm.LeveledListItem{Level: 2, Text: "📦: " + name}) for _, dependency := range build.Dependencies { diff --git a/internal/config/tag.go b/internal/config/tag.go index 5493bd5..31d17bd 100644 --- a/internal/config/tag.go +++ b/internal/config/tag.go @@ -1,3 +1,7 @@ package config type Tag string + +func (t Tag) String() string { + return string(t) +} diff --git a/internal/config/tags.go b/internal/config/tags.go new file mode 100644 index 0000000..b5c8076 --- /dev/null +++ b/internal/config/tags.go @@ -0,0 +1,30 @@ +package config + +import ( + "slices" + "strings" +) + +type Tags []Tag + +func (t Tags) String() string { + return strings.Join(t.Strings(), ",") +} + +func (t Tags) SortedString() string { + return strings.Join(t.SortedStrings(), ",") +} + +func (t Tags) Strings() []string { + ret := make([]string, len(t)) + for i, tag := range t { + ret[i] = tag.String() + } + return ret +} + +func (t Tags) SortedStrings() []string { + ret := t.Strings() + slices.Sort(ret) + return ret +} diff --git a/internal/config/unit.go b/internal/config/unit.go index 36745b0..0c3d75c 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -17,7 +17,7 @@ import ( type Unit struct { Chart helm.Dependency `yaml:"chart,omitempty"` Kustomize string `yaml:"kustomize,omitempty"` - Tags []Tag `yaml:"tags,omitempty"` + Tags Tags `yaml:"tags,omitempty"` Builds map[string]Build `yaml:"builds,omitempty"` Values map[string]interface{} `yaml:"values,omitempty"` } From cdd2dc97188db011a57c0bff55822695696bec14 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Wed, 31 Jan 2024 15:32:17 +0100 Subject: [PATCH 38/63] feat: support oci on other commands --- internal/config/unit.go | 9 ++++++++- squadron.go | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/internal/config/unit.go b/internal/config/unit.go index 0c3d75c..f46f30f 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -87,10 +87,17 @@ func (u *Unit) Template(ctx context.Context, name, squadron, unit, namespace str Args(u.PostRendererArgs()...). Args("--values", "-"). Args(helmArgs...) + if strings.HasPrefix(u.Chart.Repository, "file://") { cmd.Args(path.Clean(strings.TrimPrefix(u.Chart.Repository, "file://"))) } else { - cmd.Args(u.Chart.Name, "--repo", u.Chart.Repository, "--version", u.Chart.Version) + cmd.Args(u.Chart.Name) + if u.Chart.Repository != "" { + cmd.Args("--repo", u.Chart.Repository) + } + if u.Chart.Version != "" { + cmd.Args("--version", u.Chart.Version) + } } if out, err := cmd.Run(ctx); err != nil { return nil, errors.Wrap(err, out) diff --git a/squadron.go b/squadron.go index 7ea1342..88b9d08 100644 --- a/squadron.go +++ b/squadron.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "os/exec" + "path" "slices" "strings" "sync" @@ -364,10 +365,17 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e "--dry-run", ) cmd.Stdin = bytes.NewReader(valueBytes) - if strings.Contains(v.Chart.Repository, "file://") { - cmd.Args = append(cmd.Args, "/"+strings.TrimPrefix(v.Chart.Repository, "file://")) + + if strings.HasPrefix(v.Chart.Repository, "file://") { + cmd.Args = append(cmd.Args, path.Clean(strings.TrimPrefix(v.Chart.Repository, "file://"))) } else { - cmd.Args = append(cmd.Args, v.Chart.Name, "--repo", v.Chart.Repository, "--version", v.Chart.Version) + cmd.Args = append(cmd.Args, v.Chart.Name) + if v.Chart.Repository != "" { + cmd.Args = append(cmd.Args, "--repo", v.Chart.Repository) + } + if v.Chart.Version != "" { + cmd.Args = append(cmd.Args, "--version", v.Chart.Version) + } } cmd.Args = append(cmd.Args, helmArgs...) out, err := cmd.CombinedOutput() @@ -551,8 +559,8 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version Args("--values", "-"). Args(helmArgs...) - if strings.Contains(v.Chart.Repository, "file://") { - cmd.Args(strings.TrimPrefix(v.Chart.Repository, "file://")) + if strings.HasPrefix(v.Chart.Repository, "file://") { + cmd.Args(path.Clean(strings.TrimPrefix(v.Chart.Repository, "file://"))) } else { cmd.Args(v.Chart.Name) if v.Chart.Repository != "" { From db791ae1469fa5458d84c455377fe7eabb39b2db Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 10:40:06 +0100 Subject: [PATCH 39/63] fix: parallel local dependencies update --- cmd/actions/diff.go | 4 ++ cmd/actions/template.go | 4 ++ cmd/actions/up.go | 4 ++ internal/config/unit.go | 17 -------- squadron.go | 54 +++++++++++++++++------- testdata/override/snapshop-template.yaml | 22 +++++----- testdata/simple/snapshop-template.yaml | 22 +++++----- testdata/tags/snapshop-template.yaml | 16 +++---- testdata/template/snapshop-template.yaml | 38 ++++++++--------- 9 files changed, 100 insertions(+), 81 deletions(-) diff --git a/cmd/actions/diff.go b/cmd/actions/diff.go index 6394edf..9b3435d 100644 --- a/cmd/actions/diff.go +++ b/cmd/actions/diff.go @@ -33,6 +33,10 @@ var diffCmd = &cobra.Command{ return err } + if err := sq.UpdateLocalDependencies(cmd.Context(), flagParallel); err != nil { + return err + } + return sq.Diff(cmd.Context(), helmArgs, flagParallel) }, } diff --git a/cmd/actions/template.go b/cmd/actions/template.go index cd5a3ed..b940049 100644 --- a/cmd/actions/template.go +++ b/cmd/actions/template.go @@ -37,6 +37,10 @@ var templateCmd = &cobra.Command{ return err } + if err := sq.UpdateLocalDependencies(cmd.Context(), flagParallel); err != nil { + return err + } + out, err := sq.Template(cmd.Context(), helmArgs, flagParallel) if err != nil { return err diff --git a/cmd/actions/up.go b/cmd/actions/up.go index 27c36ff..4ddaaaa 100644 --- a/cmd/actions/up.go +++ b/cmd/actions/up.go @@ -53,6 +53,10 @@ var upCmd = &cobra.Command{ } } + if err := sq.UpdateLocalDependencies(cmd.Context(), flagParallel); err != nil { + return err + } + username := "unknown" if value, err := util.NewCommand("git").Args("config", "user.name").Run(cmd.Context()); err == nil { username = strings.TrimSpace(value) diff --git a/internal/config/unit.go b/internal/config/unit.go index f46f30f..24005a1 100644 --- a/internal/config/unit.go +++ b/internal/config/unit.go @@ -106,23 +106,6 @@ func (u *Unit) Template(ctx context.Context, name, squadron, unit, namespace str return ret.Bytes(), nil } -func (u *Unit) DependencyUpdate(ctx context.Context) error { - // update local chart dependencies - // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql - if strings.HasPrefix(u.Chart.Repository, "file:///") { - pterm.Debug.Printfln("running helm dependency update for %s", u.Chart.Repository) - sh := util.NewHelmCommand(). - Cwd(strings.TrimPrefix(u.Chart.Repository, "file://")). - Args("dependency", "update", "--skip-refresh", "--debug") - if out, err := sh.Run(ctx); err != nil { - return errors.Wrap(err, out) - } else { - pterm.Debug.Println(out) - } - } - return nil -} - func (u *Unit) PostRendererArgs() []string { var ret []string if u.Kustomize != "" { diff --git a/squadron.go b/squadron.go index 88b9d08..4bb6e63 100644 --- a/squadron.go +++ b/squadron.go @@ -346,11 +346,6 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e return err } - // update local chart dependencies - if err := v.DependencyUpdate(ctx); err != nil { - return err - } - pterm.Debug.Printfln("running helm diff for: %s", k) manifest, err := exec.CommandContext(ctx, "helm", "get", "manifest", name, "--namespace", namespace).CombinedOutput() if err != nil && string(bytes.TrimSpace(manifest)) != errHelmReleaseNotFound { @@ -520,6 +515,45 @@ func (sq *Squadron) Rollback(ctx context.Context, revision string, helmArgs []st return wg.Wait() } +// UpdateLocalDependencies work around +// https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql +func (sq *Squadron) UpdateLocalDependencies(ctx context.Context, parallel int) error { + // collect unique entrie + var repositories map[string]struct{} + err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { + return value.Iterate(func(k string, v *config.Unit) error { + if strings.HasPrefix(v.Chart.Repository, "file:///") { + repositories[v.Chart.Repository] = struct{}{} + } + return nil + }) + }) + if err != nil { + return err + } + + wg, gctx := errgroup.WithContext(ctx) + wg.SetLimit(parallel) + + for repository := range repositories { + repository := repository + wg.Go(func() error { + pterm.Debug.Printfln("running helm dependency update for %s", repository) + if out, err := util.NewHelmCommand(). + Cwd(path.Clean(strings.TrimPrefix(repository, "file://"))). + Args("dependency", "update", "--skip-refresh", "--debug"). + Run(gctx); err != nil { + return errors.Wrap(err, out) + } else { + pterm.Debug.Println(out) + } + return nil + }) + } + + return wg.Wait() +} + func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version, commit, branch string, parallel int) error { description := fmt.Sprintf("\nDeployed-By: %s\nManaged-By: Squadron %s\nGit-Commit: %s\nGit-Branch: %s", username, version, commit, branch) @@ -539,11 +573,6 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version return err } - // update local chart dependencies - if err := v.DependencyUpdate(ctx); err != nil { - return err - } - // install chart pterm.Debug.Printfln("running helm upgrade for %s", name) cmd := util.NewHelmCommand(). @@ -606,11 +635,6 @@ func (sq *Squadron) Template(ctx context.Context, helmArgs []string, parallel in return err } - // update local chart dependencies - if err := v.DependencyUpdate(ctx); err != nil { - return err - } - pterm.Debug.Printfln("running helm template for chart: %s", name) out, err := v.Template(gctx, name, key, k, namespace, sq.c.Global, helmArgs) if err != nil { diff --git a/testdata/override/snapshop-template.yaml b/testdata/override/snapshop-template.yaml index 1791dda..f8ebc47 100644 --- a/testdata/override/snapshop-template.yaml +++ b/testdata/override/snapshop-template.yaml @@ -3,9 +3,9 @@ apiVersion: v1 kind: Service metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -13,7 +13,7 @@ metadata: spec: type: ClusterIP selector: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend ports: - name: http @@ -23,9 +23,9 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -33,16 +33,16 @@ metadata: spec: selector: matchLabels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend template: metadata: labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend spec: containers: - - name: frontend + - name: storefinder-frontend image: 'docker.mycompany.com/mycomapny/frontend:nightly' ports: - name: http @@ -53,9 +53,9 @@ spec: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -72,7 +72,7 @@ spec: path: / backend: service: - name: frontend + name: storefinder-frontend port: name: http number: 80 diff --git a/testdata/simple/snapshop-template.yaml b/testdata/simple/snapshop-template.yaml index d8dd981..1766fa0 100644 --- a/testdata/simple/snapshop-template.yaml +++ b/testdata/simple/snapshop-template.yaml @@ -3,9 +3,9 @@ apiVersion: v1 kind: Service metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -13,7 +13,7 @@ metadata: spec: type: ClusterIP selector: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend ports: - name: http @@ -23,9 +23,9 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -33,16 +33,16 @@ metadata: spec: selector: matchLabels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend template: metadata: labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend spec: containers: - - name: frontend + - name: storefinder-frontend image: 'nginx:latest' ports: - name: http @@ -53,9 +53,9 @@ spec: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -72,7 +72,7 @@ spec: path: / backend: service: - name: frontend + name: storefinder-frontend port: name: http number: 80 diff --git a/testdata/tags/snapshop-template.yaml b/testdata/tags/snapshop-template.yaml index 3b22b7f..27fa897 100644 --- a/testdata/tags/snapshop-template.yaml +++ b/testdata/tags/snapshop-template.yaml @@ -3,9 +3,9 @@ apiVersion: v1 kind: Service metadata: - name: backend + name: checkout-backend labels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: checkout-backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'backend-0.0.1' @@ -13,7 +13,7 @@ metadata: spec: type: ClusterIP selector: - app.kubernetes.io/name: backend + app.kubernetes.io/name: checkout-backend app.kubernetes.io/component: backend ports: - name: http @@ -23,9 +23,9 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - name: backend + name: checkout-backend labels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: checkout-backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'backend-0.0.1' @@ -33,16 +33,16 @@ metadata: spec: selector: matchLabels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: checkout-backend app.kubernetes.io/component: backend template: metadata: labels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: checkout-backend app.kubernetes.io/component: backend spec: containers: - - name: backend + - name: checkout-backend image: 'nginx:latest' ports: - name: http diff --git a/testdata/template/snapshop-template.yaml b/testdata/template/snapshop-template.yaml index 44d6b21..d64469b 100644 --- a/testdata/template/snapshop-template.yaml +++ b/testdata/template/snapshop-template.yaml @@ -3,9 +3,9 @@ apiVersion: v1 kind: Service metadata: - name: backend + name: storefinder-backend labels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: storefinder-backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'backend-0.0.1' @@ -13,7 +13,7 @@ metadata: spec: type: ClusterIP selector: - app.kubernetes.io/name: backend + app.kubernetes.io/name: storefinder-backend app.kubernetes.io/component: backend ports: - name: http @@ -23,9 +23,9 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - name: backend + name: storefinder-backend labels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: storefinder-backend app.kubernetes.io/component: backend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'backend-0.0.1' @@ -33,16 +33,16 @@ metadata: spec: selector: matchLabels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: storefinder-backend app.kubernetes.io/component: backend template: metadata: labels: - app.kubernetes.io/name: backend + app.kubernetes.io/name: storefinder-backend app.kubernetes.io/component: backend spec: containers: - - name: backend + - name: storefinder-backend image: 'docker.mycompany.com/mycomapny/frontend-admin:latest' ports: - name: http @@ -53,9 +53,9 @@ spec: apiVersion: v1 kind: Service metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -63,7 +63,7 @@ metadata: spec: type: ClusterIP selector: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend ports: - name: http @@ -73,9 +73,9 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -83,16 +83,16 @@ metadata: spec: selector: matchLabels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend template: metadata: labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend spec: containers: - - name: frontend + - name: storefinder-frontend image: 'docker.mycompany.com/mycomapny/frontend:latest' ports: - name: http @@ -103,9 +103,9 @@ spec: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: frontend + name: storefinder-frontend labels: - app.kubernetes.io/name: frontend + app.kubernetes.io/name: storefinder-frontend app.kubernetes.io/component: frontend app.kubernetes.io/managed-by: Helm helm.sh/chart: 'frontend-0.0.1' @@ -122,7 +122,7 @@ spec: path: / backend: service: - name: frontend + name: storefinder-frontend port: name: http number: 80 From df1d8a83f96f56ed3cd443d26789a17483957bfa Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 10:44:17 +0100 Subject: [PATCH 40/63] chore: change release --- .github/workflows/release.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 389f426..907f77e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,17 +18,21 @@ jobs: with: fetch-depth: 0 - - run: git fetch --force --tags - - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: check-latest: true - go-version-file: 'go.mod' + go-version-file: go.mod + + - id: app_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.TOKEN_APP_ID }} + private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }} + installation_id: ${{ secrets.TOKEN_APP_INSTALLATION_ID }} - uses: goreleaser/goreleaser-action@v5 with: - distribution: goreleaser version: latest - args: release --rm-dist + args: release --clean env: - GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ steps.app_token.outputs.token }} From 3495437b4340999a09961c620d35eaefe1e65d87 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 10:44:29 +0100 Subject: [PATCH 41/63] feat: update deps --- go.mod | 23 +++++++++++------------ go.sum | 56 ++++++++++++++++++++++++-------------------------------- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 1ee5827..dcebd27 100644 --- a/go.mod +++ b/go.mod @@ -7,16 +7,15 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/miracl/conflate v1.2.1 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.74 + github.com/pterm/pterm v0.12.78 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - golang.org/x/sync v0.5.0 + golang.org/x/sync v0.6.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.28.4 - k8s.io/apimachinery v0.28.4 + k8s.io/api v0.29.1 ) require ( @@ -28,7 +27,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/gookit/color v1.5.4 // indirect @@ -50,16 +49,16 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + k8s.io/apimachinery v0.29.1 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) replace github.com/miracl/conflate v1.2.1 => github.com/runz0rd/conflate v1.2.2-0.20210920145208-fa48576ef06d diff --git a/go.sum b/go.sum index a5c7cc9..d160f34 100644 --- a/go.sum +++ b/go.sum @@ -35,13 +35,13 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -92,10 +92,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.71 h1:KcEJ98EiVCbzDkFbktJ2gMlr4pn8IzyGb9bwK6ffkuA= -github.com/pterm/pterm v0.12.71/go.mod h1:SUAcoZjRt+yjPWlWba+/Fd8zJJ2lSXBQWf0Z0HbFiIQ= -github.com/pterm/pterm v0.12.74 h1:fPsds9KisCyJh4NyY6bv8QJt3FLHceb5DxI6W0An9cc= -github.com/pterm/pterm v0.12.74/go.mod h1:+M33aZWQVpmLmLbvjykyGZ4gAfeebznRo8JMbabaxQU= +github.com/pterm/pterm v0.12.78 h1:QTWKaIAa4B32GKwqVXtu9m1DUMgWw3VRljMkMevX+b8= +github.com/pterm/pterm v0.12.78/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -159,15 +157,15 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -181,26 +179,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -229,17 +221,17 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= +k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= +k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= +k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 1ca4d77a9f293a444cb59a248d96a15d065c45fe Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 10:50:55 +0100 Subject: [PATCH 42/63] chore: remove field --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 907f77e..297e3e0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,6 @@ jobs: with: app_id: ${{ secrets.TOKEN_APP_ID }} private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }} - installation_id: ${{ secrets.TOKEN_APP_INSTALLATION_ID }} - uses: goreleaser/goreleaser-action@v5 with: From d1d5b2000d8555f3b0effe781472e2d1dea08fc3 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 11:05:31 +0100 Subject: [PATCH 43/63] fix: nil pointer --- squadron.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/squadron.go b/squadron.go index 4bb6e63..3822698 100644 --- a/squadron.go +++ b/squadron.go @@ -519,7 +519,7 @@ func (sq *Squadron) Rollback(ctx context.Context, revision string, helmArgs []st // https://stackoverflow.com/questions/59210148/error-found-in-chart-yaml-but-missing-in-charts-directory-mysql func (sq *Squadron) UpdateLocalDependencies(ctx context.Context, parallel int) error { // collect unique entrie - var repositories map[string]struct{} + repositories := map[string]struct{}{} err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error { return value.Iterate(func(k string, v *config.Unit) error { if strings.HasPrefix(v.Chart.Repository, "file:///") { From ec3024af35f1220ad21467f65becce94e97ba9d8 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 14:12:08 +0100 Subject: [PATCH 44/63] feat: replace OP_MODE --- internal/template/onepassword.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index a7e9f08..8224a26 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -24,7 +24,7 @@ var ( var ErrOnePasswordNotSignedIn = errors.New("not signed in") -func onePasswordCIGet(client connect.Client, vaultUUID, itemUUID string) (map[string]string, error) { +func onePasswordConnectGet(client connect.Client, vaultUUID, itemUUID string) (map[string]string, error) { var item *onepassword.Item if onePasswordUUID.Match([]byte(itemUUID)) { if v, err := client.GetItem(itemUUID, vaultUUID); err != nil { @@ -115,13 +115,17 @@ func onePasswordSignIn(ctx context.Context, account string) error { return nil } +func isConnect() bool { + return os.Getenv("OP_CONNECT_HOST") != "" && os.Getenv("OP_CONNECT_TOKEN") != "" +} + func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { if onePasswordCache == nil { onePasswordCache = map[string]map[string]string{} } return func(account, vaultUUID, itemUUID, field string) (string, error) { // validate command - if mode := os.Getenv("OP_MODE"); mode == "ci" { + if isConnect() { // do nothing } else if _, err := exec.LookPath("op"); err != nil { fmt.Println("Your templates includes a call to 1Password, please install it:") @@ -150,11 +154,11 @@ func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing b // create cache key cacheKey := strings.Join([]string{account, vaultUUID, itemUUID}, "#") - if mode := os.Getenv("OP_MODE"); mode == "ci" { + if isConnect() { if _, ok := onePasswordCache[cacheKey]; !ok { if client, err := connect.NewClientFromEnvironment(); err != nil { return "", err - } else if res, err := onePasswordCIGet(client, vaultUUID, itemUUID); err != nil { + } else if res, err := onePasswordConnectGet(client, vaultUUID, itemUUID); err != nil { return "", err } else { onePasswordCache[cacheKey] = res From ce9e507e0ba6d448d4fd4356ceb868ecfec3d136 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 14:38:07 +0100 Subject: [PATCH 45/63] feat: check for OP_SERVICE_ACCOUNT_TOKEN --- internal/template/onepassword.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index 8224a26..36fa2ab 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -119,13 +119,17 @@ func isConnect() bool { return os.Getenv("OP_CONNECT_HOST") != "" && os.Getenv("OP_CONNECT_TOKEN") != "" } +func isServiceAccount() bool { + return os.Getenv("OP_SERVICE_ACCOUNT_TOKEN") != "" +} + func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { if onePasswordCache == nil { onePasswordCache = map[string]map[string]string{} } return func(account, vaultUUID, itemUUID, field string) (string, error) { // validate command - if isConnect() { + if isConnect() || isServiceAccount() { // do nothing } else if _, err := exec.LookPath("op"); err != nil { fmt.Println("Your templates includes a call to 1Password, please install it:") From 7e5d5df8b47f0a5a0597a1c8f6da947ec2f89759 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 5 Feb 2024 15:13:11 +0100 Subject: [PATCH 46/63] fix: pass vaultUUID --- internal/template/onepassword.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index 36fa2ab..d088033 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -60,12 +60,12 @@ func onePasswordGet(ctx context.Context, account, vaultUUID, itemUUID string) (m Value interface{} `json:"value"` } `json:"fields"` } - if res, err := exec.CommandContext(ctx, "op", "item", "get", itemUUID, "--account", account, "--format", "json").CombinedOutput(); err != nil && strings.Contains(string(res), "You are not currently signed in") { + if res, err := exec.CommandContext(ctx, "op", "item", "get", itemUUID, "--vault", vaultUUID, "--account", account, "--format", "json").CombinedOutput(); err != nil && strings.Contains(string(res), "You are not currently signed in") { return nil, ErrOnePasswordNotSignedIn } else if err != nil { - return nil, err + return nil, errors.Wrap(err, string(res)) } else if err := json.Unmarshal(res, &v); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal secret") } else if v.Vault.ID != vaultUUID { return nil, errors.Errorf("wrong vault UUID %s for item %s", vaultUUID, itemUUID) } else { From a7b1f4f5e808067f454a82e4cb9c35db4c8f4cb7 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Mar 2024 16:59:58 +0100 Subject: [PATCH 47/63] feat: set perm --- cmd/actions/postrenderer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/actions/postrenderer.go b/cmd/actions/postrenderer.go index 1b66f3e..82aa536 100644 --- a/cmd/actions/postrenderer.go +++ b/cmd/actions/postrenderer.go @@ -26,7 +26,7 @@ var postRendererCmd = &cobra.Command{ return err } - err = os.WriteFile(path.Join(args[0], ".chart.yaml"), r, 0644) + err = os.WriteFile(path.Join(args[0], ".chart.yaml"), r, 0600) if err != nil { return err } From 2fefe6010a70aff9f0bc18959b43cb94b1fa79e1 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Mar 2024 17:00:11 +0100 Subject: [PATCH 48/63] fix: add post render args --- squadron.go | 1 + 1 file changed, 1 insertion(+) diff --git a/squadron.go b/squadron.go index 3822698..9dc8431 100644 --- a/squadron.go +++ b/squadron.go @@ -359,6 +359,7 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e "--values", "-", "--dry-run", ) + cmd.Args = append(cmd.Args, v.PostRendererArgs()...) cmd.Stdin = bytes.NewReader(valueBytes) if strings.HasPrefix(v.Chart.Repository, "file://") { From 7e0c91d9e9d6cf98ecd6a5edd7a7690275576a98 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Mar 2024 17:00:38 +0100 Subject: [PATCH 49/63] chore: update linter --- .golangci.yml | 17 ++++++++++++++--- internal/util/cmd.go | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 58a2484..f9f768e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,16 @@ run: timeout: 5m + skip-dirs: + - tmp + +linters-settings: + gocritic: + disabled-checks: + - ifElseChain + - commentFormatting + gosec: + excludes: + - G204 linters: enable: @@ -17,12 +28,12 @@ linters: - forcetypeassert # finds forced type assertions [fast: true, auto-fix: false] #- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false] #- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false] - #- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false] + - gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false] - goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. [fast: true, auto-fix: true] #- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false] - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false] - goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false] - #- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false] + - gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false] - grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false] - importas # Enforces consistent import aliases [fast: false, auto-fix: false] - maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false] @@ -31,7 +42,7 @@ linters: - nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false] #- nestif # Reports deeply nested if statements [fast: true, auto-fix: false] - nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false] - #- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false] + - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false] - noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false] - nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false] #- nonamedreturns # Reports all named returns [fast: false, auto-fix: false] diff --git a/internal/util/cmd.go b/internal/util/cmd.go index e3f8a61..c28756a 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -98,7 +98,7 @@ func (c *Cmd) Stderr(w io.Writer) *Cmd { } func (c *Cmd) Run(ctx context.Context) (string, error) { - cmd := exec.CommandContext(ctx, c.command[0], c.command[1:]...) //nolint:gosec + cmd := exec.CommandContext(ctx, c.command[0], c.command[1:]...) cmd.Env = append(os.Environ(), c.env...) if c.cwd != "" { cmd.Dir = c.cwd From 85faef41ba048fa8f866f4b294b725286466a3c7 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Mar 2024 17:00:51 +0100 Subject: [PATCH 50/63] chore: update setup --- .github/dependabot.yml | 17 ++++------ .github/workflows/pr.yml | 39 ++++++++++++++++++++++ .github/workflows/{release.yml => tag.yml} | 11 +++--- .github/workflows/test.yml | 32 ------------------ .goreleaser.yml | 33 ++++++++++-------- Makefile | 2 -- README.md | 5 +-- 7 files changed, 73 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/pr.yml rename .github/workflows/{release.yml => tag.yml} (82%) delete mode 100644 .github/workflows/test.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ba1f3b..c9d1dc6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,15 +1,10 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: github-actions + directory: '/' schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/" + interval: weekly + - package-ecosystem: gomod + directory: '/' schedule: - interval: "weekly" + interval: weekly diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..7d1adeb --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,39 @@ +name: checks + +on: + push: + branches: [ main ] + pull_request: + merge_group: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + - uses: gotesttools/gotestfmt-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: golangci/golangci-lint-action@v4 + with: + version: latest + + - name: Run tests + run: make test + env: + SHELL: "/bin/zsh" + + - uses: coverallsapp/github-action@v2 + with: + file: coverage.out diff --git a/.github/workflows/release.yml b/.github/workflows/tag.yml similarity index 82% rename from .github/workflows/release.yml rename to .github/workflows/tag.yml index 297e3e0..f365d53 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/tag.yml @@ -6,21 +6,20 @@ on: - v*.*.* workflow_dispatch: -env: - GOFLAGS: -mod=readonly - GOPROXY: https://proxy.golang.org +permissions: + contents: write jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 + + - name: Unshallow + run: git fetch --prune --unshallow - uses: actions/setup-go@v5 with: - check-latest: true go-version-file: go.mod - id: app_token diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 5e379a0..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: checks - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - merge_group: - branches: [ main ] - workflow_dispatch: - -env: - GOFLAGS: -mod=readonly - GOPROXY: https://proxy.golang.org - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-go@v4 - with: - check-latest: true - go-version-file: 'go.mod' - - - uses: golangci/golangci-lint-action@v3 - - - name: Run tests - run: go test -v ./... - env: - SHELL: "/bin/zsh" diff --git a/.goreleaser.yml b/.goreleaser.yml index d68d19e..6699fc8 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,10 +1,13 @@ -# .goreleaser.yml -# Build customization +project_name: squadron + +release: + github: + owner: foomo + name: squadron + prerelease: auto + builds: - binary: squadron - main: ./cmd/main.go - env: - - CGO_ENABLED=0 goos: - windows - darwin @@ -13,29 +16,33 @@ builds: - amd64 - arm64 goarm: - - 7 + - '7' + env: + - CGO_ENABLED=0 + main: ./cmd/main.go flags: - -trimpath - ldflags: - - -s -w -X github.com/foomo/squadron/cmd/actions.version={{.Version}} - -release: - prerelease: auto + ldflags: -s -w -X github.com/foomo/squadron/cmd/actions.version={{.Version}} archives: - format: tar.gz format_overrides: - goos: windows format: zip + files: + - LICENSE + - README.md changelog: use: github-native brews: # Repository to push the tap to. - - tap: + - repository: owner: foomo - name: homebrew-squadron + name: homebrew-tap caveats: "squadron -h" homepage: "https://github.com/foomo/squadron" description: "CLI utility manage infrastructure as code with helm" + test: | + system "#{bin}/squadron --version" diff --git a/Makefile b/Makefile index 073a3e6..29d79b4 100644 --- a/Makefile +++ b/Makefile @@ -18,8 +18,6 @@ ## === Tasks === -## === Tasks === - .PHONY: doc ## Run tests doc: diff --git a/README.md b/README.md index b3c7e82..bb1e279 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # Squadron +[![Build Status](https://github.com/foomo/squadron/actions/workflows/test.yml/badge.svg?branch=main&event=push)](https://github.com/foomo/squadron/actions/workflows/test.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/foomo/squadron)](https://goreportcard.com/report/github.com/foomo/squadron) -[![godoc](https://godoc.org/github.com/foomo/squadron?status.svg)](https://godoc.org/github.com/foomo/squadron) -[![goreleaser](https://github.com/foomo/squadron/workflows/goreleaser/badge.svg)](https://github.com/foomo/squadron/actions) +[![Coverage Status](https://coveralls.io/repos/github/foomo/squadron/badge.svg?branch=main&)](https://coveralls.io/github/foomo/squadron?branch=main) +[![GoDoc](https://godoc.org/github.com/foomo/squadron?status.svg)](https://godoc.org/github.com/foomo/squadron) Application for managing kubernetes microservice environments. From b845f239ed60df392edc6a4df9c2079e6f0aec6d Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Mon, 25 Mar 2024 17:01:30 +0100 Subject: [PATCH 51/63] feat: update deps --- go.mod | 8 ++++---- go.sum | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index dcebd27..9eeb2b9 100644 --- a/go.mod +++ b/go.mod @@ -7,15 +7,15 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/miracl/conflate v1.2.1 github.com/pkg/errors v0.9.1 - github.com/pterm/pterm v0.12.78 + github.com/pterm/pterm v0.12.79 github.com/sergi/go-diff v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 golang.org/x/sync v0.6.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.29.1 + k8s.io/api v0.29.3 ) require ( @@ -54,7 +54,7 @@ require ( golang.org/x/term v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/apimachinery v0.29.1 // indirect + k8s.io/apimachinery v0.29.3 // indirect k8s.io/klog/v2 v2.110.1 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/go.sum b/go.sum index d160f34..f1d8102 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.78 h1:QTWKaIAa4B32GKwqVXtu9m1DUMgWw3VRljMkMevX+b8= -github.com/pterm/pterm v0.12.78/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= +github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= +github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -112,14 +112,14 @@ github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyh github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= @@ -221,10 +221,10 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= -k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= -k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= -k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= From 3921c79823c8d3bd26b9534bf4134326d839dcbc Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 23 Apr 2024 09:41:39 +0200 Subject: [PATCH 52/63] feat: wrap errors --- cmd/actions/build.go | 11 ++++++----- cmd/actions/config.go | 7 ++++--- cmd/actions/diff.go | 9 +++++---- cmd/actions/down.go | 5 +++-- cmd/actions/list.go | 5 +++-- cmd/actions/push.go | 9 +++++---- cmd/actions/rollback.go | 5 +++-- cmd/actions/status.go | 5 +++-- cmd/actions/template.go | 11 ++++++----- cmd/actions/up.go | 11 ++++++----- 10 files changed, 44 insertions(+), 34 deletions(-) diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 6e8d790..53f68f2 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -2,6 +2,7 @@ package actions import ( "github.com/foomo/squadron" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -22,25 +23,25 @@ var buildCmd = &cobra.Command{ sq := squadron.New(cwd, "", flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } if err := sq.RenderConfig(cmd.Context()); err != nil { - return err + return errors.Wrap(err, "failed to render config") } if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to build units") } if flagPush { if err := sq.Push(cmd.Context(), flagPushArgs, flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to push units") } } diff --git a/cmd/actions/config.go b/cmd/actions/config.go index bebf3dd..7abb841 100644 --- a/cmd/actions/config.go +++ b/cmd/actions/config.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/squadron" "github.com/foomo/squadron/internal/util" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -22,17 +23,17 @@ var configCmd = &cobra.Command{ sq := squadron.New(cwd, "", flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } if !flagNoRender { if err := sq.RenderConfig(cmd.Context()); err != nil { - return err + return errors.Wrap(err, "failed to render config") } } diff --git a/cmd/actions/diff.go b/cmd/actions/diff.go index 9b3435d..96c513d 100644 --- a/cmd/actions/diff.go +++ b/cmd/actions/diff.go @@ -2,6 +2,7 @@ package actions import ( "github.com/foomo/squadron" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -19,22 +20,22 @@ var diffCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } if err := sq.RenderConfig(cmd.Context()); err != nil { - return err + return errors.Wrap(err, "failed to render config") } if err := sq.UpdateLocalDependencies(cmd.Context(), flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to update dependencies") } return sq.Diff(cmd.Context(), helmArgs, flagParallel) diff --git a/cmd/actions/down.go b/cmd/actions/down.go index 2ab1813..651931d 100644 --- a/cmd/actions/down.go +++ b/cmd/actions/down.go @@ -1,6 +1,7 @@ package actions import ( + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/foomo/squadron" @@ -21,14 +22,14 @@ var downCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } return sq.Down(cmd.Context(), helmArgs, flagParallel) diff --git a/cmd/actions/list.go b/cmd/actions/list.go index e27cfe8..5434fba 100644 --- a/cmd/actions/list.go +++ b/cmd/actions/list.go @@ -3,6 +3,7 @@ package actions import ( "github.com/foomo/squadron" "github.com/foomo/squadron/internal/config" + "github.com/pkg/errors" "github.com/pterm/pterm" "github.com/pterm/pterm/putils" "github.com/spf13/cobra" @@ -30,12 +31,12 @@ var listCmd = &cobra.Command{ sq := squadron.New(cwd, "", flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } var list pterm.LeveledList diff --git a/cmd/actions/push.go b/cmd/actions/push.go index 41e48f8..6ad58e7 100644 --- a/cmd/actions/push.go +++ b/cmd/actions/push.go @@ -2,6 +2,7 @@ package actions import ( "github.com/foomo/squadron" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -22,21 +23,21 @@ var pushCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } if err := sq.RenderConfig(cmd.Context()); err != nil { - return err + return errors.Wrap(err, "failed to render config") } if flagBuild { if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to build units") } } diff --git a/cmd/actions/rollback.go b/cmd/actions/rollback.go index 81bf8f4..70d7c15 100644 --- a/cmd/actions/rollback.go +++ b/cmd/actions/rollback.go @@ -1,6 +1,7 @@ package actions import ( + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/foomo/squadron" @@ -21,14 +22,14 @@ var rollbackCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } return sq.Rollback(cmd.Context(), flagRevision, helmArgs, flagParallel) diff --git a/cmd/actions/status.go b/cmd/actions/status.go index a3314e6..d05809a 100644 --- a/cmd/actions/status.go +++ b/cmd/actions/status.go @@ -1,6 +1,7 @@ package actions import ( + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/foomo/squadron" @@ -20,14 +21,14 @@ var statusCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } return sq.Status(cmd.Context(), helmArgs, flagParallel) diff --git a/cmd/actions/template.go b/cmd/actions/template.go index b940049..b0c0f28 100644 --- a/cmd/actions/template.go +++ b/cmd/actions/template.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/squadron" "github.com/foomo/squadron/internal/util" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -23,27 +24,27 @@ var templateCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } if err := sq.RenderConfig(cmd.Context()); err != nil { - return err + return errors.Wrap(err, "failed to render config") } if err := sq.UpdateLocalDependencies(cmd.Context(), flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to update dependencies") } out, err := sq.Template(cmd.Context(), helmArgs, flagParallel) if err != nil { - return err + return errors.Wrap(err, "failed to render template") } fmt.Print(util.Highlight(out)) diff --git a/cmd/actions/up.go b/cmd/actions/up.go index 4ddaaaa..29341b5 100644 --- a/cmd/actions/up.go +++ b/cmd/actions/up.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/squadron" "github.com/foomo/squadron/internal/util" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -27,29 +28,29 @@ var upCmd = &cobra.Command{ sq := squadron.New(cwd, flagNamespace, flagFiles) if err := sq.MergeConfigFiles(); err != nil { - return err + return errors.Wrap(err, "failed to merge config files") } args, helmArgs := parseExtraArgs(args) squadronName, unitNames := parseSquadronAndUnitNames(args) if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil { - return err + return errors.Wrap(err, "failed to filter config") } if err := sq.RenderConfig(cmd.Context()); err != nil { - return err + return errors.Wrap(err, "failed to render config") } if flagBuild { if err := sq.Build(cmd.Context(), flagBuildArgs, flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to build units") } } if flagPush { if err := sq.Push(cmd.Context(), flagPushArgs, flagParallel); err != nil { - return err + return errors.Wrap(err, "failed to push units") } } From 62d5f402e68ad49f510296dedfae9e13491871f1 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 23 Apr 2024 09:41:57 +0200 Subject: [PATCH 53/63] feat: check for op signin only once --- internal/template/onepassword.go | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index d088033..e830282 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -124,25 +124,31 @@ func isServiceAccount() bool { } func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { - if onePasswordCache == nil { - onePasswordCache = map[string]map[string]string{} + init := func(account string) error { + if onePasswordCache == nil { + onePasswordCache = map[string]map[string]string{} + if _, err := exec.LookPath("op"); err != nil { + fmt.Println("Your templates includes a call to 1Password, please install it:") + fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") + return errors.Wrap(err, "failed to lookup op") + } else if _, err := exec.CommandContext(ctx, "op", "account", "get", "--account", account).CombinedOutput(); err == nil { + // do nothing + } else if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { + if err := onePasswordSignIn(ctx, account); err != nil { + return errors.Wrap(err, "failed to sign in") + } + } + } + return nil } + return func(account, vaultUUID, itemUUID, field string) (string, error) { // validate command if isConnect() || isServiceAccount() { // do nothing - } else if _, err := exec.LookPath("op"); err != nil { - fmt.Println("Your templates includes a call to 1Password, please install it:") - fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") - return "", errors.Wrap(err, "failed to lookup op") - } else if _, err := exec.CommandContext(ctx, "op", "account", "get", "--account", account).CombinedOutput(); err == nil { - // do nothing - } else if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { - if err := onePasswordSignIn(ctx, account); err != nil { - return "", errors.Wrap(err, "failed to sign in") - } + } else if err := init(account); err != nil { + return "", err } - // render uuid & field params if value, err := onePasswordRender("op", itemUUID, templateVars, errorOnMissing); err != nil { return "", err From f0e6abedf3a6c72bb0b89b2de8e68adf39030a5d Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 23 Apr 2024 09:44:26 +0200 Subject: [PATCH 54/63] feat: bump deps --- go.mod | 20 +++++++++++--------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 9eeb2b9..efa82c1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/foomo/squadron -go 1.21 +go 1.22.0 + +toolchain go1.22.2 require ( github.com/1Password/connect-sdk-go v1.5.3 @@ -12,10 +14,10 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.9.0 - golang.org/x/sync v0.6.0 + golang.org/x/sync v0.7.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.29.3 + k8s.io/api v0.30.0 ) require ( @@ -27,7 +29,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/gookit/color v1.5.4 // indirect @@ -49,13 +51,13 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/apimachinery v0.29.3 // indirect - k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/apimachinery v0.30.0 // indirect + k8s.io/klog/v2 v2.120.1 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index f1d8102..476c7c7 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -157,15 +157,15 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -179,15 +179,15 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -221,12 +221,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= -k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= -k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= -k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA= +k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE= +k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA= +k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= From aa6a5bd64a60b1dec9ed4bad38a59968fca8ca94 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 23 Apr 2024 14:04:53 +0200 Subject: [PATCH 55/63] feat: switch to warning --- internal/template/onepassword.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index e830282..7823281 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -15,6 +15,7 @@ import ( "github.com/1Password/connect-sdk-go/connect" "github.com/1Password/connect-sdk-go/onepassword" "github.com/pkg/errors" + "github.com/pterm/pterm" ) var ( @@ -128,8 +129,8 @@ func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing b if onePasswordCache == nil { onePasswordCache = map[string]map[string]string{} if _, err := exec.LookPath("op"); err != nil { - fmt.Println("Your templates includes a call to 1Password, please install it:") - fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") + pterm.Warning.Println("Your templates includes a call to 1Password, please install it:") + pterm.Warning.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") return errors.Wrap(err, "failed to lookup op") } else if _, err := exec.CommandContext(ctx, "op", "account", "get", "--account", account).CombinedOutput(); err == nil { // do nothing From 489d6ba708e33b97a802f5675cd8fe6fa821ecc3 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Apr 2024 18:53:03 +0200 Subject: [PATCH 56/63] feat: add to string --- internal/util/cmd.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/util/cmd.go b/internal/util/cmd.go index c28756a..383be7a 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -97,6 +97,15 @@ func (c *Cmd) Stderr(w io.Writer) *Cmd { return c } +func (c *Cmd) String() string { + cmd := exec.Command(c.command[0], c.command[1:]...) + cmd.Env = append(os.Environ(), c.env...) + if c.cwd != "" { + cmd.Dir = c.cwd + } + return cmd.String() +} + func (c *Cmd) Run(ctx context.Context) (string, error) { cmd := exec.CommandContext(ctx, c.command[0], c.command[1:]...) cmd.Env = append(os.Environ(), c.env...) From 75a04bdd54a940828fc8b606da2e22b30ec6fd38 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Apr 2024 18:53:20 +0200 Subject: [PATCH 57/63] feat: switch to StringArray --- cmd/actions/build.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 53f68f2..0fab1ab 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -9,9 +9,9 @@ import ( func init() { buildCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes built squadron units to the registry") buildCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - buildCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") - buildCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") - buildCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") + buildCmd.Flags().StringArrayVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") + buildCmd.Flags().StringArrayVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") + buildCmd.Flags().StringArrayVar(&flagPushArgs, "push-args", nil, "additional docker push args") } var buildCmd = &cobra.Command{ From 1e6ce0b613facaec2ee666528c1157c4fc2a2d9b Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Apr 2024 18:53:35 +0200 Subject: [PATCH 58/63] feat: allow build arg override --- internal/config/build.go | 75 +++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/internal/config/build.go b/internal/config/build.go index bec27b9..7d552ef 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -3,6 +3,8 @@ package config import ( "context" "fmt" + "slices" + "strings" "github.com/foomo/squadron/internal/util" "github.com/pterm/pterm" @@ -71,37 +73,62 @@ type Build struct { // ------------------------------------------------------------------------------------------------ func (b *Build) Build(ctx context.Context, args []string) (string, error) { + argOverride := func(name string, vs string, args []string) (string, string) { + if slices.ContainsFunc(args, func(s string) bool { + return strings.HasPrefix(s, name) + }) { + return "", "" + } + return name, vs + } + boolArgOverride := func(name string, vs bool, args []string) (string, bool) { + if slices.ContainsFunc(args, func(s string) bool { + return strings.HasPrefix(s, name) + }) { + return "", false + } + return name, vs + } + listArgOverride := func(name string, vs, args []string) (string, []string) { + if slices.ContainsFunc(args, func(s string) bool { + return strings.HasPrefix(s, name) + }) { + return "", nil + } + return name, vs + } + pterm.Debug.Printfln("running docker build for %q", b.Context) return util.NewDockerCommand().Build(b.Context). - ListArg("--add-host", b.AddHost). - ListArg("--allow", b.Allow). - ListArg("--attest", b.Attest). - ListArg("--build-arg", b.BuildArg). - ListArg("--build-contet", b.BuildContext). - Arg("--builder", b.Builder). - Arg("--cache-from", b.CacheFrom). - Arg("--cache-to", b.CacheTo). - Arg("--file", b.File). - Arg("--iidfile", b.IIDFile). - ListArg("--label", b.Label). - BoolArg("--load", b.Load). - Arg("--metadata-file", b.MetadataFile). - Arg("--network", b.Network). - BoolArg("--no-cache", b.NoCache). - ListArg("--noe-cache-filter", b.NoCacheFilter). - Arg("--output", b.Output). - Arg("--platform", b.Platform). + ListArg(listArgOverride("--add-host", b.AddHost, args)). + ListArg(listArgOverride("--allow", b.Allow, args)). + ListArg(listArgOverride("--attest", b.Attest, args)). + ListArg(listArgOverride("--build-arg", b.BuildArg, args)). + ListArg(listArgOverride("--build-contet", b.BuildContext, args)). + Arg(argOverride("--builder", b.Builder, args)). + Arg(argOverride("--cache-from", b.CacheFrom, args)). + Arg(argOverride("--cache-to", b.CacheTo, args)). + Arg(argOverride("--file", b.File, args)). + Arg(argOverride("--iidfile", b.IIDFile, args)). + ListArg(listArgOverride("--label", b.Label, args)). + BoolArg(boolArgOverride("--load", b.Load, args)). + Arg(argOverride("--metadata-file", b.MetadataFile, args)). + Arg(argOverride("--network", b.Network, args)). + BoolArg(boolArgOverride("--no-cache", b.NoCache, args)). + ListArg(listArgOverride("--noe-cache-filter", b.NoCacheFilter, args)). + Arg(argOverride("--output", b.Output, args)). + Arg(argOverride("--platform", b.Platform, args)). // Arg("--progress", xxx). // Arg("--provenance", xxx). // Arg("--push", xxx). // Arg("--pull", xxx). // Arg("--quiet", xxx). - ListArg("--secret", b.Secret). - Arg("--shm-size", b.ShmSize). - Arg("--ssh", b.SSH). - Arg("--tag", fmt.Sprintf("%s:%s", b.Image, b.Tag)). - Arg("--target", b.Target). - Arg("--ulimit", b.ULimit). + ListArg(listArgOverride("--secret", b.Secret, args)). + Arg(argOverride("--shm-size", b.ShmSize, args)). + Arg(argOverride("--ssh", b.SSH, args)). + Arg(argOverride("--tag", fmt.Sprintf("%s:%s", b.Image, b.Tag), args)). + Arg(argOverride("--target", b.Target, args)). + Arg(argOverride("--ulimit", b.ULimit, args)). Args(args...). Run(ctx) } From 96890648fe85f4e3ea43d34387c240d3037f9d91 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Apr 2024 19:11:24 +0200 Subject: [PATCH 59/63] feat: switch to StringArray --- cmd/actions/build.go | 2 +- cmd/actions/push.go | 4 ++-- cmd/actions/up.go | 4 ++-- internal/config/build.go | 7 ++++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 0fab1ab..d54e9e0 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -9,9 +9,9 @@ import ( func init() { buildCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes built squadron units to the registry") buildCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - buildCmd.Flags().StringArrayVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") buildCmd.Flags().StringArrayVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") buildCmd.Flags().StringArrayVar(&flagPushArgs, "push-args", nil, "additional docker push args") + buildCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } var buildCmd = &cobra.Command{ diff --git a/cmd/actions/push.go b/cmd/actions/push.go index 6ad58e7..e037c2c 100644 --- a/cmd/actions/push.go +++ b/cmd/actions/push.go @@ -10,8 +10,8 @@ func init() { pushCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})") pushCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units") pushCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - pushCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") - pushCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") + pushCmd.Flags().StringArrayVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") + pushCmd.Flags().StringArrayVar(&flagPushArgs, "push-args", nil, "additional docker push args") pushCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } diff --git a/cmd/actions/up.go b/cmd/actions/up.go index 29341b5..82c4215 100644 --- a/cmd/actions/up.go +++ b/cmd/actions/up.go @@ -15,8 +15,8 @@ func init() { upCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units") upCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes units to the registry") upCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel") - upCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") - upCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args") + upCmd.Flags().StringArrayVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args") + upCmd.Flags().StringArrayVar(&flagPushArgs, "push-args", nil, "additional docker push args") upCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)") } diff --git a/internal/config/build.go b/internal/config/build.go index 7d552ef..eaa983f 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -99,7 +99,7 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { } pterm.Debug.Printfln("running docker build for %q", b.Context) - return util.NewDockerCommand().Build(b.Context). + sh := util.NewDockerCommand().Build(b.Context). ListArg(listArgOverride("--add-host", b.AddHost, args)). ListArg(listArgOverride("--allow", b.Allow, args)). ListArg(listArgOverride("--attest", b.Attest, args)). @@ -129,8 +129,9 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { Arg(argOverride("--tag", fmt.Sprintf("%s:%s", b.Image, b.Tag), args)). Arg(argOverride("--target", b.Target, args)). Arg(argOverride("--ulimit", b.ULimit, args)). - Args(args...). - Run(ctx) + Args(args...) + fmt.Println(sh.String()) + return sh.Run(ctx) } func (b *Build) Push(ctx context.Context, args []string) (string, error) { From 9bafb55bc21a425b78cbc26d5e8bfbc0efe346c2 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Apr 2024 19:17:30 +0200 Subject: [PATCH 60/63] revert: run and return --- internal/config/build.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/config/build.go b/internal/config/build.go index eaa983f..f937e68 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -99,7 +99,7 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { } pterm.Debug.Printfln("running docker build for %q", b.Context) - sh := util.NewDockerCommand().Build(b.Context). + return util.NewDockerCommand().Build(b.Context). ListArg(listArgOverride("--add-host", b.AddHost, args)). ListArg(listArgOverride("--allow", b.Allow, args)). ListArg(listArgOverride("--attest", b.Attest, args)). @@ -129,9 +129,7 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { Arg(argOverride("--tag", fmt.Sprintf("%s:%s", b.Image, b.Tag), args)). Arg(argOverride("--target", b.Target, args)). Arg(argOverride("--ulimit", b.ULimit, args)). - Args(args...) - fmt.Println(sh.String()) - return sh.Run(ctx) + Args(args...).Run(ctx) } func (b *Build) Push(ctx context.Context, args []string) (string, error) { From 8617fbaba1c41e9a86b7d1dcc57468a6e0852f1f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 30 Apr 2024 19:46:19 +0200 Subject: [PATCH 61/63] fix: init cache --- internal/template/onepassword.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index 7823281..0e5c73f 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -146,7 +146,7 @@ func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing b return func(account, vaultUUID, itemUUID, field string) (string, error) { // validate command if isConnect() || isServiceAccount() { - // do nothing + onePasswordCache = map[string]map[string]string{} } else if err := init(account); err != nil { return "", err } From 63e63f8f72f233e6662444873754eefb30ab9028 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 2 May 2024 14:04:53 +0200 Subject: [PATCH 62/63] feat: allow dynamic docker command arguements --- internal/config/build.go | 1 + internal/util/cmd.go | 39 +++++++++++++++++++++++++++++++++++---- internal/util/template.go | 18 ++++++++++++++++++ squadron.go | 11 +---------- 4 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 internal/util/template.go diff --git a/internal/config/build.go b/internal/config/build.go index f937e68..0595fdd 100644 --- a/internal/config/build.go +++ b/internal/config/build.go @@ -100,6 +100,7 @@ func (b *Build) Build(ctx context.Context, args []string) (string, error) { pterm.Debug.Printfln("running docker build for %q", b.Context) return util.NewDockerCommand().Build(b.Context). + TemplateData(map[string]string{"image": b.Image, "tag": b.Tag}). ListArg(listArgOverride("--add-host", b.AddHost, args)). ListArg(listArgOverride("--allow", b.Allow, args)). ListArg(listArgOverride("--attest", b.Attest, args)). diff --git a/internal/util/cmd.go b/internal/util/cmd.go index 383be7a..1ed0240 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -13,6 +13,7 @@ import ( type Cmd struct { command []string + templateData any cwd string env []string stdin io.Reader @@ -20,6 +21,10 @@ type Cmd struct { stderrWriters []io.Writer } +// ------------------------------------------------------------------------------------------------ +// ~ Constructor +// ------------------------------------------------------------------------------------------------ + func NewCommand(name string) *Cmd { return &Cmd{ command: []string{name}, @@ -27,21 +32,30 @@ func NewCommand(name string) *Cmd { } } +// ------------------------------------------------------------------------------------------------ +// ~ Public methods +// ------------------------------------------------------------------------------------------------ + func (c *Cmd) Args(args ...string) *Cmd { for _, arg := range args { if arg == "" { continue } - c.command = append(c.command, arg) + c.append(arg) } return c } +func (c *Cmd) TemplateData(v any) *Cmd { + c.templateData = v + return c +} + func (c *Cmd) Arg(name, v string) *Cmd { if name == "" || v == "" { return c } - c.command = append(c.command, name, v) + c.append(name, v) return c } @@ -49,7 +63,7 @@ func (c *Cmd) BoolArg(name string, v bool) *Cmd { if name == "" || !v { return c } - c.command = append(c.command, name) + c.append(name) return c } @@ -61,7 +75,7 @@ func (c *Cmd) ListArg(name string, vs []string) *Cmd { if v == "" { continue } - c.command = append(c.command, name, v) + c.append(name, v) } return c } @@ -127,3 +141,20 @@ func (c *Cmd) Run(ctx context.Context) (string, error) { err := cmd.Run() return stdout.String() + stderr.String(), err } + +// ------------------------------------------------------------------------------------------------ +// ~ Private methods +// ------------------------------------------------------------------------------------------------ + +func (c *Cmd) append(v ...string) { + if c.templateData != nil { + for i, s := range v { + if value, err := RenderTemplateString(s, c.templateData); err != nil { + pterm.Fatal.Println("failed to render template", err) + } else { + v[i] = value + } + } + } + c.command = append(c.command, v...) +} diff --git a/internal/util/template.go b/internal/util/template.go new file mode 100644 index 0000000..edb902d --- /dev/null +++ b/internal/util/template.go @@ -0,0 +1,18 @@ +package util + +import ( + "bytes" + "text/template" +) + +func RenderTemplateString(s string, data any) (string, error) { + t, err := template.New("template").Parse(s) + if err != nil { + return "", err + } + var out bytes.Buffer + if err := t.Execute(&out, data); err != nil { + return "", err + } + return out.String(), nil +} diff --git a/squadron.go b/squadron.go index 9dc8431..23e417c 100644 --- a/squadron.go +++ b/squadron.go @@ -11,7 +11,6 @@ import ( "slices" "strings" "sync" - "text/template" "github.com/foomo/squadron/internal/config" templatex "github.com/foomo/squadron/internal/template" @@ -54,15 +53,7 @@ func (sq *Squadron) Namespace(ctx context.Context, squadron, unit string) (strin if sq.namespace == "" { return "default", nil } - var out bytes.Buffer - t, err := template.New("namespace").Parse(sq.namespace) - if err != nil { - return "", err - } - if err := t.Execute(&out, map[string]string{"Squadron": squadron, "Unit": unit}); err != nil { - return "", err - } - return out.String(), nil + return util.RenderTemplateString(sq.namespace, map[string]string{"Squadron": squadron, "Unit": unit}) } func (sq *Squadron) Config() config.Config { From 2d8210bcf4f386766e6e38600fa151d4986e76c2 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Thu, 6 Jun 2024 22:54:13 +0200 Subject: [PATCH 63/63] feat: add opDoc template func --- internal/template/onepassword.go | 126 +++++++++++++++++++++++++++---- internal/template/template.go | 1 + 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/internal/template/onepassword.go b/internal/template/onepassword.go index 0e5c73f..3d9603a 100644 --- a/internal/template/onepassword.go +++ b/internal/template/onepassword.go @@ -49,6 +49,36 @@ func onePasswordConnectGet(client connect.Client, vaultUUID, itemUUID string) (m return ret, nil } +func onePasswordConnectGetDocument(client connect.Client, vaultUUID, itemUUID string) (string, error) { + var item *onepassword.Item + if onePasswordUUID.Match([]byte(itemUUID)) { + if v, err := client.GetItem(itemUUID, vaultUUID); err != nil { + return "", err + } else { + item = v + } + } else { + if v, err := client.GetItemByTitle(itemUUID, vaultUUID); err != nil { + return "", err + } else { + item = v + } + } + + if item.Category != onepassword.Document { + return "", errors.Errorf("unexpected document type: %s", item.Category) + } else if len(item.Files) != 0 { + return "", errors.Errorf("unexpected document files length: %d", len(item.Files)) + } + + res, err := client.GetFileContent(item.Files[0]) + if err != nil { + return "", err + } + + return strings.Trim(string(res), "\n"), nil +} + func onePasswordGet(ctx context.Context, account, vaultUUID, itemUUID string) (map[string]string, error) { var v struct { Vault struct { @@ -85,6 +115,16 @@ func onePasswordGet(ctx context.Context, account, vaultUUID, itemUUID string) (m } } +func onePasswordGetDocument(ctx context.Context, account, vaultUUID, itemUUID string) (string, error) { + res, err := exec.CommandContext(ctx, "op", "document", "get", itemUUID, "--vault", vaultUUID, "--account", account).CombinedOutput() + if err != nil && strings.Contains(string(res), "You are not currently signed in") { + return "", ErrOnePasswordNotSignedIn + } else if err != nil { + return "", errors.Wrap(err, string(res)) + } + return strings.Trim(string(res), "\n"), nil +} + func onePasswordSignIn(ctx context.Context, account string) error { fmt.Println("Your templates includes a call to 1Password, please sign in to retrieve your session token:") @@ -124,30 +164,30 @@ func isServiceAccount() bool { return os.Getenv("OP_SERVICE_ACCOUNT_TOKEN") != "" } -func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { - init := func(account string) error { - if onePasswordCache == nil { - onePasswordCache = map[string]map[string]string{} - if _, err := exec.LookPath("op"); err != nil { - pterm.Warning.Println("Your templates includes a call to 1Password, please install it:") - pterm.Warning.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") - return errors.Wrap(err, "failed to lookup op") - } else if _, err := exec.CommandContext(ctx, "op", "account", "get", "--account", account).CombinedOutput(); err == nil { - // do nothing - } else if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { - if err := onePasswordSignIn(ctx, account); err != nil { - return errors.Wrap(err, "failed to sign in") - } +func onePasswordInit(ctx context.Context, account string) error { + if onePasswordCache == nil { + onePasswordCache = map[string]map[string]string{} + if _, err := exec.LookPath("op"); err != nil { + pterm.Warning.Println("Your templates includes a call to 1Password, please install it:") + pterm.Warning.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") + return errors.Wrap(err, "failed to lookup op") + } else if _, err := exec.CommandContext(ctx, "op", "account", "get", "--account", account).CombinedOutput(); err == nil { + // do nothing + } else if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { + if err := onePasswordSignIn(ctx, account); err != nil { + return errors.Wrap(err, "failed to sign in") } } - return nil } + return nil +} +func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID, field string) (string, error) { return func(account, vaultUUID, itemUUID, field string) (string, error) { // validate command if isConnect() || isServiceAccount() { onePasswordCache = map[string]map[string]string{} - } else if err := init(account); err != nil { + } else if err := onePasswordInit(ctx, account); err != nil { return "", err } // render uuid & field params @@ -201,6 +241,60 @@ func onePassword(ctx context.Context, templateVars interface{}, errorOnMissing b } } +func onePasswordDocument(ctx context.Context, templateVars interface{}, errorOnMissing bool) func(account, vaultUUID, itemUUID string) (string, error) { + return func(account, vaultUUID, itemUUID string) (string, error) { + // validate command + if isConnect() || isServiceAccount() { + onePasswordCache = map[string]map[string]string{} + } else if err := onePasswordInit(ctx, account); err != nil { + return "", err + } + // render uuid & field params + if value, err := onePasswordRender("op", itemUUID, templateVars, errorOnMissing); err != nil { + return "", err + } else { + itemUUID = value + } + + // create cache key + cacheKey := strings.Join([]string{account, vaultUUID, itemUUID}, "#") + + if isConnect() { + if _, ok := onePasswordCache[cacheKey]; !ok { + if client, err := connect.NewClientFromEnvironment(); err != nil { + return "", err + } else if res, err := onePasswordConnectGetDocument(client, vaultUUID, itemUUID); err != nil { + return "", err + } else { + onePasswordCache[cacheKey] = map[string]string{"document": res} + } + } + } else { + if _, ok := onePasswordCache[cacheKey]; !ok { + if res, err := onePasswordGetDocument(ctx, account, vaultUUID, itemUUID); !errors.Is(err, ErrOnePasswordNotSignedIn) { + if err != nil { + return "", err + } else { + onePasswordCache[cacheKey] = map[string]string{"document": res} + } + } else if err := onePasswordSignIn(ctx, account); err != nil { + return "", errors.Wrap(err, "failed to sign in second time") + } else if res, err = onePasswordGetDocument(ctx, account, vaultUUID, itemUUID); err != nil { + return "", err + } else { + onePasswordCache[cacheKey] = map[string]string{"document": res} + } + } + } + + if value, ok := onePasswordCache[cacheKey]["document"]; !ok { + return "", nil + } else { + return value, nil + } + } +} + func onePasswordRender(name, text string, data interface{}, errorOnMissing bool) (string, error) { var opts []string if !errorOnMissing { diff --git a/internal/template/template.go b/internal/template/template.go index 01eb483..e374b18 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -11,6 +11,7 @@ func ExecuteFileTemplate(ctx context.Context, text string, templateVars interfac "env": env, "envDefault": envDefault, "op": onePassword(ctx, templateVars, errorOnMissing), + "opDoc": onePasswordDocument(ctx, templateVars, errorOnMissing), "base64": base64, "default": defaultValue, "defaultIndex": defaultIndexValue,