Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ jobs:
- name: Golangci lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.7.1
version: v2.15.0
install-mode: goinstall
2 changes: 2 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ linters:
- govet
- ineffassign
- misspell
- modernize
- nakedret
- reassign
- revive
Expand Down Expand Up @@ -111,6 +112,7 @@ linters:
- dupl
- errcheck
- funlen
- goconst
- gocyclo
- gosec
path: _test\.go
Expand Down
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This guide helps agentic coding agents work effectively with the chartify codeba
### Linting and Formatting
- **Format code**: `go fmt ./...`
- **Vet code**: `go vet ./...` (42s, set timeout 120s+)
- **NOTE**: golangci-lint config (.golangci.yaml) has compatibility issues with recent versions. Use `go fmt` and `go vet` for validation.
- **Lint**: `golangci-lint run` (uses .golangci.yaml; CI runs v2.15.0). If local golangci-lint fails with "export data version" errors, reinstall it with the same Go toolchain as go.mod: `GOTOOLCHAIN=go1.27.2 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.15.0`

### Running the CLI
- Basic usage: `./chartify -o OUTPUT_DIR RELEASE_NAME CHART_OR_MANIFEST_PATH`
Expand Down Expand Up @@ -122,11 +122,12 @@ Run these commands to ensure CI passes:
```bash
go fmt ./...
go vet ./...
golangci-lint run
CGO_ENABLED=0 go test ./...
```

### Prerequisites
- Go 1.26.0+
- Go 1.27.2+
- Helm v4.3.1 (helm command)
- Kustomize v5.8.0+ (kustomize command)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ go build -o chartreposerver ./cmd/chartreposerver

### Prerequisites

- Go 1.26.0+
- Go 1.27.2+
- Helm v4.3.1 (helm command)
- Kustomize v5.8.0+ (kustomize command, optional, for kustomize integration)

Expand Down
2 changes: 1 addition & 1 deletion chartify.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ type ChartifyOpts struct {
// TemplateFuncs is the FuncMap used while rendering .gotmpl files in the target directory
TemplateFuncs template.FuncMap
// TemplateData is the data available via {{ . }} within .gotmpl files
TemplateData interface{}
TemplateData any

// TemplateArgs to pass Flags to helm template
TemplateArgs string
Expand Down
2 changes: 1 addition & 1 deletion chartify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func TestDepCommandSelection(t *testing.T) {
ReadDir: os.ReadDir,
Walk: filepath.Walk,
Exists: exists,
Logf: func(string, ...interface{}) {},
Logf: func(string, ...any) {},
MakeTempDir: func(release, chart string, opts *ChartifyOpts) string {
return ""
},
Expand Down
5 changes: 2 additions & 3 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package chartify

import (
"io"
"maps"
"os"
"os/exec"
"strings"
Expand All @@ -18,9 +19,7 @@ func RunCommand(cmd string, args []string, dir string, stdout, stderr io.Writer,

func mergeEnv(orig []string, new map[string]string) []string {
wanted := env2map(orig)
for k, v := range new {
wanted[k] = v
}
maps.Copy(wanted, new)
return map2env(wanted)
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/helmfile/chartify

go 1.26.0
go 1.27.2

require (
github.com/Masterminds/semver/v3 v3.5.0
Expand Down
8 changes: 4 additions & 4 deletions inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type InjectOpts struct {
}

func (r *Runner) Inject(files []string, o InjectOpts) error {
var flagsTemplate string
var flagsTemplate strings.Builder
for _, inj := range o.injectors {
tokens := strings.Split(inj, ",")
injector := tokens[0]
Expand All @@ -20,16 +20,16 @@ func (r *Runner) Inject(files []string, o InjectOpts) error {
flagSplit := strings.Split(flag, "=")
switch len(flagSplit) {
case 1:
flagsTemplate += flagSplit[0]
flagsTemplate.WriteString(flagSplit[0])
case 2:
key, val := flagSplit[0], flagSplit[1]
flagsTemplate += createFlagChain(key, []string{val})
flagsTemplate.WriteString(createFlagChain(key, []string{val}))
default:
return fmt.Errorf("inject-flags must be in the form of key1=value1[,key2=value2,...]: %v", flag)
}
}
for _, file := range files {
flags := strings.Replace(flagsTemplate, "FILE", file, 1)
flags := strings.Replace(flagsTemplate.String(), "FILE", file, 1)
command := fmt.Sprintf("%s %s", injector, flags)
stdout, err := r.runBytes(nil, "", command)
if err != nil {
Expand Down
7 changes: 3 additions & 4 deletions kustomize_extra_args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"io"
"os"
"path/filepath"
"slices"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -47,10 +48,8 @@ func newSpyRunner(t *testing.T, versionOut string) (*Runner, *[]spyCall) {
// buildCall returns the first recorded invocation that runs a kustomize "build".
func buildCall(calls []spyCall) (spyCall, bool) {
for _, c := range calls {
for _, a := range c.args {
if a == "build" {
return c, true
}
if slices.Contains(c.args, "build") {
return c, true
}
}
return spyCall{}, false
Expand Down
26 changes: 13 additions & 13 deletions patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,9 @@ func (r *Runner) resolveTransformerFileRefs(transformerBytes []byte, transformer
// A transformer file can be a single document, a list of documents, or multi-document YAML.
decoder := yaml.NewDecoder(bytes.NewReader(transformerBytes))

var docs []interface{}
var docs []any
for {
var doc interface{}
var doc any
if err := decoder.Decode(&doc); err != nil {
if err == io.EOF {
break
Expand All @@ -532,14 +532,14 @@ func (r *Runner) resolveTransformerFileRefs(transformerBytes []byte, transformer
// Collect all transformer map nodes. This handles both single-document and
// list-of-documents formats. Maps are reference types in Go, so modifying
// them below will be reflected when re-encoding docs.
var allMaps []map[string]interface{}
var allMaps []map[string]any
for _, doc := range docs {
switch v := doc.(type) {
case map[string]interface{}:
case map[string]any:
allMaps = append(allMaps, v)
case []interface{}:
case []any:
for _, item := range v {
if m, ok := item.(map[string]interface{}); ok {
if m, ok := item.(map[string]any); ok {
allMaps = append(allMaps, m)
}
}
Expand Down Expand Up @@ -655,13 +655,13 @@ func (r *Runner) resolveTransformerPath(pathStr string, transformerFileDir strin
// kind: Deployment
//
// See https://github.com/kubernetes-sigs/kustomize/blob/master/examples/inlinePatch.md
func parsePatchDocuments(content []byte) ([]map[string]interface{}, error) {
func parsePatchDocuments(content []byte) ([]map[string]any, error) {
decoder := yaml.NewDecoder(bytes.NewReader(content))

var entries []map[string]interface{}
var entries []map[string]any

for {
var doc interface{}
var doc any
if err := decoder.Decode(&doc); err != nil {
if err == io.EOF {
break
Expand All @@ -670,18 +670,18 @@ func parsePatchDocuments(content []byte) ([]map[string]interface{}, error) {
}

switch v := doc.(type) {
case map[string]interface{}:
case map[string]any:
if v == nil {
// Skip null documents (e.g. from empty "---" separators).
continue
}
entries = append(entries, v)
case []interface{}:
case []any:
if len(v) == 0 {
return nil, fmt.Errorf("patches list is empty")
}
for i, item := range v {
m, ok := item.(map[string]interface{})
m, ok := item.(map[string]any)
if !ok {
return nil, fmt.Errorf("patches list item %d must be a YAML mapping, got %T", i, item)
}
Expand All @@ -705,7 +705,7 @@ func parsePatchDocuments(content []byte) ([]map[string]interface{}, error) {
// marshalPatchEntry encodes a single kustomize patches entry as YAML suitable for
// embedding as a list item under the "patches:" field of kustomization.yaml.
// The returned string has no leading or trailing whitespace lines.
func marshalPatchEntry(entry map[string]interface{}) (string, error) {
func marshalPatchEntry(entry map[string]any) (string, error) {
buf := &bytes.Buffer{}
encoder := yaml.NewEncoder(buf)
encoder.SetIndent(2)
Expand Down
8 changes: 4 additions & 4 deletions patch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ func TestParsePatchDocuments(t *testing.T) {
// TestMarshalPatchEntry verifies YAML encoding of a patch entry.
func TestMarshalPatchEntry(t *testing.T) {
t.Run("preserves inline block scalar patch", func(t *testing.T) {
entry := map[string]interface{}{
entry := map[string]any{
"patch": "apiVersion: v1\nkind: ConfigMap\ndata:\n key: val\n",
"target": map[string]interface{}{
"target": map[string]any{
"kind": "ConfigMap",
},
}
Expand All @@ -347,9 +347,9 @@ func TestMarshalPatchEntry(t *testing.T) {
})

t.Run("preserves path field", func(t *testing.T) {
entry := map[string]interface{}{
entry := map[string]any{
"path": "some-file.yaml",
"target": map[string]interface{}{
"target": map[string]any{
"kind": "Deployment",
},
}
Expand Down
8 changes: 4 additions & 4 deletions replace.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ func (r *Runner) ReplaceWithRendered(name, chartName, chartPath string, o Replac
}
}

lines := strings.Split(stdout, "\n")
for _, line := range lines {
lines := strings.SplitSeq(stdout, "\n")
for line := range lines {
if strings.HasPrefix(line, "wrote ") {
file := strings.Split(line, "wrote ")[1]

Expand Down Expand Up @@ -245,8 +245,8 @@ func (r *Runner) ReplaceWithRendered(name, chartName, chartPath string, o Replac
// should have been downloaded by `helm fetch` that run in an even earlier phase of chartify.
if r.IsHelm3() || r.IsHelm4() {
type ChartMeta struct {
Dependencies []Dependency `yaml:"dependencies,omitempty"`
Data map[string]interface{} `yaml:",inline"`
Dependencies []Dependency `yaml:"dependencies,omitempty"`
Data map[string]any `yaml:",inline"`
}
var chartMeta ChartMeta

Expand Down
6 changes: 3 additions & 3 deletions requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Dependency struct {
Version string `yaml:"version,omitempty"`
// ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
// string or pair of child/parent sublist items.
ImportValues []interface{} `yaml:"import-values,omitempty"`
ImportValues []any `yaml:"import-values,omitempty"`
}

type ChartDependency struct {
Expand Down Expand Up @@ -64,8 +64,8 @@ func (r *Runner) UpdateRequirements(replace bool, chartYamlPath, tempDir string,

if r.IsHelm3() || r.IsHelm4() {
type ChartMeta struct {
Dependencies []Dependency `yaml:"dependencies,omitempty"`
Data map[string]interface{} `yaml:",inline"`
Dependencies []Dependency `yaml:"dependencies,omitempty"`
Data map[string]any `yaml:",inline"`
}
var chartMeta ChartMeta

Expand Down
6 changes: 3 additions & 3 deletions runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type Runner struct {
Exists func(path string) (bool, error)

// Logf is the alternative log function used by chartify
Logf func(string, ...interface{})
Logf func(string, ...any)
}

type Option func(*Runner) error
Expand All @@ -61,7 +61,7 @@ func UseHelm4(u bool) Option {
}
}

func WithLogf(logf func(string, ...interface{})) Option {
func WithLogf(logf func(string, ...any)) Option {
return func(r *Runner) error {
r.Logf = logf
return nil
Expand Down Expand Up @@ -259,6 +259,6 @@ func (r *Runner) captureBytes(binary string, args []string, dir string, envs map
return stdout.Bytes(), stderr.Bytes(), err
}

func printf(format string, vars ...interface{}) {
func printf(format string, vars ...any) {
fmt.Fprintf(os.Stderr, format+"\n", vars...)
}
6 changes: 3 additions & 3 deletions tempdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func makeTempDir(release, chart string, opts *ChartifyOpts) string {
d := filepath.Join(workDir, id)

if os.Getenv(EnvVarDebug) != "" {
bs, _ := json.Marshal(map[string]interface{}{
bs, _ := json.Marshal(map[string]any{
"Release": release,
"Chart": chart,
"Options": opts,
Expand Down Expand Up @@ -74,7 +74,7 @@ func GenerateID(release, chart string, opts *ChartifyOpts) (string, error) {

id = append(id, release)

hash, err := HashObject([]interface{}{release, chart, opts})
hash, err := HashObject([]any{release, chart, opts})
if err != nil {
return "", err
}
Expand All @@ -84,7 +84,7 @@ func GenerateID(release, chart string, opts *ChartifyOpts) (string, error) {
return strings.Join(id, "-"), nil
}

func HashObject(obj interface{}) (string, error) {
func HashObject(obj any) (string, error) {
hash := fnv.New32a()

hash.Reset()
Expand Down
Loading