Skip to content

Commit

Permalink
Add "kcl chart set" wrapper for KCL automation
Browse files Browse the repository at this point in the history
  • Loading branch information
MacroPower committed Jan 4, 2025
1 parent 0aae8d9 commit 3cdc725
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 1 deletion.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ When you want to update a chart, you can edit the `charts.k` file like so:
}
```

Or, alternatively, you can run the following command (wraps KCL automation):

```bash
kcl chart set -c podinfo -O targetRevision=6.7.1
```

Then run re-generate the `charts.podinfo` package to update the schemas:

```bash
Expand Down
49 changes: 48 additions & 1 deletion internal/cli/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ const (
kcl chart add --chart podinfo --repo_url https://stefanprodan.github.io/podinfo --target_revision 6.7.0
# Update chart schemas for the current module
kcl chart update`
kcl chart update
# Set chart configuration attributes
kcl chart set --chart podinfo --overrides "targetRevision=6.7.1"
`
)

var ErrInvalidArgument = errors.New("invalid argument")
Expand All @@ -42,6 +46,7 @@ func NewChartCmd() *cobra.Command {
cmd.AddCommand(NewChartInitCmd())
cmd.AddCommand(NewChartAddCmd())
cmd.AddCommand(NewChartUpdateCmd())
cmd.AddCommand(NewChartSetCmd())

return cmd
}
Expand Down Expand Up @@ -143,3 +148,45 @@ func NewChartUpdateCmd() *cobra.Command {
SilenceUsage: true,
}
}

func NewChartSetCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Short: "Set chart configuration",
RunE: func(cc *cobra.Command, _ []string) error {
var merr error

flags := cc.Flags()
basePath, err := flags.GetString("path")
if err != nil {
merr = multierror.Append(merr, err)
}
chart, err := flags.GetString("chart")
if err != nil {
merr = multierror.Append(merr, err)
}
overrides, err := flags.GetString("overrides")
if err != nil {
merr = multierror.Append(merr, err)
}

if merr != nil {
return fmt.Errorf("%w: %w", ErrInvalidArgument, merr)
}

c := helmutil.NewChartPkg(basePath, helm.DefaultClient)
return c.Set(chart, overrides)
},
SilenceUsage: true,
}
cmd.Flags().StringP("chart", "c", "", "Specify the Helm chart name (required)")
cmd.Flags().StringP("overrides", "O", "", "Specify the configuration override path and value (required)")
if err := cmd.MarkFlagRequired("chart"); err != nil {
panic(err)
}
if err := cmd.MarkFlagRequired("overrides"); err != nil {
panic(err)
}

return cmd
}
49 changes: 49 additions & 0 deletions pkg/helmutil/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package helmutil

import (
"errors"
"fmt"
"reflect"
"strings"

"kcl-lang.io/kcl-go"

"github.com/MacroPower/kclipper/pkg/helmmodels"
)

func (c *ChartPkg) Set(chart string, keyValueOverrides string) error {
if chart == "" {
return errors.New("chart name cannot be empty")
}

hc := helmmodels.Chart{
ChartBase: helmmodels.ChartBase{
Chart: chart,
},
}

key, value, found := strings.Cut(keyValueOverrides, "=")
if !found {
return fmt.Errorf("no key=value pair found in '%s'", keyValueOverrides)
}

configValue := reflect.ValueOf(&helmmodels.ChartConfig{}).Elem().FieldByNameFunc(func(fieldName string) bool {
return strings.EqualFold(fieldName, key)
})

if !configValue.CanSet() {
return fmt.Errorf("key '%s' is not a valid chart configuration attribute", key)
}

chartConfig := map[string]string{key: value}
if err := c.updateChartsFile(c.BasePath, hc.GetSnakeCaseName(), chartConfig); err != nil {
return err
}

_, err := kcl.FormatPath(c.BasePath)
if err != nil {
return fmt.Errorf("failed to format kcl files: %w", err)
}

return nil
}
70 changes: 70 additions & 0 deletions pkg/helmutil/set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package helmutil_test

import (
"errors"
"os"
"path"
"testing"

"github.com/stretchr/testify/require"

"github.com/MacroPower/kclipper/pkg/helmutil"
)

func TestChartPkg_Set(t *testing.T) {
t.Parallel()

// Setup test data
basePath := "testdata/got/set"
chartPath := path.Join(basePath, "charts")
_ = os.RemoveAll(chartPath)
err := os.MkdirAll(chartPath, 0o755)
require.NoError(t, err)

ca := helmutil.NewChartPkg(chartPath, nil)

tests := map[string]struct {
chart string
keyValueOverrides string
expectedError error
}{
"empty chart name": {
chart: "",
keyValueOverrides: "key=value",
expectedError: errors.New("chart name cannot be empty"),
},
"invalid key-value pair": {
chart: "test-chart",
keyValueOverrides: "invalidpair",
expectedError: errors.New("no key=value pair found in 'invalidpair'"),
},
"invalid chart configuration attribute": {
chart: "test-chart",
keyValueOverrides: "InvalidKey=value",
expectedError: errors.New("key 'InvalidKey' is not a valid chart configuration attribute"),
},
"successful set": {
chart: "test-chart",
keyValueOverrides: "schemaPath=https://example.com",
expectedError: nil,
},
"successful base set": {
chart: "test-chart",
keyValueOverrides: "repoURL=https://example.com",
expectedError: nil,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
t.Parallel()

err := ca.Set(tc.chart, tc.keyValueOverrides)
if tc.expectedError != nil {
require.EqualError(t, err, tc.expectedError.Error())
} else {
require.NoError(t, err)
}
})
}
}

0 comments on commit 3cdc725

Please sign in to comment.