commit
f00a8194e0
|
|
@ -0,0 +1,28 @@
|
||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
GO_VERSION: 1.18
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.18
|
||||||
|
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Golangci lint
|
||||||
|
uses: golangci/golangci-lint-action@v3
|
||||||
|
with:
|
||||||
|
version: v1.46.2
|
||||||
|
|
@ -0,0 +1,352 @@
|
||||||
|
# This file contains all available configuration options
|
||||||
|
# with their default values.
|
||||||
|
|
||||||
|
# options for analysis running
|
||||||
|
run:
|
||||||
|
# default concurrency is a available CPU number
|
||||||
|
# concurrency: 4
|
||||||
|
|
||||||
|
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||||
|
timeout: 30m
|
||||||
|
|
||||||
|
# exit code when at least one issue was found, default is 1
|
||||||
|
issues-exit-code: 1
|
||||||
|
|
||||||
|
# include test files or not, default is true
|
||||||
|
tests: true
|
||||||
|
|
||||||
|
# list of build tags, all linters use it. Default is empty list.
|
||||||
|
# build-tags:
|
||||||
|
# - mytag
|
||||||
|
|
||||||
|
# which dirs to skip: issues from them won't be reported;
|
||||||
|
# can use regexp here: generated.*, regexp is applied on full path;
|
||||||
|
# default value is empty list, but default dirs are skipped independently
|
||||||
|
# from this option's value (see skip-dirs-use-default).
|
||||||
|
# skip-dirs:
|
||||||
|
# - src/external_libs
|
||||||
|
# - autogenerated_by_my_lib
|
||||||
|
|
||||||
|
# default is true. Enables skipping of directories:
|
||||||
|
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
|
||||||
|
skip-dirs-use-default: true
|
||||||
|
|
||||||
|
# which files to skip: they will be analyzed, but issues from them
|
||||||
|
# won't be reported. Default value is empty list, but there is
|
||||||
|
# no need to include all autogenerated files, we confidently recognize
|
||||||
|
# autogenerated files. If it's not please let us know.
|
||||||
|
# skip-files:
|
||||||
|
# - ".*\\.my\\.go$"
|
||||||
|
# - lib/bad.go
|
||||||
|
|
||||||
|
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
|
||||||
|
# If invoked with -mod=readonly, the go command is disallowed from the implicit
|
||||||
|
# automatic updating of go.mod described above. Instead, it fails when any changes
|
||||||
|
# to go.mod are needed. This setting is most useful to check that go.mod does
|
||||||
|
# not need updates, such as in a continuous integration and testing system.
|
||||||
|
# If invoked with -mod=vendor, the go command assumes that the vendor
|
||||||
|
# directory holds the correct copies of dependencies and ignores
|
||||||
|
# the dependency descriptions in go.mod.
|
||||||
|
# modules-download-mode: readonly|release|vendor
|
||||||
|
|
||||||
|
# output configuration options
|
||||||
|
output:
|
||||||
|
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
|
||||||
|
format: line-number
|
||||||
|
|
||||||
|
# print lines of code with issue, default is true
|
||||||
|
print-issued-lines: true
|
||||||
|
|
||||||
|
# print linter name in the end of issue text, default is true
|
||||||
|
print-linter-name: true
|
||||||
|
|
||||||
|
# all available settings of specific linters
|
||||||
|
linters-settings:
|
||||||
|
errcheck:
|
||||||
|
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
|
||||||
|
# default is false: such cases aren't reported by default.
|
||||||
|
check-type-assertions: false
|
||||||
|
|
||||||
|
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
|
||||||
|
# default is false: such cases aren't reported by default.
|
||||||
|
check-blank: false
|
||||||
|
|
||||||
|
# [deprecated] comma-separated list of pairs of the form pkg:regex
|
||||||
|
# the regex is used to ignore names within pkg. (default "fmt:.*").
|
||||||
|
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
|
||||||
|
# ignore: fmt:.*
|
||||||
|
|
||||||
|
# path to a file containing a list of functions to exclude from checking
|
||||||
|
# see https://github.com/kisielk/errcheck#excluding-functions for details
|
||||||
|
# exclude: /path/to/file.txt
|
||||||
|
|
||||||
|
# Disable error checking, as errorcheck detects more errors and is more configurable.
|
||||||
|
gosec:
|
||||||
|
exclude:
|
||||||
|
- "G104"
|
||||||
|
|
||||||
|
govet:
|
||||||
|
# report about shadowed variables
|
||||||
|
check-shadowing: false
|
||||||
|
|
||||||
|
# settings per analyzer
|
||||||
|
settings:
|
||||||
|
printf: # analyzer name, run `go tool vet help` to see all analyzers
|
||||||
|
funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer
|
||||||
|
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
|
||||||
|
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||||
|
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||||
|
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||||
|
|
||||||
|
# enable or disable analyzers by name
|
||||||
|
# enable:
|
||||||
|
# - atomicalign
|
||||||
|
# enable-all: false
|
||||||
|
# disable:
|
||||||
|
# - shadow
|
||||||
|
# disable-all: false
|
||||||
|
golint:
|
||||||
|
# minimal confidence for issues, default is 0.8
|
||||||
|
min-confidence: 0.8
|
||||||
|
gofmt:
|
||||||
|
# simplify code: gofmt with `-s` option, true by default
|
||||||
|
simplify: true
|
||||||
|
goimports:
|
||||||
|
# put imports beginning with prefix after 3rd-party packages;
|
||||||
|
# it's a comma-separated list of prefixes
|
||||||
|
# local-prefixes: github.com/org/project
|
||||||
|
gocyclo:
|
||||||
|
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||||
|
min-complexity: 30
|
||||||
|
gocognit:
|
||||||
|
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||||
|
min-complexity: 100
|
||||||
|
maligned:
|
||||||
|
# print struct with more effective memory layout or not, false by default
|
||||||
|
suggest-new: true
|
||||||
|
dupl:
|
||||||
|
# tokens count to trigger issue, 150 by default
|
||||||
|
threshold: 100
|
||||||
|
goconst:
|
||||||
|
# minimal length of string constant, 3 by default
|
||||||
|
min-len: 3
|
||||||
|
# minimal occurrences count to trigger, 3 by default
|
||||||
|
min-occurrences: 8
|
||||||
|
# depguard:
|
||||||
|
# list-type: blacklist
|
||||||
|
# include-go-root: false
|
||||||
|
# packages:
|
||||||
|
# - github.com/sirupsen/logrus
|
||||||
|
# packages-with-error-messages:
|
||||||
|
# # specify an error message to output when a blacklisted package is used
|
||||||
|
# github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
|
||||||
|
misspell:
|
||||||
|
# Correct spellings using locale preferences for US or UK.
|
||||||
|
# Default is to use a neutral variety of English.
|
||||||
|
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
|
||||||
|
locale: US
|
||||||
|
ignore-words:
|
||||||
|
- GitLab
|
||||||
|
lll:
|
||||||
|
# max line length, lines longer will be reported. Default is 120.
|
||||||
|
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
|
||||||
|
line-length: 120
|
||||||
|
# tab width in spaces. Default to 1.
|
||||||
|
tab-width: 1
|
||||||
|
unused:
|
||||||
|
# treat code as a program (not a library) and report unused exported identifiers; default is false.
|
||||||
|
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
|
||||||
|
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
|
||||||
|
# with golangci-lint call it on a directory with the changed file.
|
||||||
|
check-exported: false
|
||||||
|
unparam:
|
||||||
|
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
|
||||||
|
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
|
||||||
|
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
|
||||||
|
# with golangci-lint call it on a directory with the changed file.
|
||||||
|
check-exported: false
|
||||||
|
nakedret:
|
||||||
|
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
|
||||||
|
max-func-lines: 30
|
||||||
|
prealloc:
|
||||||
|
# XXX: we don't recommend using this linter before doing performance profiling.
|
||||||
|
# For most programs usage of prealloc will be a premature optimization.
|
||||||
|
|
||||||
|
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
|
||||||
|
# True by default.
|
||||||
|
simple: true
|
||||||
|
range-loops: true # Report preallocation suggestions on range loops, true by default
|
||||||
|
for-loops: false # Report preallocation suggestions on for loops, false by default
|
||||||
|
gocritic:
|
||||||
|
# Which checks should be enabled; can't be combined with 'disabled-checks';
|
||||||
|
# See https://go-critic.github.io/overview#checks-overview
|
||||||
|
# To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
|
||||||
|
# By default list of stable checks is used.
|
||||||
|
# enabled-checks:
|
||||||
|
# - rangeValCopy
|
||||||
|
|
||||||
|
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
|
||||||
|
# disabled-checks:
|
||||||
|
# - regexpMust
|
||||||
|
|
||||||
|
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
|
||||||
|
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
|
||||||
|
# enabled-tags:
|
||||||
|
# - performance
|
||||||
|
|
||||||
|
settings: # settings passed to gocritic
|
||||||
|
captLocal: # must be valid enabled check name
|
||||||
|
paramsOnly: true
|
||||||
|
# rangeValCopy:
|
||||||
|
# sizeThreshold: 32
|
||||||
|
godox:
|
||||||
|
# report any comments starting with keywords, this is useful for TODO or FIXME comments that
|
||||||
|
# might be left in the code accidentally and should be resolved before merging
|
||||||
|
keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
|
||||||
|
- TODO
|
||||||
|
- BUG
|
||||||
|
- FIXME
|
||||||
|
- NOTE
|
||||||
|
- OPTIMIZE # marks code that should be optimized before merging
|
||||||
|
- HACK # marks hack-arounds that should be removed before merging
|
||||||
|
dogsled:
|
||||||
|
# checks assignments with too many blank identifiers; default is 2
|
||||||
|
max-blank-identifiers: 2
|
||||||
|
|
||||||
|
whitespace:
|
||||||
|
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
|
||||||
|
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
|
||||||
|
wsl:
|
||||||
|
# If true append is only allowed to be cuddled if appending value is
|
||||||
|
# matching variables, fields or types on line above. Default is true.
|
||||||
|
strict-append: true
|
||||||
|
# Allow calls and assignments to be cuddled as long as the lines have any
|
||||||
|
# matching variables, fields or types. Default is true.
|
||||||
|
allow-assign-and-call: true
|
||||||
|
# Allow multiline assignments to be cuddled. Default is true.
|
||||||
|
allow-multiline-assign: true
|
||||||
|
# Allow declarations (var) to be cuddled.
|
||||||
|
allow-cuddle-declarations: false
|
||||||
|
# Allow trailing comments in ending of blocks
|
||||||
|
allow-trailing-comment: false
|
||||||
|
# Force newlines in end of case at this limit (0 = never).
|
||||||
|
force-case-trailing-whitespace: 0
|
||||||
|
revive:
|
||||||
|
ignore-generated-header: true
|
||||||
|
severity: warning
|
||||||
|
funlen:
|
||||||
|
# Checks the number of lines in a function.
|
||||||
|
# If lower than 0, disable the check.
|
||||||
|
# Default: 60
|
||||||
|
lines: 280
|
||||||
|
# Checks the number of statements in a function.
|
||||||
|
# If lower than 0, disable the check.
|
||||||
|
# Default: 40
|
||||||
|
statements: 140
|
||||||
|
|
||||||
|
linters:
|
||||||
|
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||||
|
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- depguard
|
||||||
|
# - dogsled
|
||||||
|
# - dupl
|
||||||
|
- errcheck
|
||||||
|
- funlen
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
# - gocritic
|
||||||
|
# - godox
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- revive
|
||||||
|
# - gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
# - interfacer
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- exportloopref
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
# - stylecheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
- whitespace
|
||||||
|
# don't enable:
|
||||||
|
# - deadcode
|
||||||
|
# - gochecknoglobals
|
||||||
|
# - gochecknoinits
|
||||||
|
# - gocyclo
|
||||||
|
# - lll
|
||||||
|
# - maligned
|
||||||
|
# - prealloc
|
||||||
|
# - varcheck
|
||||||
|
|
||||||
|
issues:
|
||||||
|
# List of regexps of issue texts to exclude, empty list by default.
|
||||||
|
# But independently from this option we use default exclude patterns,
|
||||||
|
# it can be disabled by `exclude-use-default: false`. To list all
|
||||||
|
# excluded by default patterns execute `golangci-lint run --help`
|
||||||
|
# exclude:
|
||||||
|
# - abcdef
|
||||||
|
|
||||||
|
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||||
|
exclude-rules:
|
||||||
|
# Exclude some linters from running on tests files.
|
||||||
|
- path: _test\.go
|
||||||
|
linters:
|
||||||
|
- gocyclo
|
||||||
|
- errcheck
|
||||||
|
- dupl
|
||||||
|
- gosec
|
||||||
|
- funlen
|
||||||
|
|
||||||
|
# Exclude known linters from partially hard-vendored code,
|
||||||
|
# which is impossible to exclude via "nolint" comments.
|
||||||
|
# - path: internal/hmac/
|
||||||
|
# text: "weak cryptographic primitive"
|
||||||
|
# linters:
|
||||||
|
# - gosec
|
||||||
|
|
||||||
|
# Exclude some staticcheck messages
|
||||||
|
# - linters:
|
||||||
|
# - staticcheck
|
||||||
|
# text: "SA9003:"
|
||||||
|
|
||||||
|
# Exclude lll issues for long lines with go:generate
|
||||||
|
- linters:
|
||||||
|
- lll
|
||||||
|
source: "^//go:generate "
|
||||||
|
|
||||||
|
# Independently from option `exclude` we use default exclude patterns,
|
||||||
|
# it can be disabled by this option. To list all
|
||||||
|
# excluded by default patterns execute `golangci-lint run --help`.
|
||||||
|
# Default value for this option is true.
|
||||||
|
exclude-use-default: false
|
||||||
|
|
||||||
|
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
|
||||||
|
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||||
|
max-same-issues: 0
|
||||||
|
|
||||||
|
# Show only new issues: if there are unstaged changes or untracked files,
|
||||||
|
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
|
||||||
|
# It's a super-useful option for integration of golangci-lint into existing
|
||||||
|
# large codebase. It's not practical to fix all existing issues at the moment
|
||||||
|
# of integration: much better don't allow issues in new code.
|
||||||
|
# Default is false.
|
||||||
|
new: false
|
||||||
|
|
||||||
|
# Show only new issues created after git revision `REV`
|
||||||
|
# This should be passed as flag during individual CI jobs.
|
||||||
|
# new-from-rev: REV
|
||||||
|
|
||||||
|
# Show only new issues created in git patch with set file path.
|
||||||
|
# new-from-patch: path/to/patch/file
|
||||||
|
|
@ -26,7 +26,7 @@ func addApplySubcommand(cliApp *cli.App) {
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "validate",
|
Name: "validate",
|
||||||
Usage: "validate your manifests against the Kubernetes cluster you are currently pointing at. Note that this requiers access to a Kubernetes cluster to obtain information necessary for validating, like the list of available API versions",
|
Usage: "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 list of available API versions",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
Name: "context",
|
Name: "context",
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func addDiffSubcommand(cliApp *cli.App) {
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "validate",
|
Name: "validate",
|
||||||
Usage: "validate your manifests against the Kubernetes cluster you are currently pointing at. Note that this requiers access to a Kubernetes cluster to obtain information necessary for validating, like the list of available API versions",
|
Usage: "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 list of available API versions",
|
||||||
},
|
},
|
||||||
|
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,6 @@ func setRootCommandFlags(cliApp *cli.App) {
|
||||||
Usage: "Request confirmation before attempting to modify clusters",
|
Usage: "Request confirmation before attempting to modify clusters",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCliError(c *cli.Context, err error) error {
|
func toCliError(c *cli.Context, err error) error {
|
||||||
|
|
@ -153,7 +152,7 @@ func configureLogging(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
logger = helmexec.NewLogger(os.Stderr, logLevel)
|
logger = helmexec.NewLogger(os.Stderr, logLevel)
|
||||||
if c.App.Metadata == nil {
|
if c.App.Metadata == nil {
|
||||||
// Auto-initialised in 1.19.0
|
// Auto-initialized in 1.19.0
|
||||||
// https://github.com/urfave/cli/blob/master/CHANGELOG.md#1190---2016-11-19
|
// https://github.com/urfave/cli/blob/master/CHANGELOG.md#1190---2016-11-19
|
||||||
c.App.Metadata = make(map[string]interface{})
|
c.App.Metadata = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func addSyncSubcommand(cliApp *cli.App) {
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "validate",
|
Name: "validate",
|
||||||
Usage: `ADVANCED CONFIGURATION: When sync is going to involve helm-template as a part of the "chartify" process, it might fail due to missing .Capabilities. This flag makes instructs helmfile to pass --validate to helm-template so it populates .Capabilities and validates your manifests against the Kubernetes cluster you are currently pointing at. Note that this requiers access to a Kubernetes cluster to obtain information necessary for validating, like the list of available API versions`,
|
Usage: `ADVANCED CONFIGURATION: When sync is going to involve helm-template as a part of the "chartify" process, it might fail due to missing .Capabilities. This flag makes instructs helmfile to pass --validate to helm-template so it populates .Capabilities and validates 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 list of available API versions`,
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "wait",
|
Name: "wait",
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func addTemplateSubcommand(cliApp *cli.App) {
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "validate",
|
Name: "validate",
|
||||||
Usage: "validate your manifests against the Kubernetes cluster you are currently pointing at. Note that this requiers access to a Kubernetes cluster to obtain information necessary for validating, like the list of available API versions",
|
Usage: "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 list of available API versions",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "include-crds",
|
Name: "include-crds",
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -30,6 +30,7 @@ require (
|
||||||
go.uber.org/multierr v1.6.0
|
go.uber.org/multierr v1.6.0
|
||||||
go.uber.org/zap v1.21.0
|
go.uber.org/zap v1.21.0
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
k8s.io/apimachinery v0.23.4
|
k8s.io/apimachinery v0.23.4
|
||||||
)
|
)
|
||||||
|
|
@ -123,7 +124,6 @@ require (
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect
|
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
|
@ -146,5 +146,5 @@ require (
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||||
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c // indirect
|
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c // indirect
|
||||||
github.com/pierrec/lz4 v2.3.0+incompatible // indirect
|
github.com/pierrec/lz4 v2.3.0+incompatible // indirect
|
||||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
1
main.go
1
main.go
|
|
@ -8,7 +8,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
rootCmd := cmd.RootCommand()
|
rootCmd := cmd.RootCommand()
|
||||||
err := rootCmd.Run(os.Args)
|
err := rootCmd.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// App is the main application object.
|
||||||
type App struct {
|
type App struct {
|
||||||
OverrideKubeContext string
|
OverrideKubeContext string
|
||||||
OverrideHelmBinary string
|
OverrideHelmBinary string
|
||||||
|
|
@ -552,8 +553,7 @@ func (a *App) ListReleases(c ListConfigProvider) error {
|
||||||
SkipRepos: true,
|
SkipRepos: true,
|
||||||
SkipDeps: true,
|
SkipDeps: true,
|
||||||
}, func() {
|
}, func() {
|
||||||
|
// var releases m
|
||||||
//var releases m
|
|
||||||
for _, r := range run.state.Releases {
|
for _, r := range run.state.Releases {
|
||||||
labels := ""
|
labels := ""
|
||||||
if r.Labels == nil {
|
if r.Labels == nil {
|
||||||
|
|
@ -805,7 +805,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
|
||||||
Reverse: defOpts.Reverse,
|
Reverse: defOpts.Reverse,
|
||||||
RetainValuesFiles: defOpts.RetainValuesFiles,
|
RetainValuesFiles: defOpts.RetainValuesFiles,
|
||||||
}
|
}
|
||||||
//assign parent selector to sub helm selector in legacy mode or do not inherit in experimental mode
|
// assign parent selector to sub helm selector in legacy mode or do not inherit in experimental mode
|
||||||
if (m.Selectors == nil && !isExplicitSelectorInheritanceEnabled()) || m.SelectorsInherited {
|
if (m.Selectors == nil && !isExplicitSelectorInheritanceEnabled()) || m.SelectorsInherited {
|
||||||
optsForNestedState.Selectors = opts.Selectors
|
optsForNestedState.Selectors = opts.Selectors
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -915,7 +915,7 @@ func printBatches(batches [][]state.Release) string {
|
||||||
fmt.Fprintf(w, "%d\t%s\n", i+1, strings.Join(ids, ", "))
|
fmt.Fprintf(w, "%d\t%s\n", i+1, strings.Join(ids, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Flush()
|
_ = w.Flush()
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
@ -1092,11 +1092,12 @@ func (a *App) findDesiredStateFiles(specifiedPath string, opts LoadOpts) ([]stri
|
||||||
|
|
||||||
var helmfileDir string
|
var helmfileDir string
|
||||||
if specifiedPath != "" {
|
if specifiedPath != "" {
|
||||||
if a.fileExistsAt(specifiedPath) {
|
switch {
|
||||||
|
case a.fileExistsAt(specifiedPath):
|
||||||
return []string{specifiedPath}, nil
|
return []string{specifiedPath}, nil
|
||||||
} else if a.directoryExistsAt(specifiedPath) {
|
case a.directoryExistsAt(specifiedPath):
|
||||||
helmfileDir = specifiedPath
|
helmfileDir = specifiedPath
|
||||||
} else {
|
default:
|
||||||
return []string{}, fmt.Errorf("specified state file %s is not found", specifiedPath)
|
return []string{}, fmt.Errorf("specified state file %s is not found", specifiedPath)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1113,15 +1114,16 @@ func (a *App) findDesiredStateFiles(specifiedPath string, opts LoadOpts) ([]stri
|
||||||
defaultFile = DeprecatedHelmfile
|
defaultFile = DeprecatedHelmfile
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.directoryExistsAt(DefaultHelmfileDirectory) {
|
switch {
|
||||||
|
case a.directoryExistsAt(DefaultHelmfileDirectory):
|
||||||
if defaultFile != "" {
|
if defaultFile != "" {
|
||||||
return []string{}, fmt.Errorf("configuration conlict error: you can have either %s or %s, but not both", defaultFile, DefaultHelmfileDirectory)
|
return []string{}, fmt.Errorf("configuration conlict error: you can have either %s or %s, but not both", defaultFile, DefaultHelmfileDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
helmfileDir = DefaultHelmfileDirectory
|
helmfileDir = DefaultHelmfileDirectory
|
||||||
} else if defaultFile != "" {
|
case defaultFile != "":
|
||||||
return []string{defaultFile}, nil
|
return []string{defaultFile}, nil
|
||||||
} else {
|
default:
|
||||||
return []string{}, fmt.Errorf("no state file found. It must be named %s/*.{yaml,yml} or %s, otherwise specified with the --file flag", DefaultHelmfileDirectory, DefaultHelmfile)
|
return []string{}, fmt.Errorf("no state file found. It must be named %s/*.{yaml,yml} or %s, otherwise specified with the --file flag", DefaultHelmfileDirectory, DefaultHelmfile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1944,6 +1946,7 @@ func directoryExistsAt(path string) bool {
|
||||||
return err == nil && fileInfo.Mode().IsDir()
|
return err == nil && fileInfo.Mode().IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error is a wrapper around an error that adds context to the error.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
msg string
|
msg string
|
||||||
|
|
||||||
|
|
@ -2084,7 +2087,10 @@ func (a *App) CleanCacheDir(c ListConfigProvider) error {
|
||||||
}
|
}
|
||||||
for _, e := range dirs {
|
for _, e := range dirs {
|
||||||
fmt.Printf("- %s\n", e.Name())
|
fmt.Printf("- %s\n", e.Name())
|
||||||
os.RemoveAll(filepath.Join(remote.CacheDir(), e.Name()))
|
err := os.RemoveAll(filepath.Join(remote.CacheDir(), e.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -1275,7 +1275,7 @@ foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("select non existant release with --allow-no-matching-release", func(t *testing.T) {
|
t.Run("select non existent release with --allow-no-matching-release", func(t *testing.T) {
|
||||||
check(t, testcase{
|
check(t, testcase{
|
||||||
files: map[string]string{
|
files: map[string]string{
|
||||||
"/path/to/helmfile.yaml": `
|
"/path/to/helmfile.yaml": `
|
||||||
|
|
|
||||||
|
|
@ -612,7 +612,7 @@ releases:
|
||||||
whatever: yes
|
whatever: yes
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
//Check with legacy behavior, that is when no explicit selector then sub-helmfiles inherits from command line selector
|
// Check with legacy behavior, that is when no explicit selector then sub-helmfiles inherits from command line selector
|
||||||
legacyTestcases := []struct {
|
legacyTestcases := []struct {
|
||||||
label string
|
label string
|
||||||
expectedReleases []string
|
expectedReleases []string
|
||||||
|
|
@ -626,7 +626,7 @@ releases:
|
||||||
}
|
}
|
||||||
runFilterSubHelmFilesTests(legacyTestcases, files, t, "1st EmbeddedSelectors")
|
runFilterSubHelmFilesTests(legacyTestcases, files, t, "1st EmbeddedSelectors")
|
||||||
|
|
||||||
//Check with experimental behavior, that is when no explicit selector then sub-helmfiles do no inherit from any selector
|
// Check with experimental behavior, that is when no explicit selector then sub-helmfiles do no inherit from any selector
|
||||||
desiredTestcases := []struct {
|
desiredTestcases := []struct {
|
||||||
label string
|
label string
|
||||||
expectedReleases []string
|
expectedReleases []string
|
||||||
|
|
@ -640,7 +640,6 @@ releases:
|
||||||
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
||||||
|
|
||||||
runFilterSubHelmFilesTests(desiredTestcases, files, t, "2nd EmbeddedSelectors")
|
runFilterSubHelmFilesTests(desiredTestcases, files, t, "2nd EmbeddedSelectors")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVisitDesiredStatesWithReleasesFiltered_InheritedSelectors_3leveldeep(t *testing.T) {
|
func TestVisitDesiredStatesWithReleasesFiltered_InheritedSelectors_3leveldeep(t *testing.T) {
|
||||||
|
|
@ -665,7 +664,7 @@ releases:
|
||||||
chart: stable/grafana
|
chart: stable/grafana
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
//Check with legacy behavior, that is when no explicit selector then sub-helmfiles inherits from command line selector
|
// Check with legacy behavior, that is when no explicit selector then sub-helmfiles inherits from command line selector
|
||||||
legacyTestcases := []struct {
|
legacyTestcases := []struct {
|
||||||
label string
|
label string
|
||||||
expectedReleases []string
|
expectedReleases []string
|
||||||
|
|
@ -676,7 +675,7 @@ releases:
|
||||||
}
|
}
|
||||||
runFilterSubHelmFilesTests(legacyTestcases, files, t, "1st 3leveldeep")
|
runFilterSubHelmFilesTests(legacyTestcases, files, t, "1st 3leveldeep")
|
||||||
|
|
||||||
//Check with experimental behavior, that is when no explicit selector then sub-helmfiles do no inherit from any selector
|
// Check with experimental behavior, that is when no explicit selector then sub-helmfiles do no inherit from any selector
|
||||||
desiredTestcases := []struct {
|
desiredTestcases := []struct {
|
||||||
label string
|
label string
|
||||||
expectedReleases []string
|
expectedReleases []string
|
||||||
|
|
@ -689,7 +688,6 @@ releases:
|
||||||
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
||||||
|
|
||||||
runFilterSubHelmFilesTests(desiredTestcases, files, t, "2nd 3leveldeep")
|
runFilterSubHelmFilesTests(desiredTestcases, files, t, "2nd 3leveldeep")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVisitDesiredStatesWithReleasesFiltered_InheritedSelectors_inherits(t *testing.T) {
|
func TestVisitDesiredStatesWithReleasesFiltered_InheritedSelectors_inherits(t *testing.T) {
|
||||||
|
|
@ -724,7 +722,7 @@ releases:
|
||||||
select: foo
|
select: foo
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
//Check with legacy behavior, that is when no explicit selector then sub-helmfiles inherits from command line selector
|
// Check with legacy behavior, that is when no explicit selector then sub-helmfiles inherits from command line selector
|
||||||
legacyTestcases := []struct {
|
legacyTestcases := []struct {
|
||||||
label string
|
label string
|
||||||
expectedReleases []string
|
expectedReleases []string
|
||||||
|
|
@ -736,7 +734,7 @@ releases:
|
||||||
}
|
}
|
||||||
runFilterSubHelmFilesTests(legacyTestcases, files, t, "1st inherits")
|
runFilterSubHelmFilesTests(legacyTestcases, files, t, "1st inherits")
|
||||||
|
|
||||||
//Check with experimental behavior, that is when no explicit selector then sub-helmfiles do no inherit from any selector
|
// Check with experimental behavior, that is when no explicit selector then sub-helmfiles do no inherit from any selector
|
||||||
desiredTestcases := []struct {
|
desiredTestcases := []struct {
|
||||||
label string
|
label string
|
||||||
expectedReleases []string
|
expectedReleases []string
|
||||||
|
|
@ -750,7 +748,6 @@ releases:
|
||||||
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
||||||
|
|
||||||
runFilterSubHelmFilesTests(desiredTestcases, files, t, "2nd inherits")
|
runFilterSubHelmFilesTests(desiredTestcases, files, t, "2nd inherits")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFilterSubHelmFilesTests(testcases []struct {
|
func runFilterSubHelmFilesTests(testcases []struct {
|
||||||
|
|
@ -801,7 +798,6 @@ func runFilterSubHelmFilesTests(testcases []struct {
|
||||||
t.Errorf("[%s]unexpected releases for selector %s: expected=%v, actual=%v", testName, testcase.label, testcase.expectedReleases, actual)
|
t.Errorf("[%s]unexpected releases for selector %s: expected=%v, actual=%v", testName, testcase.label, testcase.expectedReleases, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVisitDesiredStatesWithReleasesFiltered_EmbeddedNestedStateAdditionalEnvValues(t *testing.T) {
|
func TestVisitDesiredStatesWithReleasesFiltered_EmbeddedNestedStateAdditionalEnvValues(t *testing.T) {
|
||||||
|
|
@ -2257,8 +2253,8 @@ type configImpl struct {
|
||||||
includeTransitiveNeeds bool
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a configImpl) Selectors() []string {
|
func (c configImpl) Selectors() []string {
|
||||||
return a.selectors
|
return c.selectors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c configImpl) Set() []string {
|
func (c configImpl) Set() []string {
|
||||||
|
|
@ -2399,16 +2395,16 @@ func (a applyConfig) SkipDeps() bool {
|
||||||
return a.skipDeps
|
return a.skipDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c applyConfig) SkipNeeds() bool {
|
func (a applyConfig) SkipNeeds() bool {
|
||||||
return c.skipNeeds
|
return a.skipNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c applyConfig) IncludeNeeds() bool {
|
func (a applyConfig) IncludeNeeds() bool {
|
||||||
return c.includeNeeds
|
return a.includeNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c applyConfig) IncludeTransitiveNeeds() bool {
|
func (a applyConfig) IncludeTransitiveNeeds() bool {
|
||||||
return c.includeTransitiveNeeds
|
return a.includeTransitiveNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) IncludeTests() bool {
|
func (a applyConfig) IncludeTests() bool {
|
||||||
|
|
@ -2765,7 +2761,6 @@ releases:
|
||||||
t.Errorf("HelmState.TemplateReleases() = [%v], want %v", helm.templated[i].flags[j], wantReleases[i].flags[j])
|
t.Errorf("HelmState.TemplateReleases() = [%v], want %v", helm.templated[i].flags[j], wantReleases[i].flags[j])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4312,11 +4307,12 @@ changing working directory back to "/path/to"
|
||||||
skipDiffOnInstall: tc.skipDiffOnInstall,
|
skipDiffOnInstall: tc.skipDiffOnInstall,
|
||||||
skipNeeds: tc.fields.skipNeeds,
|
skipNeeds: tc.fields.skipNeeds,
|
||||||
})
|
})
|
||||||
if tc.error == "" && applyErr != nil {
|
switch {
|
||||||
|
case tc.error == "" && applyErr != nil:
|
||||||
t.Fatalf("unexpected error for data defined at %s: %v", tc.loc, applyErr)
|
t.Fatalf("unexpected error for data defined at %s: %v", tc.loc, applyErr)
|
||||||
} else if tc.error != "" && applyErr == nil {
|
case tc.error != "" && applyErr == nil:
|
||||||
t.Fatalf("expected error did not occur for data defined at %s", tc.loc)
|
t.Fatalf("expected error did not occur for data defined at %s", tc.loc)
|
||||||
} else if tc.error != "" && applyErr != nil && tc.error != applyErr.Error() {
|
case tc.error != "" && applyErr != nil && tc.error != applyErr.Error():
|
||||||
t.Fatalf("invalid error: expected %q, got %q", tc.error, applyErr.Error())
|
t.Fatalf("invalid error: expected %q, got %q", tc.error, applyErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4433,7 +4429,6 @@ changing working directory back to "/path/to"
|
||||||
for i := range testcases {
|
for i := range testcases {
|
||||||
tc := testcases[i]
|
tc := testcases[i]
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
||||||
var helm = &exectest.Helm{
|
var helm = &exectest.Helm{
|
||||||
DiffMutex: &sync.Mutex{},
|
DiffMutex: &sync.Mutex{},
|
||||||
ChartsMutex: &sync.Mutex{},
|
ChartsMutex: &sync.Mutex{},
|
||||||
|
|
@ -4483,12 +4478,12 @@ changing working directory back to "/path/to"
|
||||||
skipRepos: false,
|
skipRepos: false,
|
||||||
includeTransitiveNeeds: false,
|
includeTransitiveNeeds: false,
|
||||||
})
|
})
|
||||||
|
switch {
|
||||||
if tc.error == "" && depsErr != nil {
|
case tc.error == "" && depsErr != nil:
|
||||||
t.Fatalf("unexpected error for data defined at %s: %v", tc.loc, depsErr)
|
t.Fatalf("unexpected error for data defined at %s: %v", tc.loc, depsErr)
|
||||||
} else if tc.error != "" && depsErr == nil {
|
case tc.error != "" && depsErr == nil:
|
||||||
t.Fatalf("expected error did not occur for data defined at %s", tc.loc)
|
t.Fatalf("expected error did not occur for data defined at %s", tc.loc)
|
||||||
} else if tc.error != "" && depsErr != nil && tc.error != depsErr.Error() {
|
case tc.error != "" && depsErr != nil && tc.error != depsErr.Error():
|
||||||
t.Fatalf("invalid error: expected %q, got %q", tc.error, depsErr.Error())
|
t.Fatalf("invalid error: expected %q, got %q", tc.error, depsErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,19 @@ import (
|
||||||
|
|
||||||
// TestIsExplicitSelectorInheritanceEnabled tests the isExplicitSelectorInheritanceEnabled function
|
// TestIsExplicitSelectorInheritanceEnabled tests the isExplicitSelectorInheritanceEnabled function
|
||||||
func TestIsExplicitSelectorInheritanceEnabled(t *testing.T) {
|
func TestIsExplicitSelectorInheritanceEnabled(t *testing.T) {
|
||||||
//env var ExperimentalEnvVar is not set
|
// env var ExperimentalEnvVar is not set
|
||||||
require.Empty(t, os.Getenv(envvar.Experimental))
|
require.Empty(t, os.Getenv(envvar.Experimental))
|
||||||
require.False(t, isExplicitSelectorInheritanceEnabled())
|
require.False(t, isExplicitSelectorInheritanceEnabled())
|
||||||
|
|
||||||
//check for env var ExperimentalEnvVar set to true
|
// check for env var ExperimentalEnvVar set to true
|
||||||
t.Setenv(envvar.Experimental, "true")
|
t.Setenv(envvar.Experimental, "true")
|
||||||
require.True(t, isExplicitSelectorInheritanceEnabled())
|
require.True(t, isExplicitSelectorInheritanceEnabled())
|
||||||
|
|
||||||
//check for env var ExperimentalEnvVar set to anything
|
// check for env var ExperimentalEnvVar set to anything
|
||||||
t.Setenv(envvar.Experimental, "anything")
|
t.Setenv(envvar.Experimental, "anything")
|
||||||
require.False(t, isExplicitSelectorInheritanceEnabled())
|
require.False(t, isExplicitSelectorInheritanceEnabled())
|
||||||
|
|
||||||
//check for env var ExperimentalEnvVar set to ExperimentalSelectorExplicit
|
// check for env var ExperimentalEnvVar set to ExperimentalSelectorExplicit
|
||||||
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
t.Setenv(envvar.Experimental, ExperimentalSelectorExplicit)
|
||||||
require.True(t, isExplicitSelectorInheritanceEnabled())
|
require.True(t, isExplicitSelectorInheritanceEnabled())
|
||||||
|
|
||||||
|
|
@ -34,15 +34,15 @@ func TestIsExplicitSelectorInheritanceEnabled(t *testing.T) {
|
||||||
|
|
||||||
// TestExperimentalModeEnabled tests the experimentalModeEnabled function
|
// TestExperimentalModeEnabled tests the experimentalModeEnabled function
|
||||||
func TestExperimentalModeEnabled(t *testing.T) {
|
func TestExperimentalModeEnabled(t *testing.T) {
|
||||||
//env var ExperimentalEnvVar is not set
|
// env var ExperimentalEnvVar is not set
|
||||||
require.Empty(t, os.Getenv(envvar.Experimental))
|
require.Empty(t, os.Getenv(envvar.Experimental))
|
||||||
require.False(t, experimentalModeEnabled())
|
require.False(t, experimentalModeEnabled())
|
||||||
|
|
||||||
//check for env var ExperimentalEnvVar set to anything
|
// check for env var ExperimentalEnvVar set to anything
|
||||||
t.Setenv(envvar.Experimental, "anything")
|
t.Setenv(envvar.Experimental, "anything")
|
||||||
require.False(t, experimentalModeEnabled())
|
require.False(t, experimentalModeEnabled())
|
||||||
|
|
||||||
//check for env var ExperimentalEnvVar set to true
|
// check for env var ExperimentalEnvVar set to true
|
||||||
t.Setenv(envvar.Experimental, "true")
|
t.Setenv(envvar.Experimental, "true")
|
||||||
require.True(t, experimentalModeEnabled())
|
require.True(t, experimentalModeEnabled())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ func (ld *desiredStateLoader) Load(f string, opts LoadOpts) (*state.HelmState, e
|
||||||
return nil, errors.New("err: Cannot use option --kube-context and set attribute kubeContext.")
|
return nil, errors.New("err: Cannot use option --kube-context and set attribute kubeContext.")
|
||||||
}
|
}
|
||||||
st.OverrideKubeContext = ld.overrideKubeContext
|
st.OverrideKubeContext = ld.overrideKubeContext
|
||||||
// HelmDefaults.KubeContext is also overriden in here
|
// HelmDefaults.KubeContext is also overridden in here
|
||||||
// to set default release value properly.
|
// to set default release value properly.
|
||||||
st.HelmDefaults.KubeContext = ld.overrideKubeContext
|
st.HelmDefaults.KubeContext = ld.overrideKubeContext
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,11 +108,12 @@ func TestDestroy_2(t *testing.T) {
|
||||||
includeTransitiveNeeds: false,
|
includeTransitiveNeeds: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
if tc.error == "" && destroyErr != nil {
|
switch {
|
||||||
|
case tc.error == "" && destroyErr != nil:
|
||||||
t.Fatalf("unexpected error: %v", destroyErr)
|
t.Fatalf("unexpected error: %v", destroyErr)
|
||||||
} else if tc.error != "" && destroyErr == nil {
|
case tc.error != "" && destroyErr == nil:
|
||||||
t.Fatal("expected error did not occur")
|
t.Fatal("expected error did not occur")
|
||||||
} else if tc.error != "" && destroyErr != nil && tc.error != destroyErr.Error() {
|
case tc.error != "" && destroyErr != nil && tc.error != destroyErr.Error():
|
||||||
t.Fatalf("invalid error: expected %q, got %q", tc.error, destroyErr.Error())
|
t.Fatalf("invalid error: expected %q, got %q", tc.error, destroyErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,11 +148,12 @@ func TestDestroy(t *testing.T) {
|
||||||
logger: logger,
|
logger: logger,
|
||||||
})
|
})
|
||||||
|
|
||||||
if tc.error == "" && destroyErr != nil {
|
switch {
|
||||||
|
case tc.error == "" && destroyErr != nil:
|
||||||
t.Fatalf("unexpected error: %v", destroyErr)
|
t.Fatalf("unexpected error: %v", destroyErr)
|
||||||
} else if tc.error != "" && destroyErr == nil {
|
case tc.error != "" && destroyErr == nil:
|
||||||
t.Fatal("expected error did not occur")
|
t.Fatal("expected error did not occur")
|
||||||
} else if tc.error != "" && destroyErr != nil && tc.error != destroyErr.Error() {
|
case tc.error != "" && destroyErr != nil && tc.error != destroyErr.Error():
|
||||||
t.Fatalf("invalid error: expected %q, got %q", tc.error, destroyErr.Error())
|
t.Fatalf("invalid error: expected %q, got %q", tc.error, destroyErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
// TestFormatAsTable tests the FormatAsTable function.
|
// TestFormatAsTable tests the FormatAsTable function.
|
||||||
func TestFormatAsTable(t *testing.T) {
|
func TestFormatAsTable(t *testing.T) {
|
||||||
|
|
||||||
h := []*HelmRelease{
|
h := []*HelmRelease{
|
||||||
{
|
{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
|
|
@ -78,5 +77,4 @@ func TestFormatAsJson(t *testing.T) {
|
||||||
if result != string(expectd) {
|
if result != string(expectd) {
|
||||||
t.Errorf("FormatAsJson() = %v, want %v", result, string(expectd))
|
t.Errorf("FormatAsJson() = %v, want %v", result, string(expectd))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,4 @@ func TestLoadOptsDeepCopy(t *testing.T) {
|
||||||
|
|
||||||
// Check that the new struct is not the same as the old one.
|
// Check that the new struct is not the same as the old one.
|
||||||
require.Equal(t, lOld, lNew, "DeepCopy should return a copy of the LoadOpts struct")
|
require.Equal(t, lOld, lNew, "DeepCopy should return a copy of the LoadOpts struct")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,9 @@ func (r *Run) withPreparedCharts(helmfileCommand string, opts state.ChartPrepare
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tempDir)
|
defer func() {
|
||||||
|
_ = os.RemoveAll(tempDir)
|
||||||
|
}()
|
||||||
dir = tempDir
|
dir = tempDir
|
||||||
} else {
|
} else {
|
||||||
dir = opts.OutputDir
|
dir = opts.OutputDir
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,7 @@ func (r *desiredStateLoader) renderPrestate(firstPassEnv *environment.Environmen
|
||||||
// create preliminary state, as we may have an environment. Tolerate errors.
|
// create preliminary state, as we may have an environment. Tolerate errors.
|
||||||
prestate, err := c.ParseAndLoad([]byte(sanitized), baseDir, filename, r.env, false, firstPassEnv)
|
prestate, err := c.ParseAndLoad([]byte(sanitized), baseDir, filename, r.env, false, firstPassEnv)
|
||||||
if err != nil && r.logger != nil {
|
if err != nil && r.logger != nil {
|
||||||
switch err.(type) {
|
if _, ok := err.(*state.StateLoadError); ok {
|
||||||
case *state.StateLoadError:
|
|
||||||
r.logger.Debugf("could not deduce `environment:` block, configuring only .Environment.Name. error: %v", err)
|
r.logger.Debugf("could not deduce `environment:` block, configuring only .Environment.Name. error: %v", err)
|
||||||
}
|
}
|
||||||
r.logger.Debugf("error in first-pass rendering: result of \"%s\":\n%s", filename, prependLineNumbers(yamlBuf.String()))
|
r.logger.Debugf("error in first-pass rendering: result of \"%s\":\n%s", filename, prependLineNumbers(yamlBuf.String()))
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ func makeLoader(files map[string]string, env string) (*desiredStateLoader, *test
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadFromYaml_MakeEnvironmentHasNoSideEffects(t *testing.T) {
|
func TestReadFromYaml_MakeEnvironmentHasNoSideEffects(t *testing.T) {
|
||||||
|
|
||||||
yamlContent := []byte(`
|
yamlContent := []byte(`
|
||||||
environments:
|
environments:
|
||||||
staging:
|
staging:
|
||||||
|
|
@ -71,7 +70,6 @@ releases:
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadFromYaml_RenderTemplate(t *testing.T) {
|
func TestReadFromYaml_RenderTemplate(t *testing.T) {
|
||||||
|
|
||||||
defaultValuesYaml := `
|
defaultValuesYaml := `
|
||||||
releaseName: "hello"
|
releaseName: "hello"
|
||||||
conditionalReleaseTag: "yes"
|
conditionalReleaseTag: "yes"
|
||||||
|
|
@ -159,7 +157,6 @@ releases:
|
||||||
// even if the pre-render disables the readFile and exec functions.
|
// even if the pre-render disables the readFile and exec functions.
|
||||||
// This does not apply to .gotmpl files, which is a nice side-effect.
|
// This does not apply to .gotmpl files, which is a nice side-effect.
|
||||||
func TestReadFromYaml_RenderTemplateWithGotmpl(t *testing.T) {
|
func TestReadFromYaml_RenderTemplateWithGotmpl(t *testing.T) {
|
||||||
|
|
||||||
defaultValuesYamlGotmpl := `
|
defaultValuesYamlGotmpl := `
|
||||||
releaseName: {{ readFile "nonIgnoredFile" }}
|
releaseName: {{ readFile "nonIgnoredFile" }}
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package app
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
// ValidateConfig validates the given Helmfile config.
|
||||||
func ValidateConfig(conf ApplyConfigProvider) error {
|
func ValidateConfig(conf ApplyConfigProvider) error {
|
||||||
if conf.NoColor() && conf.Color() {
|
if conf.NoColor() && conf.Color() {
|
||||||
return errors.New("--color and --no-color cannot be specified at the same time")
|
return errors.New("--color and --no-color cannot be specified at the same time")
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Package version is used to get the version of the Helmfile CLI.
|
||||||
package version
|
package version
|
||||||
|
|
||||||
|
// Version is the version of Helmfile
|
||||||
var Version string
|
var Version string
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func GetArgs(args string, state *state.HelmState) []string {
|
||||||
value := argVal[1]
|
value := argVal[1]
|
||||||
argsMap.SetArg(arg, value, false)
|
argsMap.SetArg(arg, value, false)
|
||||||
} else {
|
} else {
|
||||||
//check if next value is arg to flag
|
// check if next value is arg to flag
|
||||||
if index+1 < len(argsVals) {
|
if index+1 < len(argsVals) {
|
||||||
nextVal := argsVals[index+1]
|
nextVal := argsVals[index+1]
|
||||||
if strings.HasPrefix(nextVal, "--") {
|
if strings.HasPrefix(nextVal, "--") {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import (
|
||||||
|
|
||||||
// TestGetArgs tests the GetArgs function
|
// TestGetArgs tests the GetArgs function
|
||||||
func TestGetArgs(t *testing.T) {
|
func TestGetArgs(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
args string
|
args string
|
||||||
expected string
|
expected string
|
||||||
|
|
@ -86,6 +85,5 @@ func TestSetArg(t *testing.T) {
|
||||||
require.NotContainsf(t, ap.flags, test.flag, "expected flag %s to be not set", test.flag)
|
require.NotContainsf(t, ap.flags, test.flag, "expected flag %s to be not set", test.flag)
|
||||||
require.NotContainsf(t, ap.m, test.flag, "expected m %s to be not set", test.flag)
|
require.NotContainsf(t, ap.m, test.flag, "expected m %s to be not set", test.flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,10 @@ import (
|
||||||
"github.com/helmfile/helmfile/pkg/state"
|
"github.com/helmfile/helmfile/pkg/state"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
type ConfigImpl struct {
|
type ConfigImpl struct {
|
||||||
c *cli.Context
|
c *cli.Context
|
||||||
|
|
||||||
|
|
@ -239,10 +240,10 @@ func (c ConfigImpl) Color() bool {
|
||||||
// we can't rely on helm-diff's ability to auto-detect term for color output.
|
// we can't rely on helm-diff's ability to auto-detect term for color output.
|
||||||
// See https://github.com/roboll/helmfile/issues/2043
|
// See https://github.com/roboll/helmfile/issues/2043
|
||||||
|
|
||||||
term := terminal.IsTerminal(int(os.Stdout.Fd()))
|
terminal := term.IsTerminal(int(os.Stdout.Fd()))
|
||||||
// https://github.com/databus23/helm-diff/issues/281
|
// https://github.com/databus23/helm-diff/issues/281
|
||||||
dumb := os.Getenv("TERM") == "dumb"
|
dumb := os.Getenv("TERM") == "dumb"
|
||||||
return term && !dumb
|
return terminal && !dumb
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ConfigImpl) NoColor() bool {
|
func (c ConfigImpl) NoColor() bool {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package environment
|
package environment
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// See https://github.com/roboll/helmfile/issues/1150
|
// See https://github.com/roboll/helmfile/issues/1150
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,10 @@ func (context *HelmContext) GetTillerlessArgs(helm *execer) []string {
|
||||||
if context.Tillerless && !helm.IsHelm3() {
|
if context.Tillerless && !helm.IsHelm3() {
|
||||||
if context.TillerNamespace != "" {
|
if context.TillerNamespace != "" {
|
||||||
return []string{"tiller", "run", context.TillerNamespace, "--", helm.helmBinary}
|
return []string{"tiller", "run", context.TillerNamespace, "--", helm.helmBinary}
|
||||||
} else {
|
|
||||||
return []string{"tiller", "run", "--", helm.helmBinary}
|
|
||||||
}
|
}
|
||||||
} else {
|
return []string{"tiller", "run", "--", helm.helmBinary}
|
||||||
return []string{}
|
|
||||||
}
|
}
|
||||||
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (context *HelmContext) getTillerlessEnv() map[string]string {
|
func (context *HelmContext) getTillerlessEnv() map[string]string {
|
||||||
|
|
@ -41,7 +39,6 @@ func (context *HelmContext) getTillerlessEnv() map[string]string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
} else {
|
|
||||||
return map[string]string{}
|
|
||||||
}
|
}
|
||||||
|
return map[string]string{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ func TestGetTillerlessArgs(t *testing.T) {
|
||||||
version: *sr,
|
version: *sr,
|
||||||
}
|
}
|
||||||
require.Equalf(t, test.expected, hc.GetTillerlessArgs(he), "expected result %s, received result %s", test.expected, hc.GetTillerlessArgs(he))
|
require.Equalf(t, test.expected, hc.GetTillerlessArgs(he), "expected result %s, received result %s", test.expected, hc.GetTillerlessArgs(he))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,6 +96,5 @@ func TestGetTillerlessEnv(t *testing.T) {
|
||||||
t.Setenv(kubeconfigEnv, test.kubeconfig)
|
t.Setenv(kubeconfigEnv, test.kubeconfig)
|
||||||
result := hc.getTillerlessEnv()
|
result := hc.getTillerlessEnv()
|
||||||
require.Equalf(t, test.expected, result, "expected result %s, received result %s", test.expected, result)
|
require.Equalf(t, test.expected, result, "expected result %s, received result %s", test.expected, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ func parseHelmVersion(versionStr string) (semver.Version, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHelmVersion(helmBinary string, runner Runner) (semver.Version, error) {
|
func getHelmVersion(helmBinary string, runner Runner) (semver.Version, error) {
|
||||||
|
|
||||||
// Autodetect from `helm version`
|
// Autodetect from `helm version`
|
||||||
outBytes, err := runner.Execute(helmBinary, []string{"version", "--client", "--short"}, nil)
|
outBytes, err := runner.Execute(helmBinary, []string{"version", "--client", "--short"}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -84,15 +83,16 @@ func getHelmVersion(helmBinary string, runner Runner) (semver.Version, error) {
|
||||||
return parseHelmVersion(string(outBytes))
|
return parseHelmVersion(string(outBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func redactedUrl(chart string) string {
|
func redactedURL(chart string) string {
|
||||||
chartUrl, err := url.ParseRequestURI(chart)
|
chartURL, err := url.ParseRequestURI(chart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return chart
|
return chart
|
||||||
}
|
}
|
||||||
return chartUrl.Redacted()
|
return chartURL.Redacted()
|
||||||
}
|
}
|
||||||
|
|
||||||
// New for running helm commands
|
// New for running helm commands
|
||||||
|
// nolint: golint
|
||||||
func New(helmBinary string, logger *zap.SugaredLogger, kubeContext string, runner Runner) *execer {
|
func New(helmBinary string, logger *zap.SugaredLogger, kubeContext string, runner Runner) *execer {
|
||||||
// TODO: proper error handling
|
// TODO: proper error handling
|
||||||
version, err := getHelmVersion(helmBinary, runner)
|
version, err := getHelmVersion(helmBinary, runner)
|
||||||
|
|
@ -206,7 +206,7 @@ func (helm *execer) UpdateDeps(chart string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (helm *execer) SyncRelease(context HelmContext, name, chart string, flags ...string) error {
|
func (helm *execer) SyncRelease(context HelmContext, name, chart string, flags ...string) error {
|
||||||
helm.logger.Infof("Upgrading release=%v, chart=%v", name, redactedUrl(chart))
|
helm.logger.Infof("Upgrading release=%v, chart=%v", name, redactedURL(chart))
|
||||||
preArgs := context.GetTillerlessArgs(helm)
|
preArgs := context.GetTillerlessArgs(helm)
|
||||||
env := context.getTillerlessEnv()
|
env := context.getTillerlessEnv()
|
||||||
|
|
||||||
|
|
@ -270,7 +270,6 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
|
||||||
|
|
||||||
// Cache miss
|
// Cache miss
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
||||||
secret = &decryptedSecret{}
|
secret = &decryptedSecret{}
|
||||||
helm.decryptedSecrets[absPath] = secret
|
helm.decryptedSecrets[absPath] = secret
|
||||||
|
|
||||||
|
|
@ -288,7 +287,6 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
|
||||||
}
|
}
|
||||||
|
|
||||||
secret.bytes = secretBytes
|
secret.bytes = secretBytes
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Cache hit
|
// Cache hit
|
||||||
helm.logger.Debugf("Found secret in cache %v", absPath)
|
helm.logger.Debugf("Found secret in cache %v", absPath)
|
||||||
|
|
@ -312,7 +310,9 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer tmpFile.Close()
|
defer func() {
|
||||||
|
_ = tmpFile.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
_, err = tmpFile.Write(content)
|
_, err = tmpFile.Write(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -334,7 +334,7 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (helm *execer) TemplateRelease(name string, chart string, flags ...string) error {
|
func (helm *execer) TemplateRelease(name string, chart string, flags ...string) error {
|
||||||
helm.logger.Infof("Templating release=%v, chart=%v", name, redactedUrl(chart))
|
helm.logger.Infof("Templating release=%v, chart=%v", name, redactedURL(chart))
|
||||||
var args []string
|
var args []string
|
||||||
if helm.IsHelm3() {
|
if helm.IsHelm3() {
|
||||||
args = []string{"template", name, chart}
|
args = []string{"template", name, chart}
|
||||||
|
|
@ -373,9 +373,9 @@ func (helm *execer) TemplateRelease(name string, chart string, flags ...string)
|
||||||
|
|
||||||
func (helm *execer) DiffRelease(context HelmContext, name, chart string, suppressDiff bool, flags ...string) error {
|
func (helm *execer) DiffRelease(context HelmContext, name, chart string, suppressDiff bool, flags ...string) error {
|
||||||
if context.Writer != nil {
|
if context.Writer != nil {
|
||||||
fmt.Fprintf(context.Writer, "Comparing release=%v, chart=%v\n", name, redactedUrl(chart))
|
fmt.Fprintf(context.Writer, "Comparing release=%v, chart=%v\n", name, redactedURL(chart))
|
||||||
} else {
|
} else {
|
||||||
helm.logger.Infof("Comparing release=%v, chart=%v", name, redactedUrl(chart))
|
helm.logger.Infof("Comparing release=%v, chart=%v", name, redactedURL(chart))
|
||||||
}
|
}
|
||||||
preArgs := context.GetTillerlessArgs(helm)
|
preArgs := context.GetTillerlessArgs(helm)
|
||||||
env := context.getTillerlessEnv()
|
env := context.getTillerlessEnv()
|
||||||
|
|
@ -390,14 +390,12 @@ func (helm *execer) DiffRelease(context HelmContext, name, chart string, suppres
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if detailedExitcodeEnabled {
|
if detailedExitcodeEnabled {
|
||||||
switch e := err.(type) {
|
e, ok := err.(ExitError)
|
||||||
case ExitError:
|
if ok && e.ExitStatus() == 2 {
|
||||||
if e.ExitStatus() == 2 {
|
if !(suppressDiff) {
|
||||||
if !(suppressDiff) {
|
helm.write(context.Writer, out)
|
||||||
helm.write(context.Writer, out)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
} else if !(suppressDiff) {
|
} else if !(suppressDiff) {
|
||||||
helm.write(context.Writer, out)
|
helm.write(context.Writer, out)
|
||||||
|
|
@ -413,7 +411,7 @@ func (helm *execer) Lint(name, chart string, flags ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (helm *execer) Fetch(chart string, flags ...string) error {
|
func (helm *execer) Fetch(chart string, flags ...string) error {
|
||||||
helm.logger.Infof("Fetching %v", redactedUrl(chart))
|
helm.logger.Infof("Fetching %v", redactedURL(chart))
|
||||||
out, err := helm.exec(append([]string{"fetch", chart}, flags...), map[string]string{})
|
out, err := helm.exec(append([]string{"fetch", chart}, flags...), map[string]string{})
|
||||||
helm.info(out)
|
helm.info(out)
|
||||||
return err
|
return err
|
||||||
|
|
@ -432,7 +430,9 @@ func (helm *execer) ChartPull(chart string, flags ...string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tempDir)
|
defer func() {
|
||||||
|
_ = os.RemoveAll(tempDir)
|
||||||
|
}()
|
||||||
helmArgs = []string{"fetch", ociChartURL, "--version", ociChartTag, "--destination", tempDir}
|
helmArgs = []string{"fetch", ociChartURL, "--version", ociChartTag, "--destination", tempDir}
|
||||||
} else {
|
} else {
|
||||||
helmArgs = []string{"chart", "pull", chart}
|
helmArgs = []string{"chart", "pull", chart}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ func (mock *mockRunner) Execute(cmd string, args []string, env map[string]string
|
||||||
return mock.output, mock.err
|
return mock.output, mock.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
func MockExecer(logger *zap.SugaredLogger, kubeContext string) *execer {
|
func MockExecer(logger *zap.SugaredLogger, kubeContext string) *execer {
|
||||||
execer := New("helm", logger, kubeContext, &mockRunner{})
|
execer := New("helm", logger, kubeContext, &mockRunner{})
|
||||||
return execer
|
return execer
|
||||||
|
|
@ -816,14 +817,14 @@ func Test_GetVersion(t *testing.T) {
|
||||||
helm := New("helm", NewLogger(os.Stdout, "info"), "dev", &helm2Runner)
|
helm := New("helm", NewLogger(os.Stdout, "info"), "dev", &helm2Runner)
|
||||||
ver := helm.GetVersion()
|
ver := helm.GetVersion()
|
||||||
if ver.Major != 2 || ver.Minor != 16 || ver.Patch != 1 {
|
if ver.Major != 2 || ver.Minor != 16 || ver.Patch != 1 {
|
||||||
t.Error(fmt.Sprintf("helmexec.GetVersion - did not detect correct Helm2 version; it was: %+v", ver))
|
t.Errorf("helmexec.GetVersion - did not detect correct Helm2 version; it was: %+v", ver)
|
||||||
}
|
}
|
||||||
|
|
||||||
helm3Runner := mockRunner{output: []byte("v3.2.4+ge29ce2a\n")}
|
helm3Runner := mockRunner{output: []byte("v3.2.4+ge29ce2a\n")}
|
||||||
helm = New("helm", NewLogger(os.Stdout, "info"), "dev", &helm3Runner)
|
helm = New("helm", NewLogger(os.Stdout, "info"), "dev", &helm3Runner)
|
||||||
ver = helm.GetVersion()
|
ver = helm.GetVersion()
|
||||||
if ver.Major != 3 || ver.Minor != 2 || ver.Patch != 4 {
|
if ver.Major != 3 || ver.Minor != 2 || ver.Patch != 4 {
|
||||||
t.Error(fmt.Sprintf("helmexec.GetVersion - did not detect correct Helm3 version; it was: %+v", ver))
|
t.Errorf("helmexec.GetVersion - did not detect correct Helm3 version; it was: %+v", ver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package helmexec
|
package helmexec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.uber.org/zap"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type logWriterGenerator struct {
|
type logWriterGenerator struct {
|
||||||
|
|
|
||||||
|
|
@ -10,57 +10,57 @@ func CastKeysToStrings(s interface{}) (map[string]interface{}, error) {
|
||||||
switch src := s.(type) {
|
switch src := s.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
for k, v := range src {
|
for k, v := range src {
|
||||||
var str_k string
|
var strK string
|
||||||
switch typed_k := k.(type) {
|
switch typedK := k.(type) {
|
||||||
case string:
|
case string:
|
||||||
str_k = typed_k
|
strK = typedK
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected type of key in map: expected string, got %T: value=%v, map=%v", typed_k, typed_k, src)
|
return nil, fmt.Errorf("unexpected type of key in map: expected string, got %T: value=%v, map=%v", typedK, typedK, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
casted_v, err := recursivelyStringifyMapKey(v)
|
castedV, err := recursivelyStringifyMapKey(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
new[str_k] = casted_v
|
new[strK] = castedV
|
||||||
}
|
}
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
for k, v := range src {
|
for k, v := range src {
|
||||||
casted_v, err := recursivelyStringifyMapKey(v)
|
castedV, err := recursivelyStringifyMapKey(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
new[k] = casted_v
|
new[k] = castedV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new, nil
|
return new, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func recursivelyStringifyMapKey(v interface{}) (interface{}, error) {
|
func recursivelyStringifyMapKey(v interface{}) (interface{}, error) {
|
||||||
var casted_v interface{}
|
var castedV interface{}
|
||||||
switch typed_v := v.(type) {
|
switch typedV := v.(type) {
|
||||||
case map[interface{}]interface{}, map[string]interface{}:
|
case map[interface{}]interface{}, map[string]interface{}:
|
||||||
tmp, err := CastKeysToStrings(typed_v)
|
tmp, err := CastKeysToStrings(typedV)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
casted_v = tmp
|
castedV = tmp
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
a := []interface{}{}
|
a := []interface{}{}
|
||||||
for i := range typed_v {
|
for i := range typedV {
|
||||||
res, err := recursivelyStringifyMapKey(typed_v[i])
|
res, err := recursivelyStringifyMapKey(typedV[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
a = append(a, res)
|
a = append(a, res)
|
||||||
}
|
}
|
||||||
casted_v = a
|
castedV = a
|
||||||
default:
|
default:
|
||||||
casted_v = typed_v
|
castedV = typedV
|
||||||
}
|
}
|
||||||
return casted_v, nil
|
return castedV, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type arg interface {
|
type arg interface {
|
||||||
|
|
@ -169,7 +169,7 @@ func ParseKey(key string) []string {
|
||||||
r = append(r, part)
|
r = append(r, part)
|
||||||
part = ""
|
part = ""
|
||||||
} else {
|
} else {
|
||||||
part = part + string(rune)
|
part += string(rune)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(part) > 0 {
|
if len(part) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/variantdev/vals"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/variantdev/vals"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,7 @@ func (r *Remote) Locate(urlOrPath string) (string, error) {
|
||||||
}
|
}
|
||||||
fetched, err := r.Fetch(urlOrPath)
|
fetched, err := r.Fetch(urlOrPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.(type) {
|
if _, ok := err.(InvalidURLError); ok {
|
||||||
case InvalidURLError:
|
|
||||||
return urlOrPath, nil
|
return urlOrPath, nil
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -134,8 +133,7 @@ func IsRemote(goGetterSrc string) bool {
|
||||||
func Parse(goGetterSrc string) (*Source, error) {
|
func Parse(goGetterSrc string) (*Source, error) {
|
||||||
items := strings.Split(goGetterSrc, "::")
|
items := strings.Split(goGetterSrc, "::")
|
||||||
var getter string
|
var getter string
|
||||||
switch len(items) {
|
if len(items) == 2 {
|
||||||
case 2:
|
|
||||||
getter = items[0]
|
getter = items[0]
|
||||||
goGetterSrc = items[1]
|
goGetterSrc = items[1]
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +197,7 @@ func (r *Remote) Fetch(goGetterSrc string, cacheDirOpt ...string) (string, error
|
||||||
if q.Has("sshkey") {
|
if q.Has("sshkey") {
|
||||||
q.Set("sshkey", "redacted")
|
q.Set("sshkey", "redacted")
|
||||||
}
|
}
|
||||||
paramsKey := strings.Replace(q.Encode(), "&", "_", -1)
|
paramsKey := strings.ReplaceAll(q.Encode(), "&", "_")
|
||||||
cacheKey = fmt.Sprintf("%s.%s", dirKey, paramsKey)
|
cacheKey = fmt.Sprintf("%s.%s", dirKey, paramsKey)
|
||||||
} else {
|
} else {
|
||||||
cacheKey = dirKey
|
cacheKey = dirKey
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,9 @@ func (st *HelmState) updateDependenciesInTempDir(shell helmexec.DependencyUpdate
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create dir: %v", err)
|
return nil, fmt.Errorf("unable to create dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(d)
|
defer func() {
|
||||||
|
_ = os.RemoveAll(d)
|
||||||
|
}()
|
||||||
|
|
||||||
return updateDependencies(st, shell, unresolved, filename, d)
|
return updateDependencies(st, shell, unresolved, filename, d)
|
||||||
}
|
}
|
||||||
|
|
@ -219,9 +221,9 @@ func getUnresolvedDependenciess(st *HelmState) (string, *UnresolvedDependencies,
|
||||||
}
|
}
|
||||||
|
|
||||||
unresolved := &UnresolvedDependencies{deps: map[string][]unresolvedChartDependency{}}
|
unresolved := &UnresolvedDependencies{deps: map[string][]unresolvedChartDependency{}}
|
||||||
//if err := unresolved.Add("stable/envoy", "https://kubernetes-charts.storage.googleapis.com", ""); err != nil {
|
// if err := unresolved.Add("stable/envoy", "https://kubernetes-charts.storage.googleapis.com", ""); err != nil {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
//}
|
// }
|
||||||
|
|
||||||
for _, r := range st.Releases {
|
for _, r := range st.Releases {
|
||||||
repo, chart, ok := resolveRemoteChart(r.Chart)
|
repo, chart, ok := resolveRemoteChart(r.Chart)
|
||||||
|
|
@ -269,6 +271,7 @@ type chartDependencyManager struct {
|
||||||
writeFile func(string, []byte, os.FileMode) error
|
writeFile func(string, []byte, os.FileMode) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
func NewChartDependencyManager(name string, logger *zap.SugaredLogger) *chartDependencyManager {
|
func NewChartDependencyManager(name string, logger *zap.SugaredLogger) *chartDependencyManager {
|
||||||
return &chartDependencyManager{
|
return &chartDependencyManager{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|
@ -324,7 +327,6 @@ func (m *chartDependencyManager) updateHelm2(shell helmexec.DependencyUpdater, w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *chartDependencyManager) doUpdate(chartLockFile string, unresolved *UnresolvedDependencies, shell helmexec.DependencyUpdater, wd string) (*ResolvedDependencies, error) {
|
func (m *chartDependencyManager) doUpdate(chartLockFile string, unresolved *UnresolvedDependencies, shell helmexec.DependencyUpdater, wd string) (*ResolvedDependencies, error) {
|
||||||
|
|
||||||
// Generate `requirements.lock` of the temporary local chart by coping `<basename>.lock`
|
// Generate `requirements.lock` of the temporary local chart by coping `<basename>.lock`
|
||||||
lockFile := m.lockFileName()
|
lockFile := m.lockFileName()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ const (
|
||||||
DefaultHelmBinary = "helm"
|
DefaultHelmBinary = "helm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
type StateLoadError struct {
|
type StateLoadError struct {
|
||||||
msg string
|
msg string
|
||||||
Cause error
|
Cause error
|
||||||
|
|
@ -231,7 +232,6 @@ func (c *StateCreator) loadEnvValues(st *HelmState, name string, failOnMissingEn
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(envSpec.Secrets) > 0 {
|
if len(envSpec.Secrets) > 0 {
|
||||||
|
|
||||||
var envSecretFiles []string
|
var envSecretFiles []string
|
||||||
for _, urlOrPath := range envSpec.Secrets {
|
for _, urlOrPath := range envSpec.Secrets {
|
||||||
resolved, skipped, err := st.storage().resolveFile(envSpec.MissingFileHandler, "environment values", urlOrPath)
|
resolved, skipped, err := st.storage().resolveFile(envSpec.MissingFileHandler, "environment values", urlOrPath)
|
||||||
|
|
@ -305,6 +305,7 @@ func (c *StateCreator) scatterGatherEnvSecretFiles(st *HelmState, envSecretFiles
|
||||||
results <- secretResult{secret.id, nil, err, secret.path}
|
results <- secretResult{secret.id, nil, err, secret.path}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// nolint: staticcheck
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := c.DeleteFile(decFile); err != nil {
|
if err := c.DeleteFile(decFile); err != nil {
|
||||||
c.logger.Warnf("removing decrypted file %s: %w", decFile, err)
|
c.logger.Warnf("removing decrypted file %s: %w", decFile, err)
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R
|
||||||
return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err)
|
return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := renderer.RenderTemplateContentToBuffer([]byte(serialized))
|
s, err := renderer.RenderTemplateContentToBuffer(serialized)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, serialized, err)
|
return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, serialized, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -873,7 +873,7 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
|
||||||
affectedReleases.Upgraded = append(affectedReleases.Upgraded, release)
|
affectedReleases.Upgraded = append(affectedReleases.Upgraded, release)
|
||||||
m.Unlock()
|
m.Unlock()
|
||||||
installedVersion, err := st.getDeployedVersion(context, helm, release)
|
installedVersion, err := st.getDeployedVersion(context, helm, release)
|
||||||
if err != nil { //err is not really impacting so just log it
|
if err != nil { // err is not really impacting so just log it
|
||||||
st.logger.Debugf("getting deployed release version failed:%v", err)
|
st.logger.Debugf("getting deployed release version failed:%v", err)
|
||||||
} else {
|
} else {
|
||||||
release.installedVersion = installedVersion
|
release.installedVersion = installedVersion
|
||||||
|
|
@ -1121,6 +1121,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
|
||||||
|
|
||||||
chartification, clean, err := st.PrepareChartify(helm, release, chartPath, workerIndex)
|
chartification, clean, err := st.PrepareChartify(helm, release, chartPath, workerIndex)
|
||||||
if !opts.SkipCleanup {
|
if !opts.SkipCleanup {
|
||||||
|
// nolint: staticcheck
|
||||||
defer clean()
|
defer clean()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1350,7 +1351,6 @@ func (o *TemplateOpts) Apply(opts *TemplateOpts) {
|
||||||
// TemplateReleases wrapper for executing helm template on the releases
|
// TemplateReleases wrapper for executing helm template on the releases
|
||||||
func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, additionalValues []string, args []string, workerLimit int,
|
func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, additionalValues []string, args []string, workerLimit int,
|
||||||
validate bool, opt ...TemplateOpt) []error {
|
validate bool, opt ...TemplateOpt) []error {
|
||||||
|
|
||||||
opts := &TemplateOpts{}
|
opts := &TemplateOpts{}
|
||||||
for _, o := range opt {
|
for _, o := range opt {
|
||||||
o.Apply(opts)
|
o.Apply(opts)
|
||||||
|
|
@ -2100,7 +2100,7 @@ func markExcludedReleases(releases []ReleaseSpec, selectors []string, commonLabe
|
||||||
// Strip off just the last portion for the name stable/newrelic would give newrelic
|
// Strip off just the last portion for the name stable/newrelic would give newrelic
|
||||||
chartSplit := strings.Split(r.Chart, "/")
|
chartSplit := strings.Split(r.Chart, "/")
|
||||||
r.Labels["chart"] = chartSplit[len(chartSplit)-1]
|
r.Labels["chart"] = chartSplit[len(chartSplit)-1]
|
||||||
//Merge CommonLabels into release labels
|
// Merge CommonLabels into release labels
|
||||||
for k, v := range commonLabels {
|
for k, v := range commonLabels {
|
||||||
r.Labels[k] = v
|
r.Labels[k] = v
|
||||||
}
|
}
|
||||||
|
|
@ -2579,7 +2579,6 @@ func (st *HelmState) chartVersionFlags(release *ReleaseSpec) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) appendApiVersionsFlags(flags []string, r *ReleaseSpec) []string {
|
func (st *HelmState) appendApiVersionsFlags(flags []string, r *ReleaseSpec) []string {
|
||||||
|
|
||||||
if len(r.ApiVersions) != 0 {
|
if len(r.ApiVersions) != 0 {
|
||||||
for _, a := range r.ApiVersions {
|
for _, a := range r.ApiVersions {
|
||||||
flags = append(flags, "--api-versions", a)
|
flags = append(flags, "--api-versions", a)
|
||||||
|
|
@ -2745,7 +2744,9 @@ func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, v
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return generatedFiles, err
|
return generatedFiles, err
|
||||||
}
|
}
|
||||||
defer valfile.Close()
|
defer func() {
|
||||||
|
_ = valfile.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
if _, err := valfile.Write(yamlBytes); err != nil {
|
if _, err := valfile.Write(yamlBytes); err != nil {
|
||||||
return generatedFiles, fmt.Errorf("failed to write %s: %v", valfile.Name(), err)
|
return generatedFiles, fmt.Errorf("failed to write %s: %v", valfile.Name(), err)
|
||||||
|
|
@ -2759,10 +2760,14 @@ func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, v
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return generatedFiles, err
|
return generatedFiles, err
|
||||||
}
|
}
|
||||||
defer valfile.Close()
|
defer func() {
|
||||||
|
_ = valfile.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
encoder := yaml.NewEncoder(valfile)
|
encoder := yaml.NewEncoder(valfile)
|
||||||
defer encoder.Close()
|
defer func() {
|
||||||
|
_ = encoder.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
if err := encoder.Encode(typedValue); err != nil {
|
if err := encoder.Encode(typedValue); err != nil {
|
||||||
return generatedFiles, err
|
return generatedFiles, err
|
||||||
|
|
@ -3031,13 +3036,13 @@ func (ar *AffectedReleases) DisplayAffectedReleases(logger *zap.SugaredLogger) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func escape(value string) string {
|
func escape(value string) string {
|
||||||
intermediate := strings.Replace(value, "{", "\\{", -1)
|
intermediate := strings.ReplaceAll(value, "{", "\\{")
|
||||||
intermediate = strings.Replace(intermediate, "}", "\\}", -1)
|
intermediate = strings.ReplaceAll(intermediate, "}", "\\}")
|
||||||
return strings.Replace(intermediate, ",", "\\,", -1)
|
return strings.ReplaceAll(intermediate, ",", "\\,")
|
||||||
}
|
}
|
||||||
|
|
||||||
//MarshalYAML will ensure we correctly marshal SubHelmfileSpec structure correctly so it can be unmarshalled at some
|
// MarshalYAML will ensure we correctly marshal SubHelmfileSpec structure correctly so it can be unmarshalled at some
|
||||||
//future time
|
// future time
|
||||||
func (p SubHelmfileSpec) MarshalYAML() (interface{}, error) {
|
func (p SubHelmfileSpec) MarshalYAML() (interface{}, error) {
|
||||||
type SubHelmfileSpecTmp struct {
|
type SubHelmfileSpecTmp struct {
|
||||||
Path string `yaml:"path,omitempty"`
|
Path string `yaml:"path,omitempty"`
|
||||||
|
|
@ -3053,10 +3058,9 @@ func (p SubHelmfileSpec) MarshalYAML() (interface{}, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//UnmarshalYAML will unmarshal the helmfile yaml section and fill the SubHelmfileSpec structure
|
// UnmarshalYAML will unmarshal the helmfile yaml section and fill the SubHelmfileSpec structure
|
||||||
//this is required to keep allowing string scalar for defining helmfile
|
// this is required to keep allowing string scalar for defining helmfile
|
||||||
func (hf *SubHelmfileSpec) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
func (hf *SubHelmfileSpec) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
|
||||||
var tmp interface{}
|
var tmp interface{}
|
||||||
if err := unmarshal(&tmp); err != nil {
|
if err := unmarshal(&tmp); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -3081,12 +3085,12 @@ func (hf *SubHelmfileSpec) UnmarshalYAML(unmarshal func(interface{}) error) erro
|
||||||
hf.SelectorsInherited = subHelmfileSpecTmp.SelectorsInherited
|
hf.SelectorsInherited = subHelmfileSpecTmp.SelectorsInherited
|
||||||
hf.Environment = subHelmfileSpecTmp.Environment
|
hf.Environment = subHelmfileSpecTmp.Environment
|
||||||
}
|
}
|
||||||
//since we cannot make sur the "console" string can be red after the "path" we must check we don't have
|
// since we cannot make sur the "console" string can be red after the "path" we must check we don't have
|
||||||
//a SubHelmfileSpec with only selector and no path
|
// a SubHelmfileSpec with only selector and no path
|
||||||
if hf.Selectors != nil && hf.Path == "" {
|
if hf.Selectors != nil && hf.Path == "" {
|
||||||
return fmt.Errorf("found 'selectors' definition without path: %v", hf.Selectors)
|
return fmt.Errorf("found 'selectors' definition without path: %v", hf.Selectors)
|
||||||
}
|
}
|
||||||
//also exclude SelectorsInherited to true and explicit selectors
|
// also exclude SelectorsInherited to true and explicit selectors
|
||||||
if hf.SelectorsInherited && len(hf.Selectors) > 0 {
|
if hf.SelectorsInherited && len(hf.Selectors) > 0 {
|
||||||
return fmt.Errorf("you cannot use 'SelectorsInherited: true' along with and explicit selector for path: %v", hf.Path)
|
return fmt.Errorf("you cannot use 'SelectorsInherited: true' along with and explicit selector for path: %v", hf.Path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ func getBoolRefFromStringTemplate(templateRef string) (*bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateBoolTemplatedValues(r *ReleaseSpec) error {
|
func updateBoolTemplatedValues(r *ReleaseSpec) error {
|
||||||
|
|
||||||
if r.InstalledTemplate != nil {
|
if r.InstalledTemplate != nil {
|
||||||
if installed, err := getBoolRefFromStringTemplate(*r.InstalledTemplate); err != nil {
|
if installed, err := getBoolRefFromStringTemplate(*r.InstalledTemplate); err != nil {
|
||||||
return fmt.Errorf("installedTemplate: %v", err)
|
return fmt.Errorf("installedTemplate: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,6 @@ func TestHelmState_executeTemplates(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHelmState_recursiveRefsTemplates(t *testing.T) {
|
func TestHelmState_recursiveRefsTemplates(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
input ReleaseSpec
|
input ReleaseSpec
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ type result struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) scatterGather(concurrency int, items int, produceInputs func(), receiveInputsAndProduceIntermediates func(int), aggregateIntermediates func()) {
|
func (st *HelmState) scatterGather(concurrency int, items int, produceInputs func(), receiveInputsAndProduceIntermediates func(int), aggregateIntermediates func()) {
|
||||||
|
|
||||||
if concurrency < 1 || concurrency > items {
|
if concurrency < 1 || concurrency > items {
|
||||||
concurrency = items
|
concurrency = items
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +52,6 @@ func (st *HelmState) scatterGather(concurrency int, items int, produceInputs fun
|
||||||
|
|
||||||
func (st *HelmState) scatterGatherReleases(helm helmexec.Interface, concurrency int,
|
func (st *HelmState) scatterGatherReleases(helm helmexec.Interface, concurrency int,
|
||||||
do func(ReleaseSpec, int) error) []error {
|
do func(ReleaseSpec, int) error) []error {
|
||||||
|
|
||||||
return st.iterateOnReleases(helm, concurrency, st.Releases, do)
|
return st.iterateOnReleases(helm, concurrency, st.Releases, do)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,7 +142,6 @@ func GroupReleasesByDependency(releases []Release, opts PlanOptions) ([][]Releas
|
||||||
|
|
||||||
d := dag.New()
|
d := dag.New()
|
||||||
for i, r := range releases {
|
for i, r := range releases {
|
||||||
|
|
||||||
id := ReleaseToID(&r.ReleaseSpec)
|
id := ReleaseToID(&r.ReleaseSpec)
|
||||||
|
|
||||||
idToReleases[id] = append(idToReleases[id], r)
|
idToReleases[id] = append(idToReleases[id], r)
|
||||||
|
|
|
||||||
|
|
@ -1244,7 +1244,6 @@ func TestHelmState_SyncReleases_MissingValuesFileForUndesiredRelease(t *testing.
|
||||||
t.Fatalf("unexpected error(s): expected=0, got=%d: %v", len(errs), errs)
|
t.Fatalf("unexpected error(s): expected=0, got=%d: %v", len(errs), errs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1392,7 +1391,6 @@ func TestHelmState_SyncReleasesAffectedRealeases(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEq(a []*ReleaseSpec, b []*exectest.Release) bool {
|
func testEq(a []*ReleaseSpec, b []*exectest.Release) bool {
|
||||||
|
|
||||||
// If one is nil, the other must also be nil.
|
// If one is nil, the other must also be nil.
|
||||||
if (a == nil) != (b == nil) {
|
if (a == nil) != (b == nil) {
|
||||||
return false
|
return false
|
||||||
|
|
@ -1473,7 +1471,7 @@ func TestGetDeployedVersion(t *testing.T) {
|
||||||
helm := &exectest.Helm{
|
helm := &exectest.Helm{
|
||||||
Lists: map[exectest.ListKey]string{},
|
Lists: map[exectest.ListKey]string{},
|
||||||
}
|
}
|
||||||
//simulate the helm.list call result
|
// simulate the helm.list call result
|
||||||
helm.Lists[exectest.ListKey{Filter: "^" + tt.release.Name + "$", Flags: "--deleting--deployed--failed--pending"}] = tt.listResult
|
helm.Lists[exectest.ListKey{Filter: "^" + tt.release.Name + "$", Flags: "--deleting--deployed--failed--pending"}] = tt.listResult
|
||||||
|
|
||||||
affectedReleases := AffectedReleases{}
|
affectedReleases := AffectedReleases{}
|
||||||
|
|
@ -1652,10 +1650,8 @@ func TestHelmState_DiffFlags(t *testing.T) {
|
||||||
t.Errorf("HelmState.flagsForDiff() for [%s][%s] = %v, want %v", tt.name, tt.releases[j].Name, flags, tt.wantDiffFlags)
|
t.Errorf("HelmState.flagsForDiff() for [%s][%s] = %v, want %v", tt.name, tt.releases[j].Name, flags, tt.wantDiffFlags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHelmState_SyncReleasesCleanup(t *testing.T) {
|
func TestHelmState_SyncReleasesCleanup(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/helmfile/helmfile/pkg/remote"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/helmfile/helmfile/pkg/remote"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,10 @@ func HashObject(obj interface{}) (string, error) {
|
||||||
DisableMethods: true,
|
DisableMethods: true,
|
||||||
SpewKeys: true,
|
SpewKeys: true,
|
||||||
}
|
}
|
||||||
printer.Fprintf(hash, "%#v", obj)
|
_, err := printer.Fprintf(hash, "%#v", obj)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
sum := fmt.Sprint(hash.Sum32())
|
sum := fmt.Sprint(hash.Sum32())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func TestGenerateID(t *testing.T) {
|
||||||
|
|
||||||
for id, n := range ids {
|
for id, n := range ids {
|
||||||
if n > 1 {
|
if n > 1 {
|
||||||
t.Fatalf("too many occurences of %s: %d", id, n)
|
t.Fatalf("too many occurrences of %s: %d", id, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func isLocalChart(chart string) bool {
|
func isLocalChart(chart string) bool {
|
||||||
regex, _ := regexp.Compile("^[.]?./")
|
regex := regexp.MustCompile("^[.]?./")
|
||||||
matched := regex.MatchString(chart)
|
matched := regex.MatchString(chart)
|
||||||
if matched {
|
if matched {
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ func (f *TestFs) ReadFile(filename string) ([]byte, error) {
|
||||||
return []byte(nil), os.ErrNotExist
|
return []byte(nil), os.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
f.fileReaderCalls += 1
|
f.fileReaderCalls++
|
||||||
|
|
||||||
f.successfulReads = append(f.successfulReads, filename)
|
f.successfulReads = append(f.successfulReads, filename)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,6 @@ func CaptureStdout(f func()) string {
|
||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
f()
|
f()
|
||||||
writer.Close()
|
_ = writer.Close()
|
||||||
return <-out
|
return <-out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,9 @@ func (c *Context) EnvExec(envs map[string]interface{}, command string, args []in
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
defer stdin.Close()
|
defer func() {
|
||||||
|
_ = stdin.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
size := len(input)
|
size := len(input)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ func TestReadFile_PassAbsPath(t *testing.T) {
|
||||||
|
|
||||||
func TestToYaml_UnsupportedNestedMapKey(t *testing.T) {
|
func TestToYaml_UnsupportedNestedMapKey(t *testing.T) {
|
||||||
expected := ``
|
expected := ``
|
||||||
|
// nolint: unconvert
|
||||||
vals := Values(map[string]interface{}{
|
vals := Values(map[string]interface{}{
|
||||||
"foo": map[interface{}]interface{}{
|
"foo": map[interface{}]interface{}{
|
||||||
"bar": "BAR",
|
"bar": "BAR",
|
||||||
|
|
@ -125,6 +126,7 @@ func TestToYaml(t *testing.T) {
|
||||||
expected := `foo:
|
expected := `foo:
|
||||||
bar: BAR
|
bar: BAR
|
||||||
`
|
`
|
||||||
|
// nolint: unconvert
|
||||||
vals := Values(map[string]interface{}{
|
vals := Values(map[string]interface{}{
|
||||||
"foo": map[string]interface{}{
|
"foo": map[string]interface{}{
|
||||||
"bar": "BAR",
|
"bar": "BAR",
|
||||||
|
|
@ -143,6 +145,7 @@ func TestFromYaml(t *testing.T) {
|
||||||
raw := `foo:
|
raw := `foo:
|
||||||
bar: BAR
|
bar: BAR
|
||||||
`
|
`
|
||||||
|
// nolint: unconvert
|
||||||
expected := Values(map[string]interface{}{
|
expected := Values(map[string]interface{}{
|
||||||
"foo": map[string]interface{}{
|
"foo": map[string]interface{}{
|
||||||
"bar": "BAR",
|
"bar": "BAR",
|
||||||
|
|
@ -276,7 +279,6 @@ func TestRequired(t *testing.T) {
|
||||||
|
|
||||||
// TestRequiredEnv tests that RequiredEnv returns an error if the environment variable is not set.
|
// TestRequiredEnv tests that RequiredEnv returns an error if the environment variable is not set.
|
||||||
func TestRequiredEnv(t *testing.T) {
|
func TestRequiredEnv(t *testing.T) {
|
||||||
|
|
||||||
// test that the environment variable is not set
|
// test that the environment variable is not set
|
||||||
envKey := "HelmFile"
|
envKey := "HelmFile"
|
||||||
envVal, err := RequiredEnv(envKey)
|
envVal, err := RequiredEnv(envKey)
|
||||||
|
|
@ -298,7 +300,6 @@ func TestRequiredEnv(t *testing.T) {
|
||||||
envVal, err = RequiredEnv(envKey)
|
envVal, err = RequiredEnv(envKey)
|
||||||
require.Nilf(t, err, "Expected no error to be returned when environment variable %s is set to a non-empty string", envKey)
|
require.Nilf(t, err, "Expected no error to be returned when environment variable %s is set to a non-empty string", envKey)
|
||||||
require.Equalf(t, expected, envVal, "Expected %s to be returned when environment variable %s is set to a non-empty string", expected, envKey)
|
require.Equalf(t, expected, envVal, "Expected %s to be returned when environment variable %s is set to a non-empty string", expected, envKey)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestExec tests that Exec returns the expected output.
|
// TestExec tests that Exec returns the expected output.
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ package tmpl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/Masterminds/sprig/v3"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/Masterminds/sprig/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Context) CreateFuncMap() template.FuncMap {
|
func (c *Context) CreateFuncMap() template.FuncMap {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/variantdev/vals"
|
"github.com/variantdev/vals"
|
||||||
)
|
)
|
||||||
|
|
||||||
//to generate mock run mockgen -source=expand_secret_ref.go -destination=expand_secrets_mock.go -package=tmpl
|
// to generate mock run mockgen -source=expand_secret_ref.go -destination=expand_secrets_mock.go -package=tmpl
|
||||||
type valClient interface {
|
type valClient interface {
|
||||||
Eval(template map[string]interface{}) (map[string]interface{}, error)
|
Eval(template map[string]interface{}) (map[string]interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ package tmpl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/helmfile/helmfile/pkg/environment"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/helmfile/helmfile/pkg/environment"
|
||||||
)
|
)
|
||||||
|
|
||||||
var emptyEnvTmplData = map[string]interface{}{
|
var emptyEnvTmplData = map[string]interface{}{
|
||||||
|
|
@ -50,8 +51,7 @@ func TestRenderToBytes_Yaml(t *testing.T) {
|
||||||
`
|
`
|
||||||
valuesFile := "values.yaml"
|
valuesFile := "values.yaml"
|
||||||
r := NewFileRenderer(func(filename string) ([]byte, error) {
|
r := NewFileRenderer(func(filename string) ([]byte, error) {
|
||||||
switch filename {
|
if filename == valuesFile {
|
||||||
case valuesFile:
|
|
||||||
return []byte(valuesYamlContent), nil
|
return []byte(valuesYamlContent), nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", valuesFile, filename)
|
return nil, fmt.Errorf("unexpected filename: expected=%v, actual=%s", valuesFile, filename)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ func get(path string, varArgs ...interface{}) (interface{}, error) {
|
||||||
def = varArgs[0]
|
def = varArgs[0]
|
||||||
obj = varArgs[1]
|
obj = varArgs[1]
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected number of args pased to the template function get(path, [def, ]obj): expected 1 or 2, got %d, args was %v", len(varArgs), varArgs)
|
return nil, fmt.Errorf("unexpected number of args passed to the template function get(path, [def, ]obj): expected 1 or 2, got %d, args was %v", len(varArgs), varArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ type TextRenderer interface {
|
||||||
RenderTemplateText(text string) (string, error)
|
RenderTemplateText(text string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
func NewTextRenderer(readFile func(filename string) ([]byte, error), basePath string, data interface{}) *templateTextRenderer {
|
func NewTextRenderer(readFile func(filename string) ([]byte, error), basePath string, data interface{}) *templateTextRenderer {
|
||||||
return &templateTextRenderer{
|
return &templateTextRenderer{
|
||||||
ReadText: readFile,
|
ReadText: readFile,
|
||||||
|
|
|
||||||
|
|
@ -93,15 +93,15 @@ func run(cmd *cobra.Command, args []string) {
|
||||||
for _, p := range ps.list {
|
for _, p := range ps.list {
|
||||||
switch {
|
switch {
|
||||||
case p.left != nil && p.right == nil:
|
case p.left != nil && p.right == nil:
|
||||||
fmt.Fprintf(os.Stderr, "Only in %s: %s\n", leftPath, p.left.getId())
|
fmt.Fprintf(os.Stderr, "Only in %s: %s\n", leftPath, p.left.getID())
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
case p.left == nil && p.right != nil:
|
case p.left == nil && p.right != nil:
|
||||||
fmt.Fprintf(os.Stderr, "Only in %s: %s\n", rightPath, p.right.getId())
|
fmt.Fprintf(os.Stderr, "Only in %s: %s\n", rightPath, p.right.getID())
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
default:
|
default:
|
||||||
diff := deep.Equal(p.left, p.right)
|
diff := deep.Equal(p.left, p.right)
|
||||||
if diff != nil {
|
if diff != nil {
|
||||||
id := p.left.getId()
|
id := p.left.getID()
|
||||||
fmt.Fprintf(os.Stderr, "< %s %s\n", id, leftPath)
|
fmt.Fprintf(os.Stderr, "< %s %s\n", id, leftPath)
|
||||||
fmt.Fprintf(os.Stderr, "> %s %s\n", id, rightPath)
|
fmt.Fprintf(os.Stderr, "> %s %s\n", id, rightPath)
|
||||||
for _, d := range diff {
|
for _, d := range diff {
|
||||||
|
|
@ -160,7 +160,9 @@ func readManifest(path string) ([]resource, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer func() {
|
||||||
|
_ = f.Close()
|
||||||
|
}()
|
||||||
decoder := yaml.NewYAMLToJSONDecoder(f)
|
decoder := yaml.NewYAMLToJSONDecoder(f)
|
||||||
resources := []resource{}
|
resources := []resource{}
|
||||||
for {
|
for {
|
||||||
|
|
@ -179,7 +181,7 @@ func readManifest(path string) ([]resource, error) {
|
||||||
return resources, nil
|
return resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (res resource) getId() string {
|
func (res resource) getID() string {
|
||||||
meta, err := res.getMeta()
|
meta, err := res.getMeta()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Sprintf("%v", res)
|
return fmt.Sprintf("%v", res)
|
||||||
|
|
@ -202,7 +204,6 @@ func (res resource) getId() string {
|
||||||
}
|
}
|
||||||
gvk := strings.Join([]string{gv, k}, "_")
|
gvk := strings.Join([]string{gv, k}, "_")
|
||||||
return strings.Join([]string{gvk, ns, nm}, "|")
|
return strings.Join([]string{gvk, ns, nm}, "|")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// lifted from kustomize/kyaml/kio/filters/merge3.go
|
// lifted from kustomize/kyaml/kio/filters/merge3.go
|
||||||
|
|
@ -267,7 +268,6 @@ func (p *pair) add(node resource, source diffSource) error {
|
||||||
return fmt.Errorf("unknown diff source value: %s", source)
|
return fmt.Errorf("unknown diff source value: %s", source)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -242,5 +242,4 @@ func TestTmplStrings(t *testing.T) {
|
||||||
require.Equal(t, tc.output, tplResult.String())
|
require.Equal(t, tc.output, tplResult.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,10 @@ func computeDiff(formatter aurora.Aurora, a interface{}, b interface{}) (string,
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(s, "+"):
|
case strings.HasPrefix(s, "+"):
|
||||||
diffs = append(diffs, formatter.Bold(formatter.Green(s)).String())
|
diffs = append(diffs, formatter.Bold(formatter.Green(s)).String())
|
||||||
ndiffs += 1
|
ndiffs++
|
||||||
case strings.HasPrefix(s, "-"):
|
case strings.HasPrefix(s, "-"):
|
||||||
diffs = append(diffs, formatter.Bold(formatter.Red(s)).String())
|
diffs = append(diffs, formatter.Bold(formatter.Red(s)).String())
|
||||||
ndiffs += 1
|
ndiffs++
|
||||||
default:
|
default:
|
||||||
diffs = append(diffs, s)
|
diffs = append(diffs, s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue