1
0
mirror of https://github.com/helm/chart-testing.git synced 2026-02-05 09:45:14 +01:00

Upgrade go1.19, helm update and add golangci-lint job (#460)

* upgrade to go1.19

Signed-off-by: cpanato <ctadeu@gmail.com>

* add golangci-lint

Signed-off-by: cpanato <ctadeu@gmail.com>

* fix lints and Replace github.com/pkg/errors dependency with native error wrapping

Signed-off-by: cpanato <ctadeu@gmail.com>

* update install kind cluster

Signed-off-by: cpanato <ctadeu@gmail.com>

* update tests

Signed-off-by: cpanato <ctadeu@gmail.com>

* use errors.new

Signed-off-by: cpanato <ctadeu@gmail.com>

Signed-off-by: cpanato <ctadeu@gmail.com>
This commit is contained in:
Carlos Tadeu Panato Junior
2022-09-16 15:59:15 +02:00
committed by GitHub
parent e7dd0ad410
commit 68f3fffe62
24 changed files with 211 additions and 170 deletions

View File

@@ -15,8 +15,8 @@
package chart
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -27,7 +27,6 @@ import (
"github.com/helm/chart-testing/v3/pkg/exec"
"github.com/helm/chart-testing/v3/pkg/tool"
"github.com/helm/chart-testing/v3/pkg/util"
"github.com/pkg/errors"
)
const maxNameLength = 63
@@ -46,7 +45,7 @@ const maxNameLength = 63
//
// ListChangedFilesInDirs diffs commit against HEAD and returns changed files for the specified dirs.
//
// GetUrlForRemote returns the repo URL for the specified remote.
// GetURLForRemote returns the repo URL for the specified remote.
//
// ValidateRepository checks that the current working directory is a valid git repository,
// and returns nil if valid.
@@ -57,17 +56,17 @@ type Git interface {
RemoveWorktree(path string) error
MergeBase(commit1 string, commit2 string) (string, error)
ListChangedFilesInDirs(commit string, dirs ...string) ([]string, error)
GetUrlForRemote(remote string) (string, error)
GetURLForRemote(remote string) (string, error)
ValidateRepository() error
}
// Helm is the interface that wraps Helm operations
//
// AddRepo adds a chart repository to the local Helm configuration
// # AddRepo adds a chart repository to the local Helm configuration
//
// BuildDependencies builds the chart's dependencies
// # BuildDependencies builds the chart's dependencies
//
// BuildDependenciesWithArgs allows passing additional arguments to BuildDependencies
// # BuildDependenciesWithArgs allows passing additional arguments to BuildDependencies
//
// LintWithValues runs `helm lint` for the given chart using the specified values file.
// Pass a zero value for valuesFile in order to run lint without specifying a values file.
@@ -95,21 +94,21 @@ type Helm interface {
// Kubectl is the interface that wraps kubectl operations
//
// DeleteNamespace deletes a namespace
// # DeleteNamespace deletes a namespace
//
// WaitForDeployments waits for a deployment to become ready
// # WaitForDeployments waits for a deployment to become ready
//
// GetPodsforDeployment gets all pods for a deployment
// # GetPodsforDeployment gets all pods for a deployment
//
// GetPods gets pods for the given args
// # GetPods gets pods for the given args
//
// GetEvents prints all events for namespace
// # GetEvents prints all events for namespace
//
// DescribePod prints the pod's description
// # DescribePod prints the pod's description
//
// Logs prints the logs of container
// # Logs prints the logs of container
//
// GetInitContainers gets all init containers of pod
// # GetInitContainers gets all init containers of pod
//
// GetContainers gets all containers of pod
type Kubectl interface {
@@ -127,7 +126,7 @@ type Kubectl interface {
// Linter is the interface that wrap linting operations
//
// YamlLint runs `yamllint` on the specified file with the specified configuration
// # YamlLint runs `yamllint` on the specified file with the specified configuration
//
// Yamale runs `yamale` on the specified file with the specified schema file
type Linter interface {
@@ -149,10 +148,10 @@ type DirectoryLister interface {
ListChildDirs(parentDir string, test func(string) bool) ([]string, error)
}
// ChartUtils is the interface that wraps chart-related methods
// Utils is the interface that wraps chart-related methods
//
// LookupChartDir looks up the chart's root directory based on some chart file that has changed
type ChartUtils interface {
type Utils interface {
LookupChartDir(chartDirs []string, dir string) (string, error)
}
@@ -238,7 +237,7 @@ type Testing struct {
cmdExecutor CmdExecutor
accountValidator AccountValidator
directoryLister DirectoryLister
chartUtils ChartUtils
utils Utils
previousRevisionWorktree string
}
@@ -268,7 +267,7 @@ func NewTesting(config config.Configuration, extraSetArgs string) (Testing, erro
cmdExecutor: tool.NewCmdTemplateExecutor(procExec),
accountValidator: tool.AccountValidator{},
directoryLister: util.DirectoryLister{},
chartUtils: util.ChartUtils{},
utils: util.Utils{},
}
versionString, err := testing.helm.Version()
@@ -294,10 +293,10 @@ func (t *Testing) computePreviousRevisionPath(fileOrDirPath string) string {
}
func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestResult, error) {
var results []TestResult
var results []TestResult // nolint: prealloc
chartDirs, err := t.FindChartDirsToBeProcessed()
if err != nil {
return nil, errors.Wrap(err, "Error identifying charts to process")
return nil, fmt.Errorf("failed identifying charts to process: %w", err)
} else if len(chartDirs) == 0 {
return results, nil
}
@@ -310,20 +309,20 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
}
if t.config.ExcludeDeprecated && chart.yaml.Deprecated {
fmt.Printf("Chart '%s' is deprecated and will be ignored because '--exclude-deprecated' is set\n", chart.String())
fmt.Printf("Chart %q is deprecated and will be ignored because '--exclude-deprecated' is set\n", chart.String())
} else {
charts = append(charts, chart)
}
}
fmt.Println()
util.PrintDelimiterLine("-")
util.PrintDelimiterLineToWriter(os.Stdout, "-")
fmt.Println(" Charts to be processed:")
util.PrintDelimiterLine("-")
util.PrintDelimiterLineToWriter(os.Stdout, "-")
for _, chart := range charts {
fmt.Printf(" %s\n", chart)
}
util.PrintDelimiterLine("-")
util.PrintDelimiterLineToWriter(os.Stdout, "-")
fmt.Println()
repoArgs := map[string][]string{}
@@ -342,7 +341,7 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
repoExtraArgs := repoArgs[name]
if err := t.helm.AddRepo(name, url, repoExtraArgs); err != nil {
return nil, errors.Wrapf(err, "Error adding repo: %s=%s", name, url)
return nil, fmt.Errorf("failed adding repo: %s=%s: %w", name, url, err)
}
}
@@ -355,31 +354,31 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
if t.config.Upgrade {
mergeBase, err := t.computeMergeBase()
if err != nil {
return results, errors.Wrap(err, "Error identifying merge base")
return results, fmt.Errorf("failed identifying merge base: %w", err)
}
// Add worktree for the target revision
worktreePath, err := ioutil.TempDir("./", "ct_previous_revision")
worktreePath, err := os.MkdirTemp("./", "ct_previous_revision")
if err != nil {
return results, errors.Wrap(err, "Could not create previous revision directory")
return results, fmt.Errorf("could not create previous revision directory: %w", err)
}
t.previousRevisionWorktree = worktreePath
err = t.git.AddWorktree(worktreePath, mergeBase)
if err != nil {
return results, errors.Wrap(err, "Could not create worktree for previous revision")
return results, fmt.Errorf("could not create worktree for previous revision: %w", err)
}
defer t.git.RemoveWorktree(worktreePath)
defer t.git.RemoveWorktree(worktreePath) // nolint: errcheck
for _, chart := range charts {
if err := t.helm.BuildDependenciesWithArgs(t.computePreviousRevisionPath(chart.Path()), t.config.HelmDependencyExtraArgs); err != nil {
// Only print error (don't exit) if building dependencies for previous revision fails.
fmt.Println(errors.Wrapf(err, "Error building dependencies for previous revision of chart '%s'\n", chart))
fmt.Printf("failed building dependencies for previous revision of chart %q: %v\n", chart, err.Error())
}
}
}
for _, chart := range charts {
if err := t.helm.BuildDependenciesWithArgs(chart.Path(), t.config.HelmDependencyExtraArgs); err != nil {
return nil, errors.Wrapf(err, "Error building dependencies for chart '%s'", chart)
return nil, fmt.Errorf("failed building dependencies for chart %q: %w", chart, err)
}
result := action(chart)
@@ -392,7 +391,7 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
return results, nil
}
return results, errors.New("Error processing charts")
return results, fmt.Errorf("failed processing charts")
}
// LintCharts lints charts (changed, all, specific) depending on the configuration.
@@ -412,7 +411,7 @@ func (t *Testing) LintAndInstallCharts() ([]TestResult, error) {
// PrintResults writes test results to stdout.
func (t *Testing) PrintResults(results []TestResult) {
util.PrintDelimiterLine("-")
util.PrintDelimiterLineToWriter(os.Stdout, "-")
if results != nil {
for _, result := range results {
err := result.Error
@@ -425,12 +424,12 @@ func (t *Testing) PrintResults(results []TestResult) {
} else {
fmt.Println("No chart changes detected.")
}
util.PrintDelimiterLine("-")
util.PrintDelimiterLineToWriter(os.Stdout, "-")
}
// LintChart lints the specified chart.
func (t *Testing) LintChart(chart *Chart) TestResult {
fmt.Printf("Linting chart '%s'\n", chart)
fmt.Printf("Linting chart %q\n", chart)
result := TestResult{Chart: chart}
@@ -483,7 +482,7 @@ func (t *Testing) LintChart(chart *Chart) TestResult {
for _, valuesFile := range valuesFiles {
if valuesFile != "" {
fmt.Printf("\nLinting chart with values file '%s'...\n\n", valuesFile)
fmt.Printf("\nLinting chart with values file %q...\n\n", valuesFile)
}
if err := t.helm.LintWithValues(chart.Path(), valuesFile); err != nil {
result.Error = err
@@ -531,11 +530,11 @@ func (t *Testing) UpgradeChart(chart *Chart) TestResult {
if breakingChangeAllowed {
if err != nil {
fmt.Println(errors.Wrap(err, fmt.Sprintf("Skipping upgrade test of '%s' because", chart)))
fmt.Printf("Skipping upgrade test of %q because: %v\n", chart, err.Error())
}
return result
} else if err != nil {
fmt.Printf("Error comparing chart versions for '%s'\n", chart)
fmt.Printf("Error comparing chart versions for %q\n", chart)
result.Error = err
return result
}
@@ -548,7 +547,7 @@ func (t *Testing) UpgradeChart(chart *Chart) TestResult {
}
func (t *Testing) doInstall(chart *Chart) error {
fmt.Printf("Installing chart '%s'...\n", chart)
fmt.Printf("Installing chart %q...\n", chart)
valuesFiles := chart.ValuesFilePathsForCI()
// Test with defaults if no values files are specified.
@@ -558,7 +557,7 @@ func (t *Testing) doInstall(chart *Chart) error {
for _, valuesFile := range valuesFiles {
if valuesFile != "" {
fmt.Printf("\nInstalling chart with values file '%s'...\n\n", valuesFile)
fmt.Printf("\nInstalling chart with values file %q...\n\n", valuesFile)
}
// Use anonymous function. Otherwise deferred calls would pile up
@@ -587,7 +586,7 @@ func (t *Testing) doInstall(chart *Chart) error {
}
func (t *Testing) doUpgrade(oldChart, newChart *Chart, oldChartMustPass bool) error {
fmt.Printf("Testing upgrades of chart '%s' relative to previous revision '%s'...\n", newChart, oldChart)
fmt.Printf("Testing upgrades of chart %q relative to previous revision %q...\n", newChart, oldChart)
valuesFiles := oldChart.ValuesFilePathsForCI()
if len(valuesFiles) == 0 {
valuesFiles = append(valuesFiles, "")
@@ -595,10 +594,10 @@ func (t *Testing) doUpgrade(oldChart, newChart *Chart, oldChartMustPass bool) er
for _, valuesFile := range valuesFiles {
if valuesFile != "" {
if t.config.SkipMissingValues && !newChart.HasCIValuesFile(valuesFile) {
fmt.Printf("Upgrade testing for values file '%s' skipped because a corresponding values file was not found in %s/ci", valuesFile, newChart.Path())
fmt.Printf("Upgrade testing for values file %q skipped because a corresponding values file was not found in %s/ci\n", valuesFile, newChart.Path())
continue
}
fmt.Printf("\nInstalling chart '%s' with values file '%s'...\n\n", oldChart, valuesFile)
fmt.Printf("\nInstalling chart %q with values file %q...\n\n", oldChart, valuesFile)
}
// Use anonymous function. Otherwise deferred calls would pile up
@@ -617,14 +616,14 @@ func (t *Testing) doUpgrade(oldChart, newChart *Chart, oldChartMustPass bool) er
if oldChartMustPass {
return err
}
fmt.Println(errors.Wrap(err, fmt.Sprintf("Upgrade testing for release '%s' skipped because of previous revision installation error", release)))
fmt.Printf("Upgrade testing for release %q skipped because of previous revision installation error: %v\n", release, err.Error())
return nil
}
if err := t.testRelease(namespace, release, releaseSelector); err != nil {
if oldChartMustPass {
return err
}
fmt.Println(errors.Wrap(err, fmt.Sprintf("Upgrade testing for release '%s' skipped because of previous revision testing error", release)))
fmt.Printf("Upgrade testing for release %q skipped because of previous revision testing error: %v\n", release, err.Error())
return nil
}
@@ -656,14 +655,14 @@ func (t *Testing) testRelease(namespace, release, releaseSelector string) error
func (t *Testing) generateInstallConfig(chart *Chart) (namespace, release, releaseSelector string, cleanup func()) {
if t.config.Namespace != "" {
namespace = t.config.Namespace
release, _ = chart.CreateInstallParams(t.config.BuildId)
release, _ = chart.CreateInstallParams(t.config.BuildID)
releaseSelector = fmt.Sprintf("%s=%s", t.config.ReleaseLabel, release)
cleanup = func() {
t.PrintEventsPodDetailsAndLogs(namespace, releaseSelector)
t.helm.DeleteRelease(namespace, release)
}
} else {
release, namespace = chart.CreateInstallParams(t.config.BuildId)
release, namespace = chart.CreateInstallParams(t.config.BuildID)
cleanup = func() {
t.PrintEventsPodDetailsAndLogs(namespace, releaseSelector)
t.helm.DeleteRelease(namespace, release)
@@ -698,7 +697,7 @@ func (t *Testing) FindChartDirsToBeProcessed() ([]string, error) {
func (t *Testing) computeMergeBase() (string, error) {
err := t.git.ValidateRepository()
if err != nil {
return "", errors.New("Must be in a git repository")
return "", errors.New("must be in a git repository")
}
return t.git.MergeBase(fmt.Sprintf("%s/%s", t.config.Remote, t.config.TargetBranch), t.config.Since)
}
@@ -715,7 +714,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) {
allChangedChartFiles, err := t.git.ListChangedFilesInDirs(mergeBase, cfg.ChartDirs...)
if err != nil {
return nil, errors.Wrap(err, "Error creating diff")
return nil, fmt.Errorf("failed creating diff: %w", err)
}
var changedChartDirs []string
@@ -726,7 +725,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) {
}
dir := filepath.Dir(file)
// Make sure directory is really a chart directory
chartDir, err := t.chartUtils.LookupChartDir(cfg.ChartDirs, dir)
chartDir, err := t.utils.LookupChartDir(cfg.ChartDirs, dir)
chartDirElement := strings.Split(chartDir, "/")
if err == nil {
if len(chartDirElement) > 1 {
@@ -740,7 +739,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) {
changedChartDirs = append(changedChartDirs, chartDir)
}
} else {
fmt.Fprintf(os.Stderr, "Directory '%s' is not a valid chart directory. Skipping...\n", dir)
fmt.Fprintf(os.Stderr, "Directory %q is not a valid chart directory. Skipping...\n", dir)
}
}
@@ -756,11 +755,11 @@ func (t *Testing) ReadAllChartDirectories() ([]string, error) {
for _, chartParentDir := range cfg.ChartDirs {
dirs, err := t.directoryLister.ListChildDirs(chartParentDir,
func(dir string) bool {
_, err := t.chartUtils.LookupChartDir(cfg.ChartDirs, dir)
_, err := t.utils.LookupChartDir(cfg.ChartDirs, dir)
return err == nil && !util.StringSliceContains(cfg.ExcludedCharts, filepath.Base(dir))
})
if err != nil {
return nil, errors.Wrap(err, "Error reading chart directories")
return nil, fmt.Errorf("failed reading chart directories: %w", err)
}
chartDirs = append(chartDirs, dirs...)
}
@@ -770,7 +769,7 @@ func (t *Testing) ReadAllChartDirectories() ([]string, error) {
// CheckVersionIncrement checks that the new chart version is greater than the old one using semantic version comparison.
func (t *Testing) CheckVersionIncrement(chart *Chart) error {
fmt.Printf("Checking chart '%s' for a version bump...\n", chart)
fmt.Printf("Checking chart %q for a version bump...\n", chart)
oldVersion, err := t.GetOldChartVersion(chart.Path())
if err != nil {
@@ -793,7 +792,7 @@ func (t *Testing) CheckVersionIncrement(chart *Chart) error {
}
if result >= 0 {
return errors.New("Chart version not ok. Needs a version bump!")
return errors.New("chart version not ok. Needs a version bump! ")
}
fmt.Println("Chart version ok.")
@@ -827,12 +826,12 @@ func (t *Testing) GetOldChartVersion(chartPath string) (string, error) {
chartYamlContents, err := t.git.Show(chartYamlFile, cfg.Remote, cfg.TargetBranch)
if err != nil {
return "", errors.Wrap(err, "Error reading old Chart.yaml")
return "", fmt.Errorf("failed reading old Chart.yaml: %w", err)
}
chartYaml, err := util.UnmarshalChartYaml([]byte(chartYamlContents))
if err != nil {
return "", errors.Wrap(err, "Error reading old chart version")
return "", fmt.Errorf("failed reading old chart version: %w", err)
}
return chartYaml.Version, nil
@@ -847,22 +846,22 @@ func (t *Testing) ValidateMaintainers(chart *Chart) error {
if chartYaml.Deprecated {
if len(chartYaml.Maintainers) > 0 {
return errors.New("Deprecated chart must not have maintainers")
return errors.New("deprecated chart must not have maintainers")
}
return nil
}
if len(chartYaml.Maintainers) == 0 {
return errors.New("Chart doesn't have maintainers")
return errors.New("chart doesn't have maintainers")
}
repoUrl, err := t.git.GetUrlForRemote(t.config.Remote)
repoURL, err := t.git.GetURLForRemote(t.config.Remote)
if err != nil {
return err
}
for _, maintainer := range chartYaml.Maintainers {
if err := t.accountValidator.Validate(repoUrl, maintainer.Name); err != nil {
if err := t.accountValidator.Validate(repoURL, maintainer.Name); err != nil {
return err
}
}
@@ -871,7 +870,7 @@ func (t *Testing) ValidateMaintainers(chart *Chart) error {
}
func (t *Testing) PrintEventsPodDetailsAndLogs(namespace string, selector string) {
util.PrintDelimiterLine("=")
util.PrintDelimiterLineToWriter(os.Stdout, "=")
printDetails(namespace, "Events of namespace", ".", func(item string) error {
return t.kubectl.GetEvents(namespace)
@@ -909,7 +908,7 @@ func (t *Testing) PrintEventsPodDetailsAndLogs(namespace string, selector string
containers, err := t.kubectl.GetContainers(namespace, pod)
if err != nil {
fmt.Println("Error printing logs:", err)
fmt.Printf("failed printing logs: %v\n", err.Error())
return
}
@@ -920,24 +919,24 @@ func (t *Testing) PrintEventsPodDetailsAndLogs(namespace string, selector string
containers...)
}
util.PrintDelimiterLine("=")
util.PrintDelimiterLineToWriter(os.Stdout, "=")
}
func printDetails(resource string, text string, delimiterChar string, printFunc func(item string) error, items ...string) {
for _, item := range items {
item = strings.Trim(item, "'")
util.PrintDelimiterLine(delimiterChar)
util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
fmt.Printf("==> %s %s\n", text, resource)
util.PrintDelimiterLine(delimiterChar)
util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
if err := printFunc(item); err != nil {
fmt.Println("Error printing details:", err)
return
}
util.PrintDelimiterLine(delimiterChar)
util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
fmt.Printf("<== %s %s\n", text, resource)
util.PrintDelimiterLine(delimiterChar)
util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
}
}

View File

@@ -21,7 +21,6 @@ import (
"github.com/helm/chart-testing/v3/pkg/config"
"github.com/helm/chart-testing/v3/pkg/util"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -63,7 +62,7 @@ func (g fakeGit) RemoveWorktree(path string) error {
return nil
}
func (g fakeGit) GetUrlForRemote(remote string) (string, error) {
func (g fakeGit) GetURLForRemote(remote string) (string, error) {
return "git@github.com/helm/chart-testing", nil
}
@@ -77,7 +76,7 @@ func (v fakeAccountValidator) Validate(repoDomain string, account string) error
if strings.HasPrefix(account, "valid") {
return nil
}
return errors.New(fmt.Sprintf("Error validating account: %s", account))
return fmt.Errorf("failed validating account: %s", account)
}
type fakeLinter struct {
@@ -145,7 +144,7 @@ func newTestingMock(cfg config.Configuration) Testing {
config: cfg,
directoryLister: util.DirectoryLister{},
git: fakeGit{},
chartUtils: util.ChartUtils{},
utils: util.Utils{},
accountValidator: fakeAccountValidator{},
linter: fakeMockLinter,
helm: new(fakeHelm),
@@ -299,7 +298,6 @@ func TestLintChartSchemaValidation(t *testing.T) {
runTests(true, 0, 1)
runTests(false, 0, 0)
}
func TestLintYamlValidation(t *testing.T) {

View File

@@ -38,7 +38,7 @@ func newTestingHelmIntegration(cfg config.Configuration, extraSetArgs string) Te
config: cfg,
directoryLister: util.DirectoryLister{},
git: fakeGit{},
chartUtils: util.ChartUtils{},
utils: util.Utils{},
accountValidator: fakeAccountValidator{},
linter: fakeMockLinter,
helm: tool.NewHelm(procExec, extraArgs, strings.Fields(extraSetArgs)),
@@ -121,7 +121,7 @@ func TestUpgradeChart(t *testing.T) {
Upgrade: true,
}
ct := newTestingHelmIntegration(cfg, "")
processError := fmt.Errorf("Error waiting for process: exit status 1")
processError := fmt.Errorf("failed waiting for process: exit status 1")
cases := []testCase{
{

View File

@@ -15,6 +15,7 @@
package config
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -25,7 +26,6 @@ import (
"github.com/mitchellh/go-homedir"
"github.com/helm/chart-testing/v3/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
"github.com/spf13/viper"
@@ -45,7 +45,7 @@ type Configuration struct {
Remote string `mapstructure:"remote"`
TargetBranch string `mapstructure:"target-branch"`
Since string `mapstructure:"since"`
BuildId string `mapstructure:"build-id"`
BuildID string `mapstructure:"build-id"`
LintConf string `mapstructure:"lint-conf"`
ChartYamlSchema string `mapstructure:"chart-yaml-schema"`
ValidateMaintainers bool `mapstructure:"validate-maintainers"`
@@ -73,14 +73,14 @@ type Configuration struct {
func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*Configuration, error) {
v := viper.New()
v.SetDefault("kubectl-timeout", time.Duration(30*time.Second))
v.SetDefault("kubectl-timeout", 30*time.Second)
cmd.Flags().VisitAll(func(flag *flag.Flag) {
flagName := flag.Name
if flagName != "config" && flagName != "help" {
if err := v.BindPFlag(flagName, flag); err != nil {
// can't really happen
panic(fmt.Sprintln(errors.Wrapf(err, "Error binding flag '%s'", flagName)))
panic(fmt.Sprintf("failed binding flag %q: %v\n", flagName, err.Error()))
}
}
})
@@ -105,7 +105,7 @@ func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*C
if err := v.ReadInConfig(); err != nil {
if cfgFile != "" {
// Only error out for specified config file. Ignore for default locations.
return nil, errors.Wrap(err, "Error loading config file")
return nil, fmt.Errorf("failed loading config file: %w", err)
}
} else {
if printConfig {
@@ -118,7 +118,7 @@ func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*C
cfg := &Configuration{}
if err := v.Unmarshal(cfg); err != nil {
return nil, errors.Wrap(err, "Error unmarshaling configuration")
return nil, fmt.Errorf("failed unmarshaling configuration: %w", err)
}
if cfg.ProcessAllCharts && len(cfg.Charts) > 0 {
@@ -202,5 +202,5 @@ func findConfigFile(fileName string) (string, error) {
}
}
return "", errors.New(fmt.Sprintf("Config file not found: %s", fileName))
return "", fmt.Errorf("config file not found: %s", fileName)
}

View File

@@ -40,7 +40,7 @@ func loadAndAssertConfigFromFile(t *testing.T, configFile string) {
require.Equal(t, "origin", cfg.Remote)
require.Equal(t, "main", cfg.TargetBranch)
require.Equal(t, "pr-42", cfg.BuildId)
require.Equal(t, "pr-42", cfg.BuildID)
require.Equal(t, "my-lint-conf.yaml", cfg.LintConf)
require.Equal(t, "my-chart-yaml-schema.yaml", cfg.ChartYamlSchema)
require.Equal(t, true, cfg.ValidateMaintainers)

View File

@@ -23,7 +23,6 @@ import (
"strings"
"github.com/helm/chart-testing/v3/pkg/util"
"github.com/pkg/errors"
)
type ProcessExecutor struct {
@@ -54,7 +53,7 @@ func (p ProcessExecutor) RunProcessInDirAndCaptureOutput(workingDirectory string
bytes, err := cmd.CombinedOutput()
if err != nil {
return "", errors.Wrap(err, "Error running process")
return "", fmt.Errorf("failed running process: %w", err)
}
return strings.TrimSpace(string(bytes)), nil
}
@@ -69,7 +68,7 @@ func (p ProcessExecutor) RunProcessInDirAndCaptureStdout(workingDirectory string
bytes, err := cmd.Output()
if err != nil {
return "", errors.Wrap(err, "Error running process")
return "", fmt.Errorf("failed running process: %w", err)
}
return strings.TrimSpace(string(bytes)), nil
}
@@ -82,12 +81,12 @@ func (p ProcessExecutor) RunProcess(executable string, execArgs ...interface{})
outReader, err := cmd.StdoutPipe()
if err != nil {
return errors.Wrap(err, "Error getting StdoutPipe for command")
return fmt.Errorf("failed getting StdoutPipe for command: %w", err)
}
errReader, err := cmd.StderrPipe()
if err != nil {
return errors.Wrap(err, "Error getting StderrPipe for command")
return fmt.Errorf("failed getting StderrPipe for command: %w", err)
}
scanner := bufio.NewScanner(io.MultiReader(outReader, errReader))
@@ -99,12 +98,12 @@ func (p ProcessExecutor) RunProcess(executable string, execArgs ...interface{})
err = cmd.Start()
if err != nil {
return errors.Wrap(err, "Error running process")
return fmt.Errorf("failed running process: %w", err)
}
err = cmd.Wait()
if err != nil {
return errors.Wrap(err, "Error waiting for process")
return fmt.Errorf("failed waiting for process: %w", err)
}
return nil
@@ -116,7 +115,7 @@ func (p ProcessExecutor) CreateProcess(executable string, execArgs ...interface{
fmt.Println(">>>", executable, strings.Join(args, " "))
}
if err != nil {
return nil, errors.Wrap(err, "Invalid arguments supplied")
return nil, fmt.Errorf("invalid arguments supplied: %w", err)
}
cmd := exec.Command(executable, args...)
@@ -128,25 +127,25 @@ type fn func(port int) error
func (p ProcessExecutor) RunWithProxy(withProxy fn) error {
randomPort, err := util.GetRandomPort()
if err != nil {
return errors.Wrap(err, "Could not find a free port for running 'kubectl proxy'")
return fmt.Errorf("could not find a free port for running 'kubectl proxy': %w", err)
}
fmt.Printf("Running 'kubectl proxy' on port %d\n", randomPort)
cmdProxy, err := p.CreateProcess("kubectl", "proxy", fmt.Sprintf("--port=%d", randomPort))
if err != nil {
return errors.Wrap(err, "Error creating the 'kubectl proxy' process")
return fmt.Errorf("failed creating the 'kubectl proxy' process: %w", err)
}
err = cmdProxy.Start()
if err != nil {
return errors.Wrap(err, "Error starting the 'kubectl proxy' process")
return fmt.Errorf("failed starting the 'kubectl proxy' process: %w", err)
}
err = withProxy(randomPort)
cmdProxy.Process.Signal(os.Kill)
_ = cmdProxy.Process.Signal(os.Kill)
if err != nil {
return errors.Wrap(err, "Error running command with proxy")
return fmt.Errorf("failed running command with proxy: %w", err)
}
return nil

View File

@@ -18,8 +18,6 @@ import (
"fmt"
"net/http"
"regexp"
"github.com/pkg/errors"
)
type AccountValidator struct{}
@@ -32,12 +30,12 @@ func (v AccountValidator) Validate(repoURL string, account string) error {
return err
}
url := fmt.Sprintf("https://%s/%s", domain, account)
response, err := http.Head(url)
response, err := http.Head(url) // nolint: gosec
if err != nil {
return errors.Wrap(err, "Error validating maintainers")
return fmt.Errorf("failed validating maintainers: %w", err)
}
if response.StatusCode != 200 {
return fmt.Errorf("Error validating maintainer '%s': %s", account, response.Status)
return fmt.Errorf("failed validating maintainer %q: %s", account, response.Status)
}
return nil
}
@@ -46,7 +44,7 @@ func parseOutGitRepoDomain(repoURL string) (string, error) {
// This works for GitHub, Bitbucket, and Gitlab
submatch := repoDomainPattern.FindStringSubmatch(repoURL)
if submatch == nil || len(submatch) < 2 {
return "", fmt.Errorf("Could not parse git repository domain for '%s'", repoURL)
return "", fmt.Errorf("could not parse git repository domain for %q", repoURL)
}
return submatch[1], nil
}

View File

@@ -10,7 +10,7 @@ import (
func TestParseOutGitDomain(t *testing.T) {
var testDataSlice = []struct {
name string
repoUrl string
repoURL string
expected string
err error
}{
@@ -23,12 +23,12 @@ func TestParseOutGitDomain(t *testing.T) {
{"Bitbucket SSH", "git@bitbucket.com:foo/bar", "bitbucket.com", nil},
{"Bitbucket HTTPS", "https://bitbucket.com/foo/bar", "bitbucket.com", nil},
{"Bitbucket HTTPS with username/password", "https://user:pass@bitbucket.com/foo/bar", "bitbucket.com", nil},
{"Invalid", "foo/bar", "", fmt.Errorf("Could not parse git repository domain for 'foo/bar'")},
{"Invalid", "foo/bar", "", fmt.Errorf("could not parse git repository domain for \"foo/bar\"")},
}
for _, testData := range testDataSlice {
t.Run(testData.name, func(t *testing.T) {
actual, err := parseOutGitRepoDomain(testData.repoUrl)
actual, err := parseOutGitRepoDomain(testData.repoURL)
assert.Equal(t, err, testData.err)
assert.Equal(t, testData.expected, actual)
})

View File

@@ -69,8 +69,8 @@ func TestCmdTemplateExecutor_RunCommand(t *testing.T) {
if err := templateExecutor.RunCommand(tt.args.cmdTemplate, tt.args.data); (err != nil) != tt.wantErr {
t.Errorf("RunCommand() error = %v, wantErr %v", err, tt.wantErr)
}
tt.validate(t, processExecutor)
tt.validate(t, processExecutor)
})
}
}

View File

@@ -19,7 +19,6 @@ import (
"strings"
"github.com/helm/chart-testing/v3/pkg/exec"
"github.com/pkg/errors"
)
type Git struct {
@@ -59,7 +58,7 @@ func (g Git) ListChangedFilesInDirs(commit string, dirs ...string) ([]string, er
changedChartFilesString, err :=
g.exec.RunProcessAndCaptureOutput("git", "diff", "--find-renames", "--name-only", commit, "--", dirs)
if err != nil {
return nil, errors.Wrap(err, "Error creating diff")
return nil, fmt.Errorf("failed creating diff: %w", err)
}
if changedChartFilesString == "" {
return nil, nil
@@ -67,7 +66,7 @@ func (g Git) ListChangedFilesInDirs(commit string, dirs ...string) ([]string, er
return strings.Split(changedChartFilesString, "\n"), nil
}
func (g Git) GetUrlForRemote(remote string) (string, error) {
func (g Git) GetURLForRemote(remote string) (string, error) {
return g.exec.RunProcessAndCaptureOutput("git", "ls-remote", "--get-url", remote)
}

View File

@@ -83,7 +83,7 @@ func (h Helm) Test(namespace string, release string) error {
}
func (h Helm) DeleteRelease(namespace string, release string) {
fmt.Printf("Deleting release '%s'...\n", release)
fmt.Printf("Deleting release %q...\n", release)
if err := h.exec.RunProcess("helm", "uninstall", release, "--namespace", namespace, h.extraArgs); err != nil {
fmt.Println("Error deleting Helm release:", err)
}

View File

@@ -3,6 +3,7 @@ package tool
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
@@ -10,7 +11,6 @@ import (
"github.com/hashicorp/go-retryablehttp"
"github.com/helm/chart-testing/v3/pkg/exec"
"github.com/pkg/errors"
)
type Kubectl struct {
@@ -27,7 +27,7 @@ func NewKubectl(exec exec.ProcessExecutor, timeout time.Duration) Kubectl {
// CreateNamespace creates a new namespace with the given name.
func (k Kubectl) CreateNamespace(namespace string) error {
fmt.Printf("Creating namespace '%s'...\n", namespace)
fmt.Printf("Creating namespace %q...\n", namespace)
return k.exec.RunProcess("kubectl",
fmt.Sprintf("--request-timeout=%s", k.timeout),
"create", "namespace", namespace)
@@ -36,17 +36,17 @@ func (k Kubectl) CreateNamespace(namespace string) error {
// DeleteNamespace deletes the specified namespace. If the namespace does not terminate within 120s, pods running in the
// namespace and, eventually, the namespace itself are force-deleted.
func (k Kubectl) DeleteNamespace(namespace string) {
fmt.Printf("Deleting namespace '%s'...\n", namespace)
fmt.Printf("Deleting namespace %q...\n", namespace)
timeoutSec := "180s"
err := k.exec.RunProcess("kubectl",
fmt.Sprintf("--request-timeout=%s", k.timeout),
"delete", "namespace", namespace, "--timeout", timeoutSec)
if err != nil {
fmt.Printf("Namespace '%s' did not terminate after %s.\n", namespace, timeoutSec)
fmt.Printf("Namespace %q did not terminate after %s.\n", namespace, timeoutSec)
}
if k.getNamespace(namespace) {
fmt.Printf("Namespace '%s' did not terminate after %s.\n", namespace, timeoutSec)
fmt.Printf("Namespace %q did not terminate after %s.\n", namespace, timeoutSec)
fmt.Println("Force-deleting everything...")
err = k.exec.RunProcess("kubectl",
@@ -93,7 +93,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
// Remove finalizer from the namespace
fun := func(port int) error {
fmt.Printf("Removing finalizers from namespace '%s'...\n", namespace)
fmt.Printf("Removing finalizers from namespace %q...\n", namespace)
k8sURL := fmt.Sprintf("http://127.0.0.1:%d/api/v1/namespaces/%s/finalize", port, namespace)
req, err := retryablehttp.NewRequest("PUT", k8sURL, bytes.NewReader(namespaceUpdateBytes))
@@ -107,7 +107,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
client := retryablehttp.NewClient()
client.Logger = nil
if resp, err := client.Do(req); err != nil {
return errors.Wrap(err, errMsg)
return fmt.Errorf("%s:%w", errMsg, err)
} else if resp.StatusCode != http.StatusOK {
return errors.New(errMsg)
}
@@ -117,7 +117,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
err = k.exec.RunWithProxy(fun)
if err != nil {
return errors.Wrapf(err, "Cannot force-delete namespace '%s'", namespace)
return fmt.Errorf("cannot force-delete namespace %q: %w", namespace, err)
}
// Give it some more time to be deleted by K8s
@@ -128,11 +128,11 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
fmt.Sprintf("--request-timeout=%s", k.timeout),
"get", "namespace", namespace)
if err != nil {
fmt.Printf("Namespace '%s' terminated.\n", namespace)
fmt.Printf("Namespace %q terminated.\n", namespace)
return nil
}
fmt.Printf("Force-deleting namespace '%s'...\n", namespace)
fmt.Printf("Force-deleting namespace %q...\n", namespace)
err = k.exec.RunProcess("kubectl",
fmt.Sprintf("--request-timeout=%s", k.timeout),
"delete", "namespace", namespace, "--force", "--grace-period=0",
@@ -250,7 +250,7 @@ func (k Kubectl) getNamespace(namespace string) bool {
fmt.Sprintf("--request-timeout=%s", k.timeout),
"get", "namespace", namespace)
if err != nil {
fmt.Printf("Namespace '%s' terminated.\n", namespace)
fmt.Printf("Namespace %q terminated.\n", namespace)
return false
}

View File

@@ -15,9 +15,10 @@
package util
import (
"errors"
"fmt"
"io"
"io/ioutil"
"io/fs"
"math/rand"
"net"
"os"
@@ -28,7 +29,6 @@ import (
"github.com/Masterminds/semver"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
@@ -70,7 +70,7 @@ func doFlatten(result []string, items interface{}) ([]string, error) {
}
}
default:
return nil, errors.New(fmt.Sprintf("Flatten does not support %T", v))
return nil, fmt.Errorf("flatten does not support %T", v)
}
return result, err
@@ -97,7 +97,7 @@ func RandomString(length int) string {
n := len(chars)
bytes := make([]byte, length)
for i := range bytes {
bytes[i] = chars[rand.Intn(n)]
bytes[i] = chars[rand.Intn(n)] // nolint: gosec
}
return string(bytes)
}
@@ -106,10 +106,18 @@ type DirectoryLister struct{}
// ListChildDirs lists subdirectories of parentDir matching the test function.
func (l DirectoryLister) ListChildDirs(parentDir string, test func(dir string) bool) ([]string, error) {
fileInfos, err := ioutil.ReadDir(parentDir)
entries, err := os.ReadDir(parentDir)
if err != nil {
return nil, err
}
fileInfos := make([]fs.FileInfo, 0, len(entries))
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
return nil, err
}
fileInfos = append(fileInfos, info)
}
var dirs []string
for _, dir := range fileInfos {
@@ -123,9 +131,9 @@ func (l DirectoryLister) ListChildDirs(parentDir string, test func(dir string) b
return dirs, nil
}
type ChartUtils struct{}
type Utils struct{}
func (u ChartUtils) LookupChartDir(chartDirs []string, dir string) (string, error) {
func (u Utils) LookupChartDir(chartDirs []string, dir string) (string, error) {
for _, chartDir := range chartDirs {
currentDir := dir
for {
@@ -154,9 +162,9 @@ func (u ChartUtils) LookupChartDir(chartDirs []string, dir string) (string, erro
// and return a newly allocated ChartYaml object. If no Chart.yaml is present
// or there is an error unmarshaling the file contents, an error will be returned.
func ReadChartYaml(dir string) (*ChartYaml, error) {
yamlBytes, err := ioutil.ReadFile(filepath.Join(dir, "Chart.yaml"))
yamlBytes, err := os.ReadFile(filepath.Join(dir, "Chart.yaml"))
if err != nil {
return nil, errors.Wrap(err, "Could not read 'Chart.yaml'")
return nil, fmt.Errorf("could not read 'Chart.yaml': %w", err)
}
return UnmarshalChartYaml(yamlBytes)
}
@@ -166,7 +174,7 @@ func ReadChartYaml(dir string) (*ChartYaml, error) {
func UnmarshalChartYaml(yamlBytes []byte) (*ChartYaml, error) {
chartYaml := &ChartYaml{}
if err := yaml.Unmarshal(yamlBytes, chartYaml); err != nil {
return nil, errors.Wrap(err, "Could not unmarshal 'Chart.yaml'")
return nil, fmt.Errorf("could not unmarshal 'Chart.yaml': %w", err)
}
return chartYaml, nil
}
@@ -174,11 +182,11 @@ func UnmarshalChartYaml(yamlBytes []byte) (*ChartYaml, error) {
func CompareVersions(left string, right string) (int, error) {
leftVersion, err := semver.NewVersion(left)
if err != nil {
return 0, errors.Wrap(err, "Error parsing semantic version")
return 0, fmt.Errorf("failed parsing semantic version: %w", err)
}
rightVersion, err := semver.NewVersion(right)
if err != nil {
return 0, errors.Wrap(err, "Error parsing semantic version")
return 0, fmt.Errorf("failed parsing semantic version: %w", err)
}
return leftVersion.Compare(rightVersion), nil
}
@@ -186,11 +194,11 @@ func CompareVersions(left string, right string) (int, error) {
func BreakingChangeAllowed(left string, right string) (bool, error) {
leftVersion, err := semver.NewVersion(left)
if err != nil {
return false, errors.Wrap(err, "Error parsing semantic version")
return false, fmt.Errorf("failed parsing semantic version: %w", err)
}
rightVersion, err := semver.NewVersion(right)
if err != nil {
return false, errors.Wrap(err, "Error parsing semantic version")
return false, fmt.Errorf("failed parsing semantic version: %w", err)
}
constraintOp := "^"
@@ -199,7 +207,7 @@ func BreakingChangeAllowed(left string, right string) (bool, error) {
}
c, err := semver.NewConstraint(fmt.Sprintf("%s %s", constraintOp, leftVersion.String()))
if err != nil {
return false, errors.Wrap(err, "Error parsing semantic version constraint")
return false, fmt.Errorf("failed parsing semantic version constraint: %w", err)
}
minor, reasons := c.Validate(rightVersion)
@@ -210,11 +218,6 @@ func BreakingChangeAllowed(left string, right string) (bool, error) {
return !minor, err
}
// Deprecated: To be removed in v4. Use PrintDelimiterLineToWriter instead.
func PrintDelimiterLine(delimiterChar string) {
PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
}
func PrintDelimiterLineToWriter(w io.Writer, delimiterChar string) {
delim := make([]string, 120)
for i := 0; i < 120; i++ {
@@ -235,8 +238,8 @@ func SanitizeName(s string, maxLength int) string {
}
func GetRandomPort() (int, error) {
listener, err := net.Listen("tcp", ":0")
defer listener.Close()
listener, err := net.Listen("tcp", ":0") // nolint: gosec
defer listener.Close() // nolint: staticcheck
if err != nil {
return 0, err
}