Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

helm: add arkade chart bump to bump chart versions #1024

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ With over 120 CLIs and 55 Kubernetes apps (charts, manifests, installers) availa
- [Download CLI tools with arkade](#download-cli-tools-with-arkade)
- [Install System Packages](#install-system-packages)
- [Install CLIs during CI with GitHub Actions](#install-clis-during-ci-with-github-actions)
- [Bump Helm chart versions](#bump-helm-chart-versions)
- [Verify and upgrade images in Helm charts](#verify-and-upgrade-images-in-helm-charts)
- [Upgrade images within a Helm chart](#upgrade-images-within-a-helm-chart)
- [Verify images within a helm chart](#verify-images-within-a-helm-chart)
Expand Down Expand Up @@ -283,6 +284,25 @@ If you just need system applications, you could also try "setup-arkade":
arkade system install go
```

## Bump Helm chart versions

To bump the patch version of your Helm chart, run `arkade chart bump -f ./chart/values.yaml`. This updates the patch component of the version specified in Chart.yaml.

```bash
arkade chart bump -f ./charts/flagger/values.yaml
charts/flagger/Chart.yaml 1.36.0 => 1.37.0
```

By default, the new version is written to stdout. To bump the version in the file, run the above command with the `--write` flag.
To bump the version in the chart's Chart.yaml only if the chart has any changes, specify the `--check-for-updates` flag:

```bash
arkade chart bump -f ./charts/flagger/values.yaml --check-for-updates
no changes detected in charts/flagger/values.yaml; skipping version bump
```

The directory that contains the Helm chart should be a Git repository. If the flag is specified, the command runs `git diff --exit-code <file>` to figure out if the file has any changes.

## Verify and upgrade images in Helm charts

There are two commands built into arkade designed for software vendors and open source maintainers.
Expand Down
133 changes: 133 additions & 0 deletions cmd/chart/bump.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package chart

import (
"context"
"fmt"
"log"
"os"
"path/filepath"

"github.com/Masterminds/semver"
"github.com/alexellis/arkade/pkg/helm"
"github.com/alexellis/go-execute/v2"
"github.com/spf13/cobra"
)

const (
versionKey = "version"
ChartYamlFileName = "Chart.yaml"
ChartYmlFileName = "Chart.yml"
)

func MakeBump() *cobra.Command {
var command = &cobra.Command{
Use: "bump",
Short: "Bump the patch version of the Helm chart.",
Long: `Bump the version present in the Chart.yaml of a Helm chart.
To bump the version only if the chart has changes then specify the
--check-for-updates flag. If the chart has no changes the command
returns early with an exit code zero.
`,
Example: `arkade chart bump -f ./chart/values.yaml
arkade chart bump -f ./charts/values.yaml --check-for-updates`,
SilenceUsage: true,
}

command.Flags().StringP("file", "f", "", "Path to values.yaml file")
command.Flags().BoolP("verbose", "v", false, "Verbose output")
command.Flags().BoolP("write", "w", false, "Write the updated values back to the file, or stdout when set to false")
command.Flags().Bool("check-for-updates", false, "Check for updates to the chart before bumping its version")

command.RunE = func(cmd *cobra.Command, args []string) error {
valuesFile, err := cmd.Flags().GetString("file")
if err != nil {
return fmt.Errorf("invalid value for --file")
}
if valuesFile == "" {
return fmt.Errorf("flag --file is required")
}
verbose, _ := cmd.Flags().GetBool("verbose")
write, err := cmd.Flags().GetBool("write")
if err != nil {
return fmt.Errorf("invalid value for --write")
}
checkForUpdates, err := cmd.Flags().GetBool("check-for-updates")
if err != nil {
return fmt.Errorf("invalid value for --check-for-updates")
}

chartDir := filepath.Dir(valuesFile)
chartYamlPath := filepath.Join(chartDir, ChartYamlFileName)

// Map with key as the path to Chart.yaml and the value as the parsed contents of Chart.yaml
var values helm.ValuesMap
// Try to read a Chart.yaml, but if thats unsuccessful then fall back to Chart.yml
if values, err = helm.Load(chartYamlPath); err != nil {
if verbose {
log.Printf("unable to read %s, falling back to Chart.yml\n", chartYamlPath)
}
chartYamlPath = filepath.Join(chartDir, ChartYmlFileName)
if values, err = helm.Load(chartYamlPath); err != nil {
return fmt.Errorf("unable to read Chart.yaml or Chart.yml in directory %s", chartDir)
}
}

// If the yaml does not contain a `version` key then error out.
if val, ok := values[versionKey]; !ok {
return fmt.Errorf("unable to find a version in %s", chartYamlPath)
} else {
version, ok := val.(string)
if !ok {
log.Printf("unable to find a valid version in %s", chartYamlPath)
}
if checkForUpdates {
absPath, err := filepath.Abs(chartDir)
if err != nil {
return err
}

// Run `git diff --exit-code <file>` to check if any files in the chart dir changed.
// An exit code of 0 indicates that there are no changes, thus we skip bumping the
// version of the chart.
cmd := execute.ExecTask{
Command: "git",
Args: []string{"diff", "--exit-code", "."},
Cwd: absPath,
}
res, err := cmd.Execute(context.Background())
if err != nil {
return fmt.Errorf("could not check updates to chart values: %s", err)
}

if res.ExitCode == 0 {
fmt.Printf("no changes detected in %s; skipping version bump\n", chartDir)
os.Exit(0)
}
}

ver, err := semver.NewVersion(version)
if err != nil {
return fmt.Errorf("%s", err)
}
newVer := ver.IncPatch()
fmt.Printf("%s %s => %s\n", chartYamlPath, ver.String(), newVer.String())
if write {
if verbose {
log.Printf("Bumping version")
}
update := map[string]string{
fmt.Sprintf("%s: %s", versionKey, ver.String()): fmt.Sprintf("%s: %s", versionKey, newVer.String()),
}
rawChartYaml, err := helm.ReplaceValuesInHelmValuesFile(update, chartYamlPath)
if err != nil {
return fmt.Errorf("unable to bump chart version in %s", chartYamlPath)
}
if err = os.WriteFile(chartYamlPath, []byte(rawChartYaml), 0600); err != nil {
return fmt.Errorf("unable to write updated yaml to %s", chartYamlPath)
}
}
}
return nil
}
return command
}
1 change: 1 addition & 0 deletions cmd/chart/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func MakeChart() *cobra.Command {

command.AddCommand(MakeVerify())
command.AddCommand(MakeUpgrade())
command.AddCommand(MakeBump())

return command
}
Loading