add Go lint

Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
yxxhero 2022-06-20 08:47:59 +08:00
parent cc13492623
commit ac23def893
60 changed files with 576 additions and 194 deletions

28
.github/workflows/lint.yaml vendored Normal file
View File

@ -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

352
.golangci.yaml Normal file
View File

@ -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

View 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",

View File

@ -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{

View File

@ -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{})
} }

View File

@ -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",

View File

@ -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
View File

@ -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
) )

View File

@ -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 {

View File

@ -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

View File

@ -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": `

View File

@ -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())
} }

View File

@ -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())
} }

View File

@ -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
} }

View File

@ -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())
} }

View File

@ -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())
} }

View File

@ -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))
} }
} }

View File

@ -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")
} }

View File

@ -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

View File

@ -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()))

View File

@ -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" }}
` `

View File

@ -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")

View File

@ -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

View File

@ -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, "--") {

View File

@ -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)
} }
} }
} }

View File

@ -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 {

View File

@ -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

View File

@ -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{}
} }

View File

@ -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)
} }
} }

View File

@ -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}

View File

@ -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)
} }
} }

View File

@ -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 {

View File

@ -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 {

View File

@ -1,8 +1,9 @@
package plugins package plugins
import ( import (
"github.com/variantdev/vals"
"sync" "sync"
"github.com/variantdev/vals"
) )
const ( const (

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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 {

View File

@ -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())

View File

@ -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)
} }
} }
} }

View File

@ -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

View File

@ -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)

View File

@ -35,6 +35,6 @@ func CaptureStdout(f func()) string {
}() }()
wg.Wait() wg.Wait()
f() f()
writer.Close() _ = writer.Close()
return <-out return <-out
} }

View File

@ -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)

View File

@ -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.

View File

@ -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 {

View File

@ -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)
} }

View File

@ -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)

View File

@ -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 == "" {

View File

@ -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,

View File

@ -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() {

View File

@ -242,5 +242,4 @@ func TestTmplStrings(t *testing.T) {
require.Equal(t, tc.output, tplResult.String()) require.Equal(t, tc.output, tplResult.String())
}) })
} }
} }

View File

@ -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)
} }