diff --git a/README.md b/README.md index a2495d6..c751cd1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,31 @@ You can use the `Helm-KCL-Plugin` to + For multi-environment and multi-tenant scenarios, you can maintain these configurations gracefully rather than simply copy and paste. + Validate all KRM resources using the KCL schema. +## Prerequisites + ++ Install Helm ++ Golang (at least version 1.18) + +## Test the Plugin + +You need to put your KCL script source in the functionConfig of kind KCLRun and then the function will run the KCL script that you provide. + +```bash +# Verify that the annotation is added to the `Deployment` resource and the other resource `Service` +# does not have this annotation. +diff \ + <(helm template ./examples/workload-charts-with-kcl/workload-charts) \ + <(go run main.go template --file ./examples/workload-charts-with-kcl/kcl-run.yaml) |\ + grep annotations -A1 +``` + +The output is + +```diff +> annotations: +> managed-by: helm-kcl-plugin +``` + ## Install ### Using Helm plugin manager (> 2.3.x) @@ -63,6 +88,12 @@ make install make install/helm3 ``` +## Quick Start + +```shell +helm create my-chart +``` + ## Build ### Prerequisites diff --git a/cmd/root.go b/cmd/root.go index b541d98..2fb0421 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,9 +16,11 @@ func New() *cobra.Command { Use: "kcl", Short: "Edit, transformer, validate Helm charts using the KCL programming language.", Long: rootCmdLongUsage, + SilenceUsage: true, } - cmd.AddCommand(newVersionCmd()) + cmd.AddCommand(NewVersionCmd()) + cmd.AddCommand(NewTemplateCmd()) cmd.SetHelpCommand(&cobra.Command{}) // Disable the help command return cmd } diff --git a/cmd/template.go b/cmd/template.go new file mode 100644 index 0000000..2ec5dbb --- /dev/null +++ b/cmd/template.go @@ -0,0 +1,52 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "kusionstack.io/helm-kcl/pkg/app" + "kusionstack.io/helm-kcl/pkg/config" +) + +// NewTemplateCmd returm template subcmd +func NewTemplateCmd() *cobra.Command { + templateOptions := config.NewTemplateOptions() + + cmd := &cobra.Command{ + Use: "template", + Short: "Template releases defined in the KCL state file", + PreRun: func(*cobra.Command, []string) { + app.ExpandTLSPaths() + }, + RunE: func(*cobra.Command, []string) error { + err := app.New().Template(config.NewTemplateImpl(templateOptions)) + if err != nil { + return err + } + return nil + }, + SilenceUsage: true, + } + + f := cmd.Flags() + f.StringVar(&templateOptions.File, "file", "", "input kcl file to pass to helm kcl template") + f.StringArrayVar(&templateOptions.Set, "set", nil, "additional values to be merged into the helm command --set flag") + f.StringArrayVar(&templateOptions.Values, "values", nil, "additional value files to be merged into the helm command --values flag") + f.StringVar(&templateOptions.OutputDir, "output-dir", "", "output directory to pass to helm template (helm template --output-dir)") + f.StringVar(&templateOptions.OutputDirTemplate, "output-dir-template", "", "go text template for generating the output directory. Default: {{ .OutputDir }}/{{ .State.BaseName }}-{{ .State.AbsPathSHA1 }}-{{ .Release.Name}}") + f.IntVar(&templateOptions.Concurrency, "concurrency", 0, "maximum number of concurrent helm processes to run, 0 is unlimited") + f.BoolVar(&templateOptions.Validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. Note that this requires access to a Kubernetes cluster to obtain information necessary for validating, like the template of available API versions") + f.BoolVar(&templateOptions.IncludeCRDs, "include-crds", false, "include CRDs in the templated output") + f.BoolVar(&templateOptions.SkipTests, "skip-tests", false, "skip tests from templated output") + f.BoolVar(&templateOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`) + f.BoolVar(&templateOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`) + f.BoolVar(&templateOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`) + f.BoolVar(&templateOptions.SkipDeps, "skip-deps", false, `skip running "helm repo update" and "helm dependency build"`) + f.BoolVar(&templateOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security") + f.StringVar(&templateOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`) + + if !app.IsHelm3() { + app.AddCommonCmdOptions(f) + } + + return cmd +} diff --git a/cmd/version.go b/cmd/version.go index f28b63d..10317c0 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -9,12 +9,13 @@ import ( // Version identifier populated via the CI/CD process. var Version = "HEAD" -func newVersionCmd() *cobra.Command { +func NewVersionCmd() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Show version of the helm kcl plugin", Run: func(*cobra.Command, []string) { fmt.Println(Version) }, + SilenceUsage: true, } } diff --git a/examples/workload-charts-with-kcl/kcl-run.yaml b/examples/workload-charts-with-kcl/kcl-run.yaml new file mode 100644 index 0000000..423825f --- /dev/null +++ b/examples/workload-charts-with-kcl/kcl-run.yaml @@ -0,0 +1,17 @@ +# kcl-config.yaml +apiVersion: fn.kpt.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-annotation +# EDIT THE SOURCE! +# This should be your KCL code which preloads the `ResourceList` to `option("resource_list") +source: | + [resource | {if resource.kind == "Deployment": metadata.annotations: {"managed-by" = "helm-kcl-plugin"}} for resource in option("resource_list").items] + +repositories: + - name: workload + path: ./workload-charts + # TDDO: + # url + # git + # oci diff --git a/examples/workload-charts-with-kcl/workload-charts/.helmignore b/examples/workload-charts-with-kcl/workload-charts/.helmignore new file mode 100644 index 0000000..691fa13 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ \ No newline at end of file diff --git a/examples/workload-charts-with-kcl/workload-charts/Chart.yaml b/examples/workload-charts-with-kcl/workload-charts/Chart.yaml new file mode 100644 index 0000000..dfb5012 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 0.1.0 +description: A helm chart to provision standard workloads. +name: workload +type: application +version: 0.1.0 diff --git a/examples/workload-charts-with-kcl/workload-charts/templates/_helpers.tpl b/examples/workload-charts-with-kcl/workload-charts/templates/_helpers.tpl new file mode 100644 index 0000000..09d2ff1 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/templates/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "workload.name" -}} +{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "workload.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "workload.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} +{{/* +Common labels +*/}} +{{- define "workload.labels" -}} +helm.sh/chart: {{ include "workload.chart" . }} +{{ include "workload.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} +{{/* +Selector labels +*/}} +{{- define "workload.selectorLabels" -}} +app.kubernetes.io/name: {{ include "workload.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/examples/workload-charts-with-kcl/workload-charts/templates/deployment.yaml b/examples/workload-charts-with-kcl/workload-charts/templates/deployment.yaml new file mode 100644 index 0000000..8d2e967 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/templates/deployment.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "workload.name" . }} + labels: + {{- include "workload.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "workload.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "workload.selectorLabels" . | nindent 8 }} + spec: + containers: + {{- range $name, $container := .Values.containers }} + - name: {{ $name }} + image: "{{ $container.image.name }}" + {{- with $container.command }} + command: + {{- toYaml $container.command | nindent 12 }} + {{- end }} + {{- with $container.args }} + args: + {{- toYaml $container.args | nindent 12 }} + {{- end }} + {{- with $container.env }} + env: + {{- toYaml $container.env | nindent 12 }} + {{- end }} + {{- with $container.volumeMounts }} + volumeMounts: + {{- toYaml $container.volumeMounts | nindent 12 }} + {{- end }} + {{- with $container.livenessProbe }} + livenessProbe: + {{- toYaml $container.livenessProbe | nindent 12 }} + {{- end }} + {{- with $container.readinessProbe }} + readinessProbe: + {{- toYaml $container.readinessProbe | nindent 12 }} + {{- end }} + {{- with $container.resources }} + resources: + {{- toYaml $container.resources | nindent 12 }} + {{- end }} + {{- end }} diff --git a/examples/workload-charts-with-kcl/workload-charts/templates/service.yaml b/examples/workload-charts-with-kcl/workload-charts/templates/service.yaml new file mode 100644 index 0000000..ac2afc5 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/templates/service.yaml @@ -0,0 +1,16 @@ +{{ if .Values.service }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "workload.name" . }} + labels: + {{- include "workload.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + selector: + {{- include "workload.selectorLabels" . | nindent 4 }} + {{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/examples/workload-charts-with-kcl/workload-charts/values.yaml b/examples/workload-charts-with-kcl/workload-charts/values.yaml new file mode 100644 index 0000000..64050e3 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/values.yaml @@ -0,0 +1,16 @@ +# +# Default values for the chart (for reference only). +# An actual values file is rendered from the source SCORE file by the CLI tool. + +containers: + frontend: + image: + name: nginx:alpine + +service: + type: ClusterIP + ports: + - name: www + protocol: TCP + port: 80 + targetPort: 80 diff --git a/examples/workload-charts-with-kcl/workload-charts/workload/templates/deployment.yaml b/examples/workload-charts-with-kcl/workload-charts/workload/templates/deployment.yaml new file mode 100644 index 0000000..3366559 --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/workload/templates/deployment.yaml @@ -0,0 +1,26 @@ +--- +# Source: workload/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: release-name + labels: + helm.sh/chart: workload-0.1.0 + app.kubernetes.io/name: release-name + app.kubernetes.io/instance: release-name + app.kubernetes.io/version: "0.1.0" + app.kubernetes.io/managed-by: Helm +spec: + selector: + matchLabels: + app.kubernetes.io/name: release-name + app.kubernetes.io/instance: release-name + template: + metadata: + labels: + app.kubernetes.io/name: release-name + app.kubernetes.io/instance: release-name + spec: + containers: + - name: frontend + image: "nginx:alpine" diff --git a/examples/workload-charts-with-kcl/workload-charts/workload/templates/service.yaml b/examples/workload-charts-with-kcl/workload-charts/workload/templates/service.yaml new file mode 100644 index 0000000..69aaa8a --- /dev/null +++ b/examples/workload-charts-with-kcl/workload-charts/workload/templates/service.yaml @@ -0,0 +1,22 @@ +--- +# Source: workload/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: release-name + labels: + helm.sh/chart: workload-0.1.0 + app.kubernetes.io/name: release-name + app.kubernetes.io/instance: release-name + app.kubernetes.io/version: "0.1.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: release-name + app.kubernetes.io/instance: release-name + ports: + - name: www + port: 80 + protocol: TCP + targetPort: 80 diff --git a/go.mod b/go.mod index b344eb5..311e073 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,84 @@ module kusionstack.io/helm-kcl go 1.18 require ( + github.com/Masterminds/semver v1.5.0 github.com/spf13/cobra v1.6.1 + github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.1 + go.uber.org/zap v1.24.0 + google.golang.org/grpc v1.50.1 gopkg.in/yaml.v2 v2.4.0 + k8s.io/client-go v0.26.0 k8s.io/helm v2.17.0+incompatible + kusionstack.io/kclvm-go v0.4.5 + kusionstack.io/kpt-kcl-sdk v0.1.0 ) require ( + github.com/BurntSushi/toml v1.2.1 // indirect + github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93 // indirect + github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20230302070146-e8e9cb3c3ae2 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/chai2010/jsonv v1.1.3 // indirect + github.com/chai2010/protorpc v1.1.4 // indirect + github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/huandu/xstrings v1.3.3 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/kr/pretty v0.3.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/xlab/treeprint v1.1.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 // indirect google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.26.0 // indirect + k8s.io/apimachinery v0.26.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + kusionstack.io/kcl-plugin v0.4.4 // indirect + kusionstack.io/kclvm-artifact-go v0.4.5 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) + +replace sigs.k8s.io/kustomize/kyaml v0.14.1 => sigs.k8s.io/kustomize/kyaml v0.13.9 diff --git a/go.sum b/go.sum index a1f75b0..75dd32b 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,102 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93 h1:c1GhPzYzU2a3E+/2WB9OxoljK2pNYfsBF5Fz9GkdYXs= +github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93/go.mod h1:gkK43tTaPXFNASpbIbQImzhmt1hdcdin++kvzTblykc= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20230302070146-e8e9cb3c3ae2 h1:GDUCDAY2ijsUjg70QPMvWKezRxGKKzU07ckVc5uTgZA= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20230302070146-e8e9cb3c3ae2/go.mod h1:Pnd3ImgaWS3OBVjztSiGMACMf+CDs20l5nT5Oljy/tA= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chai2010/jsonv v1.1.3 h1:gBIHXn/5mdEPTuWZfjC54fn/yUSRR8OGobXobcc6now= +github.com/chai2010/jsonv v1.1.3/go.mod h1:mEoT1dQ9qVF4oP9peVTl0UymTmJwXoTDOh+sNA6+XII= +github.com/chai2010/protorpc v1.1.4 h1:CTtFUhzXRoeuR7FtgQ2b2vdT/KgWVpCM+sIus8zJjHs= +github.com/chai2010/protorpc v1.1.4/go.mod h1:/wO0kiyVdu7ug8dCMrA2yDr2vLfyhsLEuzLa9J2HJ+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 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/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/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/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +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.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +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.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +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.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +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.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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +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/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +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.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -18,35 +104,202 @@ 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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +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 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +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/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= 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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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/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/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-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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +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/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/sys v0.0.0-20180830151530-49385e6e1522/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-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-20210615035016-665e8c7367d1/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +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= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/genproto v0.0.0-20221025140454-527a21cfbd71 h1:GEgb2jF5zxsFJpJfg9RoDDWm7tiwc/DDSTE2BtLUkXU= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +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/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +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.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= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/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= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.2/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/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.26.0 h1:IpPlZnxBpV1xl7TGk/X6lFtpgjgntCg8PJ+qrPHAC7I= +k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/client-go v0.26.0 h1:lT1D3OfO+wIi9UFolCrifbjUUgu7CpLca0AD8ghRLI8= +k8s.io/client-go v0.26.0/go.mod h1:I2Sh57A79EQsDmn7F7ASpmru1cceh3ocVT9KlX2jEZg= k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao= k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596 h1:8cNCQs+WqqnSpZ7y0LMQPKD+RZUHU17VqLPMW3qxnxc= +k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596/go.mod h1:/BYxry62FuDzmI+i9B+X2pqfySRmSOW2ARmj5Zbqhj0= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +kusionstack.io/kcl-plugin v0.4.4 h1:Ke6SMbZ33qaR0mTCaZSVmVop+8Hk8UQK217z7ml97z8= +kusionstack.io/kcl-plugin v0.4.4/go.mod h1:VgB7qXVbDGWFOh/qb/yXf75+UrliP5EPXOQUDqBCdAQ= +kusionstack.io/kclvm-artifact-go v0.4.5 h1:PlCKpdeFExV4JNFQ2dRPZ9nrEL3HxVGyGvOlOLPwD+0= +kusionstack.io/kclvm-artifact-go v0.4.5/go.mod h1:WI+NvDeMqu1AduJT119X7q8KQdYmKfv4Nq4OvZ1tAsI= +kusionstack.io/kclvm-go v0.4.5 h1:nXMYiYA96m5lzZ2Tlz5xvIvodEMn4OLlFuYL/M5dqAg= +kusionstack.io/kclvm-go v0.4.5/go.mod h1:fZhG25z3XnjqaXePHsi5GgqVtl837g7NS/1EpbdV/58= +kusionstack.io/kpt-kcl-sdk v0.1.0 h1:cGxEG15BK0XnNzvzgsiXatXuk6k1RtMK4QQAo3x2C9s= +kusionstack.io/kpt-kcl-sdk v0.1.0/go.mod h1:v94UQiiJL7fDLvU611NaUsAsCFQGrpiMLIbSUbqE2SA= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= +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.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/main.go b/main.go index 1b08911..2d32934 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,8 @@ import ( "os" "kusionstack.io/helm-kcl/cmd" + _ "kusionstack.io/kclvm-go" + _ "kusionstack.io/kpt-kcl-sdk/pkg/config" ) func main() { diff --git a/pkg/app/app.go b/pkg/app/app.go new file mode 100644 index 0000000..3da219e --- /dev/null +++ b/pkg/app/app.go @@ -0,0 +1,98 @@ +package app + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sync" + + "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" + "go.uber.org/zap" + "k8s.io/helm/pkg/helm" + "kusionstack.io/helm-kcl/pkg/config" + "kusionstack.io/kpt-kcl-sdk/pkg/process" +) + +var CleanWaitGroup sync.WaitGroup + +// App is the main application object. +type App struct { + helmBinary string + logger *zap.SugaredLogger + helm helm.Interface +} + +type HelmRelease struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Enabled bool `json:"enabled"` + Installed bool `json:"installed"` + Labels string `json:"labels"` + Chart string `json:"chart"` + Version string `json:"version"` +} + +func (app *App) Template(templateImpl *config.TemplateImpl) error { + kclRun, err := config.FromFile(templateImpl.File) + if err != nil { + return err + } + for _, repo := range kclRun.Repositories { + path := repo.Path + if !filepath.IsAbs(repo.Path) { + path = filepath.Join(filepath.Dir(templateImpl.File), repo.Path) + } + if IsHelm3() { + if err := app.runHelm3Template(templateImpl.File, repo.Name, path); err != nil { + return err + } + } else { + return errors.New("Helm 2 is not supported yet") + } + } + return nil +} + +func (app *App) runHelm3Template(kclRunFile, release, chart string) error { + if err := compatibleHelm3Version(); err != nil { + app.logger.Error(err) + return err + } + d := diffCmd{ + release: release, + chart: chart, + dryRun: true, + } + // Kubernetes manifests + template, err := d.template(false) + if err != nil { + return err + } + // KCL function config + fnCfgBytes, err := os.ReadFile(kclRunFile) + if err != nil { + return err + } + items, err := fn.ParseKubeObjects(template) + if err != nil { + return err + } + fnCfg, err := fn.ParseKubeObject(fnCfgBytes) + if err != nil { + return err + } + resourceList := &fn.ResourceList{ + Items: items, + FunctionConfig: fnCfg, + } + result, err := process.Process(resourceList) + if err != nil { + return err + } + if !result { + return errors.New(resourceList.Results.Error()) + } + fmt.Println(resourceList.Items.String()) + return nil +} diff --git a/pkg/app/helm.go b/pkg/app/helm.go new file mode 100644 index 0000000..434a055 --- /dev/null +++ b/pkg/app/helm.go @@ -0,0 +1,132 @@ +package app + +// This file contains functions that where blatantly copied from +// https://github.wdf.sap.corp/kubernetes/helm + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "google.golang.org/grpc" + "k8s.io/helm/pkg/downloader" + "k8s.io/helm/pkg/getter" + "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/helm/helmpath" +) + +/////////////// Source: cmd/helm/install.go ///////////////////////// + +type valueFiles []string + +func (v *valueFiles) String() string { + return fmt.Sprint(*v) +} + +// Ensures all valuesFiles exist +func (v *valueFiles) Valid() error { + errStr := "" + for _, valuesFile := range *v { + if strings.TrimSpace(valuesFile) != "-" { + if _, err := os.Stat(valuesFile); os.IsNotExist(err) { + errStr += err.Error() + } + } + } + + if errStr == "" { + return nil + } + + return errors.New(errStr) +} + +func (v *valueFiles) Type() string { + return "valueFiles" +} + +func (v *valueFiles) Set(value string) error { + for _, filePath := range strings.Split(value, ",") { + *v = append(*v, filePath) + } + return nil +} + +func locateChartPath(name, version string, verify bool, keyring string) (string, error) { + name = strings.TrimSpace(name) + version = strings.TrimSpace(version) + if fi, err := os.Stat(name); err == nil { + abs, err := filepath.Abs(name) + if err != nil { + return abs, err + } + if verify { + if fi.IsDir() { + return "", errors.New("cannot verify a directory") + } + if _, err := downloader.VerifyChart(abs, keyring); err != nil { + return "", err + } + } + return abs, nil + } + if filepath.IsAbs(name) || strings.HasPrefix(name, ".") { + return name, fmt.Errorf("path %q not found", name) + } + + crepo := filepath.Join(helmpath.Home(homePath()).Repository(), name) + if _, err := os.Stat(crepo); err == nil { + return filepath.Abs(crepo) + } + + dl := downloader.ChartDownloader{ + HelmHome: helmpath.Home(homePath()), + Out: os.Stdout, + Keyring: keyring, + Getters: getter.All(environment.EnvSettings{}), + } + if verify { + dl.Verify = downloader.VerifyAlways + } + + filename, _, err := dl.DownloadTo(name, version, helmpath.Home(homePath()).Archive()) + if err == nil { + lname, err := filepath.Abs(filename) + if err != nil { + return filename, err + } + return lname, nil + } + + return filename, err +} + +/////////////// Source: cmd/helm/helm.go //////////////////////////// + +func checkArgsLength(argsReceived int, requiredArgs ...string) error { + expectedNum := len(requiredArgs) + if argsReceived != expectedNum { + arg := "arguments" + if expectedNum == 1 { + arg = "argument" + } + return fmt.Errorf("This command needs %v %s: %s", expectedNum, arg, strings.Join(requiredArgs, ", ")) + } + return nil +} + +func homePath() string { + return os.Getenv("HELM_HOME") +} + +func prettyError(err error) error { + if err == nil { + return nil + } + // This is ridiculous. Why is 'grpc.rpcError' not exported? The least they + // could do is throw an interface on the lib that would let us get back + // the desc. Instead, we have to pass ALL errors through this. + return errors.New(grpc.ErrorDesc(err)) +} diff --git a/pkg/app/helm3.go b/pkg/app/helm3.go new file mode 100644 index 0000000..52f1917 --- /dev/null +++ b/pkg/app/helm3.go @@ -0,0 +1,300 @@ +package app + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "github.com/Masterminds/semver" + "k8s.io/helm/pkg/helm" +) + +var ( + helmVersionRE = regexp.MustCompile(`Version:\s*"([^"]+)"`) + minHelmVersion = semver.MustParse("v3.1.0-rc.1") +) + +func HelmBin() string { + helmBin := DefaultHelmBinary + if os.Getenv("HELM_BIN") != "" { + helmBin = os.Getenv("HELM_BIN") + } + return helmBin +} + +func compatibleHelm3Version() error { + cmd := exec.Command(HelmBin(), "version") + debugPrint("Executing %s", strings.Join(cmd.Args, " ")) + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("Failed to run `%s version`: %v", HelmBin(), err) + } + versionOutput := string(output) + + matches := helmVersionRE.FindStringSubmatch(versionOutput) + if matches == nil { + return fmt.Errorf("Failed to find version in output %#v", versionOutput) + } + helmVersion, err := semver.NewVersion(matches[1]) + if err != nil { + return fmt.Errorf("Failed to parse version %#v: %v", matches[1], err) + } + + if minHelmVersion.GreaterThan(helmVersion) { + return fmt.Errorf("helm diff upgrade requires at least helm version %s", minHelmVersion.String()) + } + return nil + +} +func getRelease(release, namespace string) ([]byte, error) { + args := []string{"get", "manifest", release} + if namespace != "" { + args = append(args, "--namespace", namespace) + } + cmd := exec.Command(HelmBin(), args...) + return outputWithRichError(cmd) +} + +func getHooks(release, namespace string) ([]byte, error) { + args := []string{"get", "hooks", release} + if namespace != "" { + args = append(args, "--namespace", namespace) + } + cmd := exec.Command(HelmBin(), args...) + return outputWithRichError(cmd) +} + +func getRevision(release string, revision int, namespace string) ([]byte, error) { + args := []string{"get", "manifest", release, "--revision", strconv.Itoa(revision)} + if namespace != "" { + args = append(args, "--namespace", namespace) + } + cmd := exec.Command(HelmBin(), args...) + return outputWithRichError(cmd) +} + +func getChart(release, namespace string) (string, error) { + args := []string{"get", "all", release, "--template", "{{.Release.Chart.Name}}"} + if namespace != "" { + args = append(args, "--namespace", namespace) + } + cmd := exec.Command(HelmBin(), args...) + out, err := outputWithRichError(cmd) + if err != nil { + return "", err + } + return string(out), nil +} + +type diffCmd struct { + release string + chart string + chartVersion string + chartRepo string + client helm.Interface + detailedExitCode bool + devel bool + disableValidation bool + disableOpenAPIValidation bool + dryRun bool + namespace string // namespace to assume the release to be installed into. Defaults to the current kube config namespace. + valueFiles valueFiles + values []string + stringValues []string + fileValues []string + reuseValues bool + resetValues bool + allowUnreleased bool + noHooks bool + includeTests bool + postRenderer string + install bool + normalizeManifests bool + threeWayMerge bool + extraAPIs []string + kubeVersion string + useUpgradeDryRun bool + isAllowUnreleased bool +} + +func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { + flags := []string{} + if d.devel { + flags = append(flags, "--devel") + } + if d.noHooks && !d.useUpgradeDryRun { + flags = append(flags, "--no-hooks") + } + if d.chartVersion != "" { + flags = append(flags, "--version", d.chartVersion) + } + if d.chartRepo != "" { + flags = append(flags, "--repo", d.chartRepo) + } + if d.namespace != "" { + flags = append(flags, "--namespace", d.namespace) + } + if d.postRenderer != "" { + flags = append(flags, "--post-renderer", d.postRenderer) + } + + shouldDefaultReusingValues := isUpgrade && len(d.values) == 0 && len(d.stringValues) == 0 && len(d.valueFiles) == 0 && len(d.fileValues) == 0 + if (d.reuseValues || shouldDefaultReusingValues) && !d.resetValues && !d.dryRun { + tmpfile, err := ioutil.TempFile("", "existing-values") + if err != nil { + return nil, err + } + defer os.Remove(tmpfile.Name()) + if err := d.writeExistingValues(tmpfile); err != nil { + return nil, err + } + flags = append(flags, "--values", tmpfile.Name()) + } + for _, value := range d.values { + flags = append(flags, "--set", value) + } + for _, stringValue := range d.stringValues { + flags = append(flags, "--set-string", stringValue) + } + for _, valueFile := range d.valueFiles { + if strings.TrimSpace(valueFile) == "-" { + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return nil, err + } + + tmpfile, err := ioutil.TempFile("", "helm-kcl-stdin-values") + if err != nil { + return nil, err + } + defer os.Remove(tmpfile.Name()) + + if _, err := tmpfile.Write(bytes); err != nil { + tmpfile.Close() + return nil, err + } + + if err := tmpfile.Close(); err != nil { + return nil, err + } + + flags = append(flags, "--values", tmpfile.Name()) + } else { + flags = append(flags, "--values", valueFile) + } + } + for _, fileValue := range d.fileValues { + flags = append(flags, "--set-file", fileValue) + } + + if d.disableOpenAPIValidation { + flags = append(flags, "--disable-openapi-validation") + } + + var ( + subcmd string + filter func([]byte) []byte + ) + + if d.useUpgradeDryRun { + if d.dryRun { + return nil, fmt.Errorf("`diff upgrade --dry-run` conflicts with HELM_DIFF_USE_UPGRADE_DRY_RUN_AS_TEMPLATE. Either remove --dry-run to enable cluster access, or unset HELM_DIFF_USE_UPGRADE_DRY_RUN_AS_TEMPLATE to make cluster access unnecessary") + } + + if d.isAllowUnreleased { + // Otherwise you get the following error when this is a diff for a new install + // Error: UPGRADE FAILED: "$RELEASE_NAME" has no deployed releases + flags = append(flags, "--install") + } + + flags = append(flags, "--dry-run") + subcmd = "upgrade" + filter = func(s []byte) []byte { + return extractManifestFromHelmUpgradeDryRunOutput(s, d.noHooks) + } + } else { + if !d.disableValidation && !d.dryRun { + flags = append(flags, "--validate") + } + + if isUpgrade { + flags = append(flags, "--is-upgrade") + } + + for _, a := range d.extraAPIs { + flags = append(flags, "--api-versions", a) + } + + if d.kubeVersion != "" { + flags = append(flags, "--kube-version", d.kubeVersion) + } + + subcmd = "template" + + filter = func(s []byte) []byte { + return s + } + } + + args := []string{subcmd, d.release, d.chart} + args = append(args, flags...) + + cmd := exec.Command(HelmBin(), args...) + out, err := outputWithRichError(cmd) + return filter(out), err +} + +func (d *diffCmd) writeExistingValues(f *os.File) error { + cmd := exec.Command(HelmBin(), "get", "values", d.release, "--all", "--output", "yaml") + debugPrint("Executing %s", strings.Join(cmd.Args, " ")) + defer f.Close() + cmd.Stdout = f + return cmd.Run() +} + +func extractManifestFromHelmUpgradeDryRunOutput(s []byte, noHooks bool) []byte { + if len(s) == 0 { + return s + } + + i := bytes.Index(s, []byte("HOOKS:")) + hooks := s[i:] + + j := bytes.Index(hooks, []byte("MANIFEST:")) + + manifest := hooks[j:] + hooks = hooks[:j] + + k := bytes.Index(manifest, []byte("\nNOTES:")) + + if k > -1 { + manifest = manifest[:k+1] + } + + if noHooks { + hooks = nil + } else { + a := bytes.Index(hooks, []byte("---")) + if a > -1 { + hooks = hooks[a:] + } else { + hooks = nil + } + } + + a := bytes.Index(manifest, []byte("---")) + if a > -1 { + manifest = manifest[a:] + } + + r := []byte{} + r = append(r, manifest...) + r = append(r, hooks...) + + return r +} diff --git a/pkg/app/helpers.go b/pkg/app/helpers.go new file mode 100644 index 0000000..13d8203 --- /dev/null +++ b/pkg/app/helpers.go @@ -0,0 +1,94 @@ +package app + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + flag "github.com/spf13/pflag" + "k8s.io/client-go/util/homedir" + "k8s.io/helm/pkg/helm" + helm_env "k8s.io/helm/pkg/helm/environment" + "k8s.io/helm/pkg/tlsutil" +) + +const ( + tlsCaCertDefault = "$HELM_HOME/ca.pem" + tlsCertDefault = "$HELM_HOME/cert.pem" + tlsKeyDefault = "$HELM_HOME/key.pem" + + helm2TestSuccessHook = "test-success" + helm3TestHook = "test" +) + +var ( + settings helm_env.EnvSettings + // DefaultHelmHome to hold default home path of .helm dir + DefaultHelmHome = filepath.Join(homedir.HomeDir(), ".helm") +) + +func IsHelm3() bool { + return os.Getenv("TILLER_HOST") == "" +} + +func IsDebug() bool { + return os.Getenv("HELM_DEBUG") == "true" +} + +func debugPrint(format string, a ...interface{}) { + if IsDebug() { + fmt.Printf(format+"\n", a...) + } +} + +func AddCommonCmdOptions(f *flag.FlagSet) { + settings.AddFlagsTLS(f) + settings.InitTLS(f) + + f.StringVar((*string)(&settings.Home), "home", DefaultHelmHome, "location of your Helm config. Overrides $HELM_HOME") +} + +func createHelmClient() helm.Interface { + options := []helm.Option{helm.Host(os.Getenv("TILLER_HOST")), helm.ConnectTimeout(int64(30))} + + if settings.TLSVerify || settings.TLSEnable { + tlsopts := tlsutil.Options{ + ServerName: settings.TLSServerName, + KeyFile: settings.TLSKeyFile, + CertFile: settings.TLSCertFile, + InsecureSkipVerify: true, + } + + if settings.TLSVerify { + tlsopts.CaCertFile = settings.TLSCaCertFile + tlsopts.InsecureSkipVerify = false + } + + tlscfg, err := tlsutil.ClientConfig(tlsopts) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + + options = append(options, helm.WithTLS(tlscfg)) + } + + return helm.NewClient(options...) +} + +func ExpandTLSPaths() { + settings.TLSCaCertFile = os.ExpandEnv(settings.TLSCaCertFile) + settings.TLSCertFile = os.ExpandEnv(settings.TLSCertFile) + settings.TLSKeyFile = os.ExpandEnv(settings.TLSKeyFile) +} + +func outputWithRichError(cmd *exec.Cmd) ([]byte, error) { + debugPrint("Executing %s", strings.Join(cmd.Args, " ")) + output, err := cmd.Output() + if exitError, ok := err.(*exec.ExitError); ok { + return output, fmt.Errorf("%s: %s", exitError.Error(), string(exitError.Stderr)) + } + return output, err +} diff --git a/pkg/app/init.go b/pkg/app/init.go new file mode 100644 index 0000000..412ef88 --- /dev/null +++ b/pkg/app/init.go @@ -0,0 +1,59 @@ +package app + +import ( + "fmt" + "os" + "strings" +) + +const ( + DefaultHelmBinary = "helm" + DefaultKubeContext = "" + HelmRequiredVersion = "v3.10.3" + HelmRecommendedVersion = "v3.11.2" + HelmDiffRecommendedVersion = "v3.4.0" + HelmSecretsRecommendedVersion = "v4.1.1" + HelmGitRecommendedVersion = "v0.12.0" + HelmS3RecommendedVersion = "v0.14.0" + HelmInstallCommand = "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3" +) + +var ( + manuallyInstallCode = 1 + windowPackageManagers = map[string]string{ + "scoop": fmt.Sprintf("scoop install helm@%s", strings.TrimLeft(HelmRecommendedVersion, "v")), + "choco": fmt.Sprintf("choco install kubernetes-helm --version %s", strings.TrimLeft(HelmRecommendedVersion, "v")), + } + helmPlugins = []helmRecommendedPlugin{ + { + name: "diff", + version: HelmDiffRecommendedVersion, + repo: "https://github.com/databus23/helm-diff", + }, + { + name: "secrets", + version: HelmSecretsRecommendedVersion, + repo: "https://github.com/jkroepke/helm-secrets", + }, + { + name: "s3", + version: HelmS3RecommendedVersion, + repo: "https://github.com/hypnoglow/helm-s3.git", + }, + { + name: "helm-git", + version: HelmGitRecommendedVersion, + repo: "https://github.com/aslafy-z/helm-git.git", + }, + } +) + +type helmRecommendedPlugin struct { + name string + version string + repo string +} + +func New() *App { + return &App{helmBinary: DefaultHelmBinary, logger: NewLogger(os.Stdout, "debug"), helm: createHelmClient()} +} diff --git a/pkg/app/logger.go b/pkg/app/logger.go new file mode 100644 index 0000000..064e0c0 --- /dev/null +++ b/pkg/app/logger.go @@ -0,0 +1,25 @@ +package app + +import ( + "io" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func NewLogger(writer io.Writer, logLevel string) *zap.SugaredLogger { + var cfg zapcore.EncoderConfig + cfg.MessageKey = "message" + out := zapcore.AddSync(writer) + var level zapcore.Level + err := level.Set(logLevel) + if err != nil { + panic(err) + } + core := zapcore.NewCore( + zapcore.NewConsoleEncoder(cfg), + out, + level, + ) + return zap.New(core).Sugar() +} diff --git a/pkg/app/util.go b/pkg/app/util.go new file mode 100644 index 0000000..3cc3a2c --- /dev/null +++ b/pkg/app/util.go @@ -0,0 +1,61 @@ +package app + +import ( + "fmt" + "io" + "net/http" + "os" +) + +func downloadfile(filepath string, url string) error { + file, err := os.Create(filepath) + if err != nil { + return err + } + defer func() { _ = file.Close() }() + resp, err := http.Get(url) + if err != nil { + return err + } + if resp.StatusCode/100 != 2 { + return fmt.Errorf("download %s error, code: %d", url, resp.StatusCode) + } + defer func() { _ = resp.Body.Close() }() + _, err = io.Copy(file, resp.Body) + if err != nil { + return err + } + return nil +} + +// Merges source and destination map, preferring values from the source map +func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} { + for k, v := range src { + // If the key doesn't exist already, then just set the key to that value + if _, exists := dest[k]; !exists { + dest[k] = v + continue + } + nextMap, ok := v.(map[string]interface{}) + // If it isn't another map, overwrite the value + if !ok { + dest[k] = v + continue + } + // If the key doesn't exist already, then just set the key to that value + if _, exists := dest[k]; !exists { + dest[k] = nextMap + continue + } + // Edge case: If the key exists in the destination, but isn't a map + destMap, isMap := dest[k].(map[string]interface{}) + // If the source map has a map for this key, prefer it + if !isMap { + dest[k] = v + continue + } + // If we got to this point, it is a map in both, so merge them + dest[k] = mergeValues(destMap, nextMap) + } + return dest +} diff --git a/pkg/config/kcl.go b/pkg/config/kcl.go new file mode 100644 index 0000000..59633f7 --- /dev/null +++ b/pkg/config/kcl.go @@ -0,0 +1,27 @@ +package config + +import ( + "os" + + "gopkg.in/yaml.v2" + "kusionstack.io/kpt-kcl-sdk/pkg/config" +) + +// KCLRun is a custom resource to provider Helm kcl config including KCL source and params. +type KCLRun struct { + config.KCLRun `json:",inline" yaml:",inline"` + Repositories []RepositorySpec `yaml:"repositories,omitempty"` +} + +func FromFile(file string) (*KCLRun, error) { + yamlFile, err := os.ReadFile(file) + if err != nil { + return nil, err + } + var config KCLRun + err = yaml.Unmarshal(yamlFile, &config) + if err != nil { + return nil, err + } + return &config, nil +} diff --git a/pkg/config/repo.go b/pkg/config/repo.go new file mode 100644 index 0000000..4e04cb6 --- /dev/null +++ b/pkg/config/repo.go @@ -0,0 +1,17 @@ +package config + +// RepositorySpec that defines values for a helm repo +type RepositorySpec struct { + Name string `yaml:"name,omitempty"` + Path string `yaml:"path,omitempty"` + URL string `yaml:"url,omitempty"` + CaFile string `yaml:"caFile,omitempty"` + CertFile string `yaml:"certFile,omitempty"` + KeyFile string `yaml:"keyFile,omitempty"` + Username string `yaml:"username,omitempty"` + Password string `yaml:"password,omitempty"` + Managed string `yaml:"managed,omitempty"` + OCI bool `yaml:"oci,omitempty"` + PassCredentials string `yaml:"passCredentials,omitempty"` + SkipTLSVerify string `yaml:"skipTLSVerify,omitempty"` +} diff --git a/pkg/config/template.go b/pkg/config/template.go new file mode 100644 index 0000000..1e14477 --- /dev/null +++ b/pkg/config/template.go @@ -0,0 +1,132 @@ +package config + +import ( + "fmt" + "os" + "strings" +) + +// TemplateOptions is the options for the build command +type TemplateOptions struct { + // File is the file flag + File string + // Set is the set flag + Set []string + // Values is the values flag + Values []string + // OutputDir is the output dir flag + OutputDir string + // OutputDirTemplate is the output dir template flag + OutputDirTemplate string + // Concurrency is the concurrency flag + Concurrency int + // Validate is the validate flag + Validate bool + // IncludeCRDs is the include crds flag + IncludeCRDs bool + // SkipTests is the skip tests flag + SkipTests bool + // SkipNeeds is the skip needs flag + SkipNeeds bool + // IncludeNeeds is the include needs flag + IncludeNeeds bool + // IncludeTransitiveNeeds is the include transitive needs flag + IncludeTransitiveNeeds bool + // SkipDeps is the skip deps flag + SkipDeps bool + // SkipCleanup is the skip cleanup flag + SkipCleanup bool + // Propagate '--post-renderer' to helmv3 template and helm install + PostRenderer string +} + +// NewTemplateOptions creates a new Apply +func NewTemplateOptions() *TemplateOptions { + return &TemplateOptions{} +} + +// TemplateImpl is impl for applyOptions +type TemplateImpl struct { + *TemplateOptions +} + +// NewTemplateImpl creates a new TemplateImpl +func NewTemplateImpl(t *TemplateOptions) *TemplateImpl { + return &TemplateImpl{ + TemplateOptions: t, + } +} + +// Concurrency returns the concurrency +func (t *TemplateImpl) Concurrency() int { + return t.TemplateOptions.Concurrency +} + +// IncludeCRDs returns the include crds +func (t *TemplateImpl) IncludeCRDs() bool { + return t.TemplateOptions.IncludeCRDs +} + +// IncludeNeeds returns the include needs +func (t *TemplateImpl) IncludeNeeds() bool { + return t.TemplateOptions.IncludeNeeds || t.IncludeTransitiveNeeds() +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (t *TemplateImpl) IncludeTransitiveNeeds() bool { + return t.TemplateOptions.IncludeTransitiveNeeds +} + +// OutputDir returns the output dir +func (t *TemplateImpl) OutputDir() string { + return strings.TrimRight(t.TemplateOptions.OutputDir, fmt.Sprintf("%c", os.PathSeparator)) +} + +// OutputDirTemplate returns the output dir template +func (t *TemplateImpl) OutputDirTemplate() string { + return t.TemplateOptions.OutputDirTemplate +} + +// Set returns the Set +func (t *TemplateImpl) Set() []string { + return t.TemplateOptions.Set +} + +// SkipCleanup returns the skip cleanup +func (t *TemplateImpl) SkipCleanup() bool { + return t.TemplateOptions.SkipCleanup +} + +// SkipDeps returns the skip deps +func (t *TemplateImpl) SkipDeps() bool { + return t.TemplateOptions.SkipDeps +} + +// SkipNeeds returns the skip needs +func (t *TemplateImpl) SkipNeeds() bool { + if !t.IncludeNeeds() { + return t.TemplateOptions.SkipNeeds + } + + return false +} + +// SkipTests returns the skip tests +func (t *TemplateImpl) SkipTests() bool { + return t.TemplateOptions.SkipTests +} + +// Validate returns the validate +func (t *TemplateImpl) Validate() bool { + return t.TemplateOptions.Validate +} + +// Values returns the values +func (t *TemplateImpl) Values() []string { + return t.TemplateOptions.Values +} + +// PostRenderer returns the PostRenderer. +func (t *TemplateImpl) PostRenderer() string { + return t.TemplateOptions.PostRenderer +}