Skip to content
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
101 changes: 84 additions & 17 deletions helm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ type PushOpts struct {
Oci bool `yaml:"oci"`
Username string `yaml:"username"`
Password *dagger.Secret
Version string `yaml:"version"`
AppVersion string `yaml:"appVersion"`
}

func (p PushOpts) getProtocol() string {
Expand All @@ -42,6 +44,29 @@ func (p PushOpts) getChartFqdn(name string) string {
return fmt.Sprintf("%s/%s", p.getRepoFqdn(), name)
}

func (p PushOpts) getHelmPkgCmd() []string {
helmPkgCmd := []string{"helm", "package", "."}
if p.Version != "" {
helmPkgCmd = append(helmPkgCmd, "--version", p.Version)
}
if p.AppVersion != "" {
helmPkgCmd = append(helmPkgCmd, "--app-version", p.AppVersion)
}
return helmPkgCmd
}

// Get and display the name of the Helm Chart located inside the given directory.
//
// Example usage: dagger call name --directory ./helm/examples/testdata/mychart/
func (h *Helm) Name(
// method call context
ctx context.Context,
// directory that contains the Helm Chart
directory *dagger.Directory,
) (string, error) {
return h.queryChartWithYq(ctx, directory, ".name")
}

// Get and display the version of the Helm Chart located inside the given directory.
//
// Example usage: dagger call version --directory ./helm/examples/testdata/mychart/
Expand All @@ -51,13 +76,19 @@ func (h *Helm) Version(
// directory that contains the Helm Chart
directory *dagger.Directory,
) (string, error) {
c := h.createContainer(directory)
version, err := c.WithExec([]string{"sh", "-c", "helm show chart . | yq eval '.version' -"}).Stdout(ctx)
if err != nil {
return "", err
}
return h.queryChartWithYq(ctx, directory, ".version")
}

return strings.TrimSpace(version), nil
// Get and display the appVersion of the Helm Chart located inside the given directory.
//
// Example usage: dagger call app-version --directory ./helm/examples/testdata/mychart/
func (h *Helm) AppVersion(
// method call context
ctx context.Context,
// directory that contains the Helm Chart
directory *dagger.Directory,
) (string, error) {
return h.queryChartWithYq(ctx, directory, ".appVersion")
}

// Packages and pushes a Helm chart to a specified OCI-compatible (by default) registry with authentication.
Expand Down Expand Up @@ -102,33 +133,40 @@ func (h *Helm) PackagePush(
// +optional
// +default=false
useNonOciHelmRepo bool, // Dev note: We are forced to use default=false due to https://github.com/dagger/dagger/issues/8810
// set chart version when packaging
// +optional
// default=""
setVersionTo string,
// set chart appVersion when packaging
// +optional
// default=""
setAppVersionTo string,
) (bool, error) {
version, err := h.valueOrQueryChart(setVersionTo, ctx, directory, ".version")
if err != nil {
return false, err
}
opts := PushOpts{
Registry: registry,
Repository: repository,
Oci: !useNonOciHelmRepo,
Username: username,
Password: password,
Version: version,
AppVersion: setAppVersionTo,
}

fmt.Fprintf(os.Stdout, "☸️ Helm package and Push")
c := dag.Container().
From("registry.puzzle.ch/cicd/alpine-base:latest").
WithDirectory("/helm", directory).
WithWorkdir("/helm")
version, err := c.WithExec([]string{"sh", "-c", "helm show chart . | yq eval '.version' -"}).Stdout(ctx)
if err != nil {
return false, err
}

version = strings.TrimSpace(version)

name, err := c.WithExec([]string{"sh", "-c", "helm show chart . | yq eval '.name' -"}).Stdout(ctx)
name, err := h.queryChartWithYq(ctx, directory, ".name")
if err != nil {
return false, err
}

name = strings.TrimSpace(name)
pkgFile := fmt.Sprintf("%s-%s.tgz", name, version)

chartExists, err := h.doesChartExistOnRepo(ctx, c, &opts, name, version)
Expand All @@ -141,7 +179,7 @@ func (h *Helm) PackagePush(
}

c, err = c.WithExec([]string{"helm", "dependency", "update", "."}).
WithExec([]string{"helm", "package", "."}).
WithExec(opts.getHelmPkgCmd()).
WithExec([]string{"sh", "-c", "ls"}).
Sync(ctx)

Expand Down Expand Up @@ -310,13 +348,29 @@ func (h *Helm) doesChartExistOnRepo(
return false, fmt.Errorf("Server returned error code %s checking for chart existence on server.", httpCode)
}

func (h *Helm) queryChartWithYq(
// method call context
ctx context.Context,
// directory that contains the Helm Chart
directory *dagger.Directory,
yqQuery string,
) (string, error) {
c := h.createContainer(directory)
version, err := c.WithExec([]string{"sh", "-c", fmt.Sprintf(`helm show chart . | yq eval '%s' -`, yqQuery)}).Stdout(ctx)
if err != nil {
return "", err
}

return strings.TrimSpace(version), nil
}

func (h *Helm) hasMissingDependencies(
// method call context
ctx context.Context,
// directory that contains the Helm Chart
directory *dagger.Directory,
) bool {
_, err := h.createContainer(directory).WithExec([]string{"sh", "-c", "helm dep list | grep missing"}).Stdout(ctx)
_, err := h.createContainer(directory).WithExec([]string{"sh", "-c", "helm dependency list | grep missing"}).Stdout(ctx)
return err == nil
}

Expand All @@ -325,7 +379,7 @@ func (h *Helm) dependencyUpdate(
directory *dagger.Directory,
) *dagger.Directory {
c := h.createContainer(directory)
return c.WithExec([]string{"sh", "-c", "helm dep update"}).Directory("charts")
return c.WithExec([]string{"sh", "-c", "helm dependency update"}).Directory("charts")
}

func (h *Helm) createContainer(
Expand All @@ -338,3 +392,16 @@ func (h *Helm) createContainer(
WithWorkdir("/helm").
WithoutEntrypoint()
}

// coalesce returns the first non-empty string from the provided arguments.
func (h *Helm) valueOrQueryChart(
theValue string,
ctx context.Context,
directory *dagger.Directory,
yqQuery string,
) (string, error) {
if theValue != "" {
return strings.TrimSpace(theValue), nil
}
return h.queryChartWithYq(ctx, directory, yqQuery)
}
109 changes: 109 additions & 0 deletions tests/charts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"dagger/go/internal/dagger"
"fmt"
)

const originalVersion = "0.1.1"
const originalAppVersion = "1.16.0"

const mychartName = "dagger-module-helm-test"
const mychartDir = "./testdata/mychart/"
const mychartTemplate = `
apiVersion: v2
name: %s
description: A Helm chart
type: application
version: %s
appVersion: "%s"
`
const mydependentchartName = "dagger-module-helm-test-with-dependency"
const mydependentchartDir = "./testdata/mydependentchart/"
const mydependentchartTemplate = `
apiVersion: v2
name: %s
description: A Helm chart
type: application
version: %s
appVersion: "%s"
dependencies:
- name: dependency-track
version: 1.8.1
repository: https://puzzle.github.io/dependencytrack-helm/
`

// Chart represents one of our test Helm charts
type Chart struct{
Name string
Directory string
ContentTemplate string
OriginalContent string
}

// Use the dagger module to get the dagger directory of the chart
func (c *Chart) DaggerDirectory(
) *dagger.Directory {
return dag.CurrentModule().Source().Directory(c.Directory)
}

// Modify the chart by changing both version and appVersion
func (c *Chart) WithVersionAndAppVersion(
version string,
appVersion string,
) *Chart {
if version == "" {
version = originalVersion
}
if appVersion == "" {
appVersion = originalAppVersion
}
c.DaggerDirectory().
WithoutFile("Chart.yaml").
WithNewFile("Chart.yaml",
fmt.Sprintf(c.ContentTemplate, c.Name, version, appVersion))
return c
}

// Modify the chart by appending a suffix to the original version
func (c *Chart) WithOriginalVersionSuffix(
suffix string,
) *Chart {
versionWithSuffix := fmt.Sprintf("%s-%s", originalVersion, suffix)
return c.WithVersion(versionWithSuffix)
}

// Modify the chart by changing only the version
func (c *Chart) WithVersion(
version string,
) *Chart {
return c.WithVersionAndAppVersion(version, "")
}

// Modify the chart by changing only the appVersion
func (c *Chart) WithAppVersion(
appVersion string,
) *Chart {
return c.WithVersionAndAppVersion("", appVersion)
}

// Reset the chart to its original content
func (c *Chart) Reset(
) *Chart {
return c.WithVersionAndAppVersion("", "")
}

var (
Mychart = Chart{
Name: mychartName,
Directory: mychartDir,
ContentTemplate: mychartTemplate,
OriginalContent: fmt.Sprintf(mychartTemplate, mychartName, originalVersion, originalAppVersion),
}
Mydependentchart = Chart{
Name: mydependentchartName,
Directory: mydependentchartDir,
ContentTemplate: mydependentchartTemplate,
OriginalContent: fmt.Sprintf(mydependentchartTemplate, mydependentchartName, originalVersion, originalAppVersion),
}
)
Loading