-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ci(helm): auto public Helm chart after PR merged (#7526)
- Loading branch information
Showing
6 changed files
with
260 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,11 @@ name: Publish Helm chart | |
on: | ||
workflow_dispatch: | ||
pull_request: | ||
types: | ||
- opened | ||
- synchronize | ||
- reopened | ||
- closed | ||
branches: | ||
- main | ||
paths: | ||
|
@@ -18,8 +23,10 @@ env: | |
KIND_VERSION: "v0.14.0" | ||
KIND_IMAGE: "kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae" | ||
jobs: | ||
# `test-chart` job starts if a PR with Helm Chart is created, merged etc. | ||
test-chart: | ||
runs-on: ubuntu-20.04 | ||
if: github.event_name != 'push' | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- name: Checkout | ||
uses: actions/[email protected] | ||
|
@@ -28,11 +35,12 @@ jobs: | |
- name: Install Helm | ||
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 | ||
with: | ||
version: v3.5.0 | ||
version: v3.14.4 | ||
- name: Set up python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: 3.7 | ||
python-version: '3.x' | ||
check-latest: true | ||
- name: Setup Chart Linting | ||
id: lint | ||
uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992 | ||
|
@@ -48,11 +56,39 @@ jobs: | |
sed -i -e '136s,false,'true',g' ./helm/trivy/values.yaml | ||
ct lint-and-install --validate-maintainers=false --charts helm/trivy | ||
# `update-chart-version` job starts if a new tag is pushed | ||
update-chart-version: | ||
if: github.event_name == 'push' | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- name: Checkout | ||
uses: actions/[email protected] | ||
with: | ||
fetch-depth: 0 | ||
- name: Set up Git user | ||
run: | | ||
git config --global user.email "[email protected]" | ||
git config --global user.name "GitHub Actions" | ||
- name: Install tools | ||
uses: aquaproj/[email protected] | ||
with: | ||
aqua_version: v1.25.0 | ||
aqua_opts: "" | ||
|
||
- name: Create a PR with Trivy version | ||
run: mage helm:updateVersion | ||
env: | ||
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN | ||
# This allows the created PR to trigger tests and other workflows | ||
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }} | ||
|
||
# `publish-chart` job starts if a PR with a new Helm Chart is merged or manually | ||
publish-chart: | ||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' | ||
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' | ||
needs: | ||
- test-chart | ||
runs-on: ubuntu-20.04 | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- name: Checkout | ||
uses: actions/[email protected] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//go:build mage_helm | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
|
||
"github.com/aquasecurity/go-version/pkg/semver" | ||
|
||
"github.com/magefile/mage/sh" | ||
"golang.org/x/xerrors" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
const chartFile = "./helm/trivy/Chart.yaml" | ||
|
||
func main() { | ||
trivyVersion, err := version() | ||
if err != nil { | ||
log.Fatalf("could not determine Trivy version: %v", err) | ||
} | ||
|
||
newHelmVersion, err := bumpHelmChart(chartFile, trivyVersion) | ||
if err != nil { | ||
log.Fatalf("could not bump Trivy version to %q: %v", trivyVersion, err) | ||
} | ||
|
||
log.Printf("Current helm version will bump up %q with Trivy %q", newHelmVersion, trivyVersion) | ||
|
||
newBranch := fmt.Sprintf("ci/helm-chart/bump-trivy-to-%s", trivyVersion) | ||
title := fmt.Sprintf("ci(helm): bump Trivy version to %s for Trivy Helm Chart %s", trivyVersion, newHelmVersion) | ||
description := fmt.Sprintf("This PR bumps Trivy up to the %s version for the Trivy Helm chart %s.", | ||
trivyVersion, newHelmVersion) | ||
|
||
cmds := [][]string{ | ||
[]string{"git", "switch", "-c", newBranch}, | ||
[]string{"git", "add", chartFile}, | ||
[]string{"git", "commit", "-m", title}, | ||
[]string{"git", "push", "origin", newBranch}, | ||
[]string{"gh", "pr", "create", "--base", "main", "--head", newBranch, "--title", title, "--body", description, "--repo", "$GITHUB_REPOSITORY"}, | ||
} | ||
|
||
if err := runShCommands(cmds); err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Print("Successfully created PR with a new helm version") | ||
} | ||
|
||
type Chart struct { | ||
Version string `yaml:"version"` | ||
AppVersion string `yaml:"appVersion"` | ||
} | ||
|
||
// bumpHelmChart bumps up helm and trivy versions inside a file (Chart.yaml) | ||
// it returns a new helm version and error | ||
func bumpHelmChart(filename, trivyVersion string) (string, error) { | ||
input, err := os.ReadFile(filename) | ||
if err != nil { | ||
return "", xerrors.Errorf("could not read file %q: %w", filename, err) | ||
} | ||
currentHelmChart := &Chart{} | ||
if err := yaml.Unmarshal(input, currentHelmChart); err != nil { | ||
return "", xerrors.Errorf("could not unmarshal helm chart %q: %w", filename, err) | ||
} | ||
|
||
newHelmVersion, err := buildNewHelmVersion(currentHelmChart.Version, currentHelmChart.AppVersion, trivyVersion) | ||
if err != nil { | ||
return "", xerrors.Errorf("could not build new helm version: %v", err) | ||
} | ||
cmds := [][]string{ | ||
[]string{"sed", "-i", "-e", fmt.Sprintf("s/appVersion: %s/appVersion: %s/g", currentHelmChart.AppVersion, trivyVersion), filename}, | ||
[]string{"sed", "-i", "-e", fmt.Sprintf("s/version: %s/version: %s/g", currentHelmChart.Version, newHelmVersion), filename}, | ||
} | ||
|
||
if err := runShCommands(cmds); err != nil { | ||
return "", xerrors.Errorf("could not update Helm Chart %q: %w", newHelmVersion, err) | ||
} | ||
return newHelmVersion, nil | ||
} | ||
|
||
func runShCommands(cmds [][]string) error { | ||
for _, cmd := range cmds { | ||
if err := sh.Run(cmd[0], cmd[1:]...); err != nil { | ||
return xerrors.Errorf("failed to run %v: %w", cmd, err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func buildNewHelmVersion(currentHelm, currentTrivy, newTrivy string) (string, error) { | ||
currentHelmVersion, err := semver.Parse(currentHelm) | ||
if err != nil { | ||
return "", xerrors.Errorf("could not parse current helm version: %w", err) | ||
} | ||
|
||
currentTrivyVersion, err := semver.Parse(currentTrivy) | ||
if err != nil { | ||
return "", xerrors.Errorf("could not parse current trivy version: %w", err) | ||
} | ||
|
||
newTrivyVersion, err := semver.Parse(newTrivy) | ||
if err != nil { | ||
return "", xerrors.Errorf("could not parse new trivy version: %w", err) | ||
} | ||
|
||
if newTrivyVersion.Major().Compare(currentTrivyVersion.Major()) > 0 { | ||
return currentHelmVersion.IncMajor().String(), nil | ||
} | ||
|
||
if newTrivyVersion.Minor().Compare(currentTrivyVersion.Minor()) > 0 { | ||
return currentHelmVersion.IncMinor().String(), nil | ||
} | ||
|
||
return currentHelmVersion.IncPatch().String(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
//go:build mage_helm | ||
|
||
package main | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewVersion(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
currentHelmVersion string | ||
currentTrivyVersion string | ||
newTrivyVersion string | ||
newHelmVersion string | ||
}{ | ||
{ | ||
"created the first patch", | ||
"0.1.0", | ||
"0.55.0", | ||
"0.55.1", | ||
"0.1.1", | ||
}, | ||
{ | ||
"created the second patch", | ||
"0.1.1", | ||
"0.55.1", | ||
"0.55.2", | ||
"0.1.2", | ||
}, | ||
{ | ||
"created the second patch but helm chart was changed", | ||
"0.1.2", | ||
"0.55.1", | ||
"0.55.2", | ||
"0.1.3", | ||
}, | ||
{ | ||
"created a new minor version", | ||
"0.1.1", | ||
"0.55.1", | ||
"0.56.0", | ||
"0.2.0", | ||
}, | ||
{ | ||
"created a new major version", | ||
"0.1.1", | ||
"0.55.1", | ||
"1.0.0", | ||
"1.0.0", | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
newHelmVersion, err := buildNewHelmVersion(test.currentHelmVersion, test.currentTrivyVersion, test.newTrivyVersion) | ||
assert.NoError(t, err) | ||
assert.Equal(t, test.newHelmVersion, newHelmVersion) | ||
}) | ||
} | ||
} | ||
|
||
func TestBumpHelmChart_Success(t *testing.T) { | ||
tempFile, err := os.CreateTemp(t.TempDir(), "Chart-*.yaml") | ||
assert.NoError(t, err) | ||
|
||
content := ` | ||
apiVersion: v2 | ||
name: trivy | ||
version: 0.8.0 | ||
appVersion: 0.55.0 | ||
description: Trivy helm chart | ||
keywords: | ||
- scanner | ||
- trivy | ||
- vulnerability | ||
` | ||
err = os.WriteFile(tempFile.Name(), []byte(content), 0644) | ||
assert.NoError(t, err) | ||
|
||
newVersion, err := bumpHelmChart(tempFile.Name(), "0.55.1") | ||
assert.NoError(t, err) | ||
assert.Equal(t, "0.8.1", newVersion) | ||
|
||
updatedContent, err := os.ReadFile(tempFile.Name()) | ||
assert.NoError(t, err) | ||
assert.Contains(t, string(updatedContent), "appVersion: 0.55.1") | ||
assert.Contains(t, string(updatedContent), "version: 0.8.1") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters