Skip to content

Commit b57dc7c

Browse files
authored
Merge pull request #85 from afdesk/ci/publish-helm
ci: publish helm
2 parents 9514148 + 27e38b7 commit b57dc7c

File tree

6 files changed

+257
-1
lines changed

6 files changed

+257
-1
lines changed

.github/workflows/bypass-test.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ on:
99
- 'mkdocs.yml'
1010
- 'LICENSE'
1111
- '.release-please-manifest.json'
12+
- 'helm/trivy/Chart.yaml'
1213
pull_request:
1314
paths:
1415
- '**.md'
1516
- 'docs/**'
1617
- 'mkdocs.yml'
1718
- 'LICENSE'
1819
- '.release-please-manifest.json'
20+
- 'helm/trivy/Chart.yaml'
1921
jobs:
2022
test:
2123
name: Test

.github/workflows/publish-chart.yaml

+36-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ name: Publish Helm chart
44
on:
55
workflow_dispatch:
66
pull_request:
7+
types:
8+
- opened
9+
- synchronize
10+
- reopened
11+
- closed
712
branches:
813
- main
914
paths:
@@ -18,7 +23,9 @@ env:
1823
KIND_VERSION: "v0.14.0"
1924
KIND_IMAGE: "kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae"
2025
jobs:
26+
# `test-chart` job starts if a PR with Helm Chart is created, merged etc.
2127
test-chart:
28+
if: github.event_name != 'push'
2229
runs-on: ubuntu-20.04
2330
steps:
2431
- name: Checkout
@@ -48,8 +55,36 @@ jobs:
4855
sed -i -e '136s,false,'true',g' ./helm/trivy/values.yaml
4956
ct lint-and-install --validate-maintainers=false --charts helm/trivy
5057
58+
# `update-chart-version` job starts if a new tag is pushed
59+
update-chart-version:
60+
if: github.event_name == 'push'
61+
runs-on: ubuntu-20.04
62+
steps:
63+
- name: Checkout
64+
uses: actions/[email protected]
65+
with:
66+
fetch-depth: 0
67+
- name: Set up Git user
68+
run: |
69+
git config --global user.email "[email protected]"
70+
git config --global user.name "GitHub Actions"
71+
72+
- name: Install tools
73+
uses: aquaproj/[email protected]
74+
with:
75+
aqua_version: v1.25.0
76+
aqua_opts: ""
77+
78+
- name: Create a PR with Trivy version
79+
run: mage helm:updateVersion
80+
env:
81+
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
82+
# This allows the created PR to trigger tests and other workflows
83+
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
84+
85+
# `publish-chart` job starts if a PR with a new Helm Chart is merged or manually
5186
publish-chart:
52-
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
87+
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
5388
needs:
5489
- test-chart
5590
runs-on: ubuntu-20.04

.github/workflows/test.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
- 'mkdocs.yml'
88
- 'LICENSE'
99
- '.release-please-manifest.json' ## don't run tests for release-please PRs
10+
- 'helm/trivy/Chart.yaml'
1011
merge_group:
1112
workflow_dispatch:
1213

magefiles/helm.go

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//go:build mage_helm
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
"log"
8+
"os"
9+
10+
"github.com/aquasecurity/go-version/pkg/semver"
11+
12+
"github.com/magefile/mage/sh"
13+
"golang.org/x/xerrors"
14+
"gopkg.in/yaml.v3"
15+
)
16+
17+
const chartFile = "./helm/trivy/Chart.yaml"
18+
19+
func main() {
20+
trivyVersion, err := version()
21+
if err != nil {
22+
log.Fatalf("could not determine Trivy version: %v", err)
23+
}
24+
25+
newHelmVersion, err := bumpHelmChart(chartFile, trivyVersion)
26+
if err != nil {
27+
log.Fatalf("could not bump Trivy version to %q: %v", trivyVersion, err)
28+
}
29+
30+
log.Printf("Current helm version will bump up %q with Trivy %q", newHelmVersion, trivyVersion)
31+
32+
newBranch := fmt.Sprintf("ci/helm-chart/bump-trivy-to-%s", trivyVersion)
33+
title := fmt.Sprintf("ci(helm): bump Trivy version to %s for Trivy Helm Chart %s", trivyVersion, newHelmVersion)
34+
description := fmt.Sprintf("This PR bumps Trivy up to the %s version for the Trivy Helm chart %s.",
35+
trivyVersion, newHelmVersion)
36+
37+
cmds := [][]string{
38+
[]string{"git", "switch", "-c", newBranch},
39+
[]string{"git", "add", chartFile},
40+
[]string{"git", "commit", "-m", title},
41+
[]string{"git", "push", "origin", newBranch},
42+
[]string{"gh", "pr", "create", "--base", "main", "--head", newBranch, "--title", title, "--body", description, "--repo", "$GITHUB_REPOSITORY"},
43+
}
44+
45+
if err := runShCommands(cmds); err != nil {
46+
log.Fatal(err)
47+
}
48+
log.Print("Successfully created PR with a new helm version")
49+
}
50+
51+
type Chart struct {
52+
Version string `yaml:"version"`
53+
AppVersion string `yaml:"appVersion"`
54+
}
55+
56+
// bumpHelmChart bumps up helm and trivy versions inside a file (Chart.yaml)
57+
// it returns a new helm version and error
58+
func bumpHelmChart(filename, trivyVersion string) (string, error) {
59+
input, err := os.ReadFile(filename)
60+
if err != nil {
61+
return "", xerrors.Errorf("could not read file %q: %w", filename, err)
62+
}
63+
currentHelmChart := &Chart{}
64+
if err := yaml.Unmarshal(input, currentHelmChart); err != nil {
65+
return "", xerrors.Errorf("could not unmarshal helm chart %q: %w", filename, err)
66+
}
67+
68+
newHelmVersion, err := buildNewHelmVersion(currentHelmChart.Version, currentHelmChart.AppVersion, trivyVersion)
69+
if err != nil {
70+
return "", xerrors.Errorf("could not build new helm version: %v", err)
71+
}
72+
cmds := [][]string{
73+
[]string{"sed", "-i", "-e", fmt.Sprintf("s/appVersion: %s/appVersion: %s/g", currentHelmChart.AppVersion, trivyVersion), filename},
74+
[]string{"sed", "-i", "-e", fmt.Sprintf("s/version: %s/version: %s/g", currentHelmChart.Version, newHelmVersion), filename},
75+
}
76+
77+
if err := runShCommands(cmds); err != nil {
78+
return "", xerrors.Errorf("could not update Helm Chart %q: %w", newHelmVersion, err)
79+
}
80+
return newHelmVersion, nil
81+
}
82+
83+
func runShCommands(cmds [][]string) error {
84+
for _, cmd := range cmds {
85+
if err := sh.Run(cmd[0], cmd[1:]...); err != nil {
86+
return xerrors.Errorf("failed to run %v: %w", cmd, err)
87+
}
88+
}
89+
return nil
90+
}
91+
92+
func buildNewHelmVersion(currentHelm, currentTrivy, newTrivy string) (string, error) {
93+
currentHelmVersion, err := semver.Parse(currentHelm)
94+
if err != nil {
95+
return "", xerrors.Errorf("could not parse current helm version: %w", err)
96+
}
97+
98+
currentTrivyVersion, err := semver.Parse(currentTrivy)
99+
if err != nil {
100+
return "", xerrors.Errorf("could not parse current trivy version: %w", err)
101+
}
102+
103+
newTrivyVersion, err := semver.Parse(newTrivy)
104+
if err != nil {
105+
return "", xerrors.Errorf("could not parse new trivy version: %w", err)
106+
}
107+
108+
if newTrivyVersion.Major().Compare(currentTrivyVersion.Major()) > 0 {
109+
return currentHelmVersion.IncMajor().String(), nil
110+
}
111+
112+
if newTrivyVersion.Minor().Compare(currentTrivyVersion.Minor()) > 0 {
113+
return currentHelmVersion.IncMinor().String(), nil
114+
}
115+
116+
return currentHelmVersion.IncPatch().String(), nil
117+
}

magefiles/helm_test.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//go:build mage_helm
2+
3+
package main
4+
5+
import (
6+
"io/ioutil"
7+
"os"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestNewVersion(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
currentHelmVersion string
17+
currentTrivyVersion string
18+
newTrivyVersion string
19+
newHelmVersion string
20+
}{
21+
{
22+
"created the first patch",
23+
"0.1.0",
24+
"0.55.0",
25+
"0.55.1",
26+
"0.1.1",
27+
},
28+
{
29+
"created the second patch",
30+
"0.1.1",
31+
"0.55.1",
32+
"0.55.2",
33+
"0.1.2",
34+
},
35+
{
36+
"created the second patch but helm chart was changed",
37+
"0.1.2",
38+
"0.55.1",
39+
"0.55.2",
40+
"0.1.3",
41+
},
42+
{
43+
"created a new minor version",
44+
"0.1.1",
45+
"0.55.1",
46+
"0.56.0",
47+
"0.2.0",
48+
},
49+
{
50+
"created a new major version",
51+
"0.1.1",
52+
"0.55.1",
53+
"1.0.0",
54+
"1.0.0",
55+
},
56+
}
57+
58+
for _, test := range tests {
59+
t.Run(test.name, func(t *testing.T) {
60+
newHelmVersion, err := buildNewHelmVersion(test.currentHelmVersion, test.currentTrivyVersion, test.newTrivyVersion)
61+
assert.NoError(t, err)
62+
assert.Equal(t, test.newHelmVersion, newHelmVersion)
63+
})
64+
}
65+
}
66+
67+
func TestBumpHelmChart_Success(t *testing.T) {
68+
tempFile, err := ioutil.TempFile("", "Chart-*.yaml")
69+
assert.NoError(t, err)
70+
defer os.Remove(tempFile.Name())
71+
72+
content := `
73+
apiVersion: v2
74+
name: trivy
75+
version: 0.8.0
76+
appVersion: 0.55.0
77+
description: Trivy helm chart
78+
keywords:
79+
- scanner
80+
- trivy
81+
- vulnerability
82+
`
83+
err = ioutil.WriteFile(tempFile.Name(), []byte(content), 0644)
84+
assert.NoError(t, err)
85+
86+
newVersion, err := bumpHelmChart(tempFile.Name(), "0.55.1")
87+
assert.NoError(t, err)
88+
assert.Equal(t, "0.8.1", newVersion)
89+
90+
updatedContent, err := ioutil.ReadFile(tempFile.Name())
91+
assert.NoError(t, err)
92+
assert.Contains(t, string(updatedContent), "appVersion: 0.55.1")
93+
assert.Contains(t, string(updatedContent), "version: 0.8.1")
94+
}

magefiles/magefile.go

+7
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,10 @@ func (CloudActions) Generate() error {
489489
func VEX(_ context.Context, dir string) error {
490490
return sh.RunWith(ENV, "go", "run", "-tags=mage_vex", "./magefiles/vex.go", "--dir", dir)
491491
}
492+
493+
type Helm mg.Namespace
494+
495+
// UpdateVersion updates a version for Trivy Helm Chart and creates a PR
496+
func (Helm) UpdateVersion() error {
497+
return sh.RunWith(ENV, "go", "run", "-tags=mage_helm", "./magefiles")
498+
}

0 commit comments

Comments
 (0)