Compare commits
10 commits
928435dcd3
...
100cac887f
| Author | SHA1 | Date | |
|---|---|---|---|
| 100cac887f | |||
| 862470812d | |||
| 3cd043b2b1 | |||
| 23f83da3d5 | |||
| 7c9d946b62 | |||
| 8f6900305b | |||
| 42fe353444 | |||
| 80d7bccbdd | |||
| e53c091e3f | |||
| 8d8f3900d0 |
9 changed files with 407 additions and 19 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
helmfile2argo
|
||||
1
LICENSE
1
LICENSE
|
|
@ -0,0 +1 @@
|
|||
GPLv3
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
| :exclamation: | This is an extremely naiive implementation and might be not what you really want, but it's better than nothing. |
|
||||
|----------------|:------------------------|
|
||||
|
||||
The actual intent of this is to create a basic structure for you to refine, when you currently have helmfile and want to move to argoCD.
|
||||
|
||||
## How it works
|
||||
|
||||
- It strips **ALL** templating from the yaml file. Naiively, with a regex.
|
||||
|
|
@ -15,3 +17,8 @@
|
|||
|
||||
- "Magic". For example, it won't replace hardcoded https://path.to/some/tarball-helm-chart.tgz with something that is argo-compatible. Point to a real helm repo, an oci repo or a git repo, argo can deal with those.
|
||||
- Multiple environments. There's not an opinionated "this is how you do it in argo" for that, so you need to work out what to do there. You can pass the environment you want to use in, and if you're using "environment" values, they'll be included in the application object for you.
|
||||
- The same as helmfile, sometimes. For example, it will only descend one level deep of helmfile references and values in the sub helmfiles might leak upwards.
|
||||
|
||||
## Context
|
||||
|
||||
This was written on trains and in cafes in my personal time, don't expect too much from it, use it if it's useful to you.
|
||||
347
cmd/convert.go
347
cmd/convert.go
|
|
@ -1,15 +1,127 @@
|
|||
/*
|
||||
Copyright © 2026 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/yookoala/realpath"
|
||||
"gopkg.in/yaml.v3"
|
||||
"internal/fileflag"
|
||||
)
|
||||
|
||||
type helmfileStructure struct {
|
||||
Repositories []helmfileRepository `json:"repositories"`
|
||||
Releases []helmfileHelmRelease `json:"releases"`
|
||||
HelmFiles []helmfileHemfileRef `json:"helmfiles"`
|
||||
Environments map[string]interface{} `json:"environments"`
|
||||
}
|
||||
|
||||
type helmfileRepository struct {
|
||||
Name string `json:"name"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type helmfileHelmRelease struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Installed bool `json:"installed"`
|
||||
Labels string `json:"labels"`
|
||||
Chart string `json:"chart"`
|
||||
Version string `json:"version"`
|
||||
Values []map[string]interface{} `json:"values"`
|
||||
}
|
||||
|
||||
type helmfileHemfileRef struct {
|
||||
Path string `json:"path"`
|
||||
Values []map[string]interface{} `json:"values"`
|
||||
}
|
||||
|
||||
type argoProjectMeta struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type argoProjectDestination struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Server string `json:"server"`
|
||||
}
|
||||
|
||||
type argoResourceWhitelistItem struct {
|
||||
Group string `json:"group"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
|
||||
type argoProjectSpec struct {
|
||||
SourceRepos []string `json:"sourceRepos"`
|
||||
Destinations []argoProjectDestination `json:"Destinations"`
|
||||
ClusterResourceWhitelist []argoResourceWhitelistItem `json:"clusterResourceWhitelist"`
|
||||
}
|
||||
|
||||
type argoProject struct {
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
Kind string `json:"kind"`
|
||||
Metadata argoProjectMeta `json:"metadata"`
|
||||
Spec argoProjectSpec `json:"spec"`
|
||||
}
|
||||
|
||||
type argoAppMeta struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
type argoAppSpecSourceHelm struct {
|
||||
ReleaseName string `releaseName`
|
||||
ValuesObject map[string]interface{} `valuesObject`
|
||||
}
|
||||
|
||||
type argoAppSpecSource struct {
|
||||
Chart string `json:"chart"`
|
||||
RepoURL string `json:"repoURL"`
|
||||
targetRevision string `json:"targetRevision"`
|
||||
Helm argoAppSpecSourceHelm `json:"helm"`
|
||||
}
|
||||
|
||||
type argoAppSpecDestination struct {
|
||||
Server string `json:"server"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
type argoAppSpec struct {
|
||||
Project string `json:"project"`
|
||||
Source argoAppSpecSource `json:"source"`
|
||||
Destination argoAppSpecDestination `json: "destination"`
|
||||
}
|
||||
|
||||
type argoApp struct {
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
Kind string `json:"kind"`
|
||||
Metadata argoAppMeta `json:"metadata"`
|
||||
Spec argoAppSpec `json:"spec"`
|
||||
}
|
||||
|
||||
var flagInputYaml fileflag.InputFileFlag = "helmfile.yaml"
|
||||
var singleFile bool = false
|
||||
var outputDir string = "-" //TODO: actually handle files
|
||||
var appNamespace string = "argocd"
|
||||
var projectName string = "helmfile-imported"
|
||||
var createProject bool = true
|
||||
var serverURL string = "https://kubernetes.default.svc"
|
||||
var recursiveConvert bool = false
|
||||
var loadEnvironmentValues string = ""
|
||||
|
||||
var reposFromHelmChart []helmfileRepository
|
||||
var environmentValues map[string]interface{}
|
||||
var filesWrittenTo []string
|
||||
|
||||
// convertCmd represents the convert command
|
||||
var convertCmd = &cobra.Command{
|
||||
Use: "convert",
|
||||
|
|
@ -18,10 +130,231 @@ var convertCmd = &cobra.Command{
|
|||
a set of .yaml files describing argocd Applications that are built from the
|
||||
releases section.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("convert called")
|
||||
helmfileContents := parseHelmfile(string(flagInputYaml), nil)
|
||||
if recursiveConvert && len(helmfileContents.HelmFiles) > 0 {
|
||||
for i := 0; i <= len(helmfileContents.HelmFiles)-1; i++ {
|
||||
fmt.Print("Merging in ")
|
||||
fmt.Println(helmfileContents.HelmFiles[i].Path)
|
||||
mergeIn := parseHelmfile(string(helmfileContents.HelmFiles[i].Path), helmfileContents.HelmFiles[i].Values)
|
||||
helmfileContents.Repositories = append(helmfileContents.Repositories, mergeIn.Repositories[:]...)
|
||||
helmfileContents.Releases = append(helmfileContents.Releases, mergeIn.Releases[:]...)
|
||||
maps.Copy(helmfileContents.Environments,mergeIn.Environments)
|
||||
}
|
||||
}
|
||||
fmt.Println("converting file:", flagInputYaml)
|
||||
|
||||
if (loadEnvironmentValues != "") {
|
||||
environmentMap, ok := helmfileContents.Environments[loadEnvironmentValues].(map[string]interface{})
|
||||
if !ok {
|
||||
fmt.Println("Error, no enviroments defined in helmfile, but environment passed in command.")
|
||||
os.Exit(1)
|
||||
}
|
||||
var valueFilesMap = environmentMap["values"].([]interface{})
|
||||
var valueFiles []string
|
||||
for i := range valueFilesMap {
|
||||
valueFiles = append(valueFiles, valueFilesMap[i].(string))
|
||||
}
|
||||
environmentValues = fetchEnvironmentValues(valueFiles)
|
||||
}
|
||||
if createProject && (len(helmfileContents.Repositories) > 0) {
|
||||
outputProject := baseProject(projectName)
|
||||
for i := 0; i <= len(helmfileContents.Repositories)-1; i++ {
|
||||
outputProject.Spec.SourceRepos = append(outputProject.Spec.SourceRepos, helmfileContents.Repositories[i].Url)
|
||||
}
|
||||
outputProjectYaml, _ := yaml.Marshal(outputProject)
|
||||
var outputFilename = "project-"+projectName+".yaml"
|
||||
if singleFile {
|
||||
outputFilename = "helmfile2argo.yaml"
|
||||
}
|
||||
outputYamlFile(outputProjectYaml, outputFilename)
|
||||
}
|
||||
reposFromHelmChart = helmfileContents.Repositories
|
||||
if len(helmfileContents.Releases) > 0 {
|
||||
for i := 0; i <= len(helmfileContents.Releases)-1; i++ {
|
||||
thisRelease := helmfileContents.Releases[i]
|
||||
outputApp := baseArgoApp(thisRelease.Name)
|
||||
outputApp.Spec.Project = projectName
|
||||
if thisRelease.Chart[0:4] == "http" {
|
||||
outputApp.Spec.Source.Chart = "UNSUPPORTED_BY_ARGO"
|
||||
outputApp.Spec.Source.RepoURL = thisRelease.Chart
|
||||
} else {
|
||||
var chartmatcher = regexp.MustCompile(`(^[^/]*)/(.*)`)
|
||||
chart := chartmatcher.ReplaceAllString(thisRelease.Chart, `$2`)
|
||||
repo := chartmatcher.ReplaceAllString(thisRelease.Chart, `$1`)
|
||||
outputApp.Spec.Source.Chart = chart
|
||||
var err error
|
||||
err, outputApp.Spec.Source.RepoURL = repoURLbyName(repo)
|
||||
if err != nil {
|
||||
outputApp.Spec.Source.RepoURL = "UNDEFINED"
|
||||
}
|
||||
}
|
||||
outputApp.Spec.Source.Helm.ReleaseName = thisRelease.Name
|
||||
if (loadEnvironmentValues != "") {
|
||||
//flattened := flattenHelmfileWeirdValues(thisRelease.Values)
|
||||
if (environmentValues == nil) {
|
||||
outputApp.Spec.Source.Helm.ValuesObject = flattenHelmfileWeirdValues(thisRelease.Values)
|
||||
} else if (thisRelease.Values == nil) {
|
||||
outputApp.Spec.Source.Helm.ValuesObject = environmentValues
|
||||
} else {
|
||||
merged := environmentValues
|
||||
maps.Copy(merged, flattenHelmfileWeirdValues(thisRelease.Values))
|
||||
outputApp.Spec.Source.Helm.ValuesObject = merged
|
||||
}
|
||||
} else {
|
||||
outputApp.Spec.Source.Helm.ValuesObject = flattenHelmfileWeirdValues(thisRelease.Values)
|
||||
}
|
||||
|
||||
outputApp.Spec.Destination.Server = serverURL
|
||||
outputApp.Spec.Destination.Namespace = thisRelease.Namespace
|
||||
|
||||
outputAppYaml, _ := yaml.Marshal(outputApp)
|
||||
var outputFilename = "app-"+thisRelease.Name+".yaml"
|
||||
if singleFile {
|
||||
outputFilename = "helmfile2argo.yaml"
|
||||
}
|
||||
outputYamlFile(outputAppYaml,outputFilename)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func flattenHelmfileWeirdValues(hfv []map[string]interface{}) map[string]interface{} {
|
||||
var nv map[string]interface{}
|
||||
for i := range hfv {
|
||||
if i == 0 {
|
||||
nv = hfv[i]
|
||||
} else {
|
||||
maps.Copy(nv,hfv[i])
|
||||
}
|
||||
}
|
||||
return nv
|
||||
}
|
||||
|
||||
func parseHelmfile(helmfileFilename string, passedValues []map[string]interface{}) helmfileStructure {
|
||||
var finalPath = helmfileFilename
|
||||
if helmfileFilename != string(flagInputYaml) {
|
||||
absolutePath, err := realpath.Realpath(string(flagInputYaml))
|
||||
basePath := filepath.Dir(absolutePath)
|
||||
finalPath, err = realpath.Realpath(basePath + string(os.PathSeparator) + helmfileFilename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
fmt.Println("parsing file:", finalPath)
|
||||
yamlFile, err := os.ReadFile(finalPath)
|
||||
if err != nil {
|
||||
fmt.Printf("yamlFile.Get err #%v ", err)
|
||||
}
|
||||
templatingMatch := regexp.MustCompile(`{{[^{}]*}}`)
|
||||
passOneRemoveTemplating := templatingMatch.ReplaceAllString(string(yamlFile), `UNDEFINED`)
|
||||
passTwoRemoveTemplating := templatingMatch.ReplaceAllString(passOneRemoveTemplating, `UNDEFINED`)
|
||||
multidocMatch := regexp.MustCompile(`\n---\n`)
|
||||
passThreeRemoveMultiDoc := multidocMatch.ReplaceAllString(passTwoRemoveTemplating, "\n")
|
||||
helmfileContents := &helmfileStructure{}
|
||||
|
||||
err = yaml.Unmarshal([]byte(passThreeRemoveMultiDoc), helmfileContents)
|
||||
if err != nil {
|
||||
fmt.Printf("Unmarshal: %v", err)
|
||||
}
|
||||
if passedValues != nil {
|
||||
for i := 0; i <= len(helmfileContents.Releases)-1; i++ {
|
||||
helmfileContents.Releases[i].Values = append(helmfileContents.Releases[i].Values, passedValues...)
|
||||
}
|
||||
}
|
||||
return *helmfileContents
|
||||
}
|
||||
|
||||
func fetchEnvironmentValues(files []string) map[string]interface{} {
|
||||
var allValues map[string]interface{}
|
||||
for i := 0; i <= len(files)-1; i++ {
|
||||
absolutePath, err := realpath.Realpath(string(flagInputYaml))
|
||||
basePath := filepath.Dir(absolutePath)
|
||||
finalPath, err := realpath.Realpath(basePath + string(os.PathSeparator) + files[i])
|
||||
fmt.Print("Loading values from ")
|
||||
fmt.Println(finalPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
yamlFile, err := os.ReadFile(finalPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var thisFilesValues map[string]interface{}
|
||||
if err := yaml.Unmarshal(yamlFile, &thisFilesValues); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(thisFilesValues)
|
||||
if i == 0 {
|
||||
allValues = thisFilesValues
|
||||
} else {
|
||||
maps.Copy(allValues, thisFilesValues)
|
||||
}
|
||||
}
|
||||
fmt.Println(allValues)
|
||||
return allValues
|
||||
}
|
||||
|
||||
func fetchRepos(helmfileFilename string) []helmfileRepository {
|
||||
return nil
|
||||
}
|
||||
|
||||
func repoURLbyName(repoName string) (error, string) {
|
||||
for i := 0; i <= len(reposFromHelmChart)-1; i++ {
|
||||
if reposFromHelmChart[i].Name == repoName {
|
||||
return nil, reposFromHelmChart[i].Url
|
||||
}
|
||||
}
|
||||
return errors.New("No repo by that name found!"), ""
|
||||
}
|
||||
|
||||
func outputString(data string, filename string) {
|
||||
if string(outputDir) == "-" {
|
||||
fmt.Println(data)
|
||||
} else {
|
||||
var mode int
|
||||
if slices.Contains(filesWrittenTo,filename) {
|
||||
mode = os.O_APPEND|os.O_CREATE|os.O_WRONLY
|
||||
} else {
|
||||
filesWrittenTo = append(filesWrittenTo, filename)
|
||||
mode = os.O_TRUNC|os.O_CREATE|os.O_WRONLY
|
||||
}
|
||||
f, err := os.OpenFile(outputDir+string(os.PathSeparator)+filename, mode, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.WriteString(data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func outputYamlFile(bytes []byte, filename string) {
|
||||
if singleFile || (string(outputDir) == "-") {
|
||||
outputString("---\n", filename)
|
||||
}
|
||||
outputString(string(bytes)+"\n", filename)
|
||||
}
|
||||
|
||||
func baseProject(name string) argoProject {
|
||||
outputProject := argoProject{}
|
||||
outputProject.ApiVersion = "argoproj.io/v1alpha1"
|
||||
outputProject.Kind = "AppProject"
|
||||
outputProject.Spec.Destinations = append(outputProject.Spec.Destinations, argoProjectDestination{Namespace: "*", Server: "*"})
|
||||
outputProject.Spec.ClusterResourceWhitelist = append(outputProject.Spec.ClusterResourceWhitelist, argoResourceWhitelistItem{Group: "*", Kind: "*"})
|
||||
outputProject.Metadata.Name = name
|
||||
return outputProject
|
||||
}
|
||||
|
||||
func baseArgoApp(name string) argoApp {
|
||||
outputApp := argoApp{}
|
||||
outputApp.ApiVersion = "argoproj.io/v1alpha1"
|
||||
outputApp.Kind = "Application"
|
||||
outputApp.Metadata.Namespace = appNamespace
|
||||
outputApp.Metadata.Name = name
|
||||
return outputApp
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(convertCmd)
|
||||
|
||||
|
|
@ -34,4 +367,14 @@ func init() {
|
|||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// convertCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
convertCmd.Flags().VarP(&flagInputYaml, "input", "i", `helmfile to convert`)
|
||||
convertCmd.Flags().BoolVarP(&singleFile, "single-file", "1", false, `single output file (always true if output is "-")`)
|
||||
convertCmd.Flags().StringVarP(&outputDir, "output", "o", "-", `output folder or "-" for stdout`)
|
||||
convertCmd.Flags().StringVarP(&appNamespace, "appnamespace", "a", "argocd", `namespace for application objects`)
|
||||
convertCmd.Flags().StringVarP(&projectName, "projectname", "p", "helmfile-imported", `project name for all apps`)
|
||||
convertCmd.Flags().BoolVarP(&createProject, "create-project", "c", true, `create project with above projectname and all repositories from helmfile`)
|
||||
convertCmd.Flags().StringVarP(&serverURL, "server-name", "n", "https://kubernetes.default.svc", `spec.destination.server value in the application objects`)
|
||||
convertCmd.Flags().BoolVarP(&recursiveConvert, "recursive", "r", false, `recurse into sub helmfiles`)
|
||||
convertCmd.Flags().StringVarP(&loadEnvironmentValues, "load-environment-values", "e", "", `set to an environment name to load environment-based values in the top-level helmfile`)
|
||||
|
||||
}
|
||||
|
|
|
|||
12
cmd/root.go
12
cmd/root.go
|
|
@ -1,13 +1,13 @@
|
|||
/*
|
||||
Copyright © 2026 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
Copyright © 2026 Martyn Ranyard <m@rtyn.berlin>
|
||||
GPLv3 licensed
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
|
@ -16,7 +16,7 @@ import (
|
|||
var (
|
||||
cfgFile string
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "helmfile2argo",
|
||||
Short: "Convert a helmfile to a set of argocd applications",
|
||||
|
|
@ -68,5 +68,3 @@ func init() {
|
|||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.helmfile2argo/config)")
|
||||
initializeConfig(rootCmd)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
21
go.mod
21
go.mod
|
|
@ -3,19 +3,32 @@ module git.martyn.berlin/martyn/helmfile2argo
|
|||
go 1.26.2
|
||||
|
||||
require (
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/viper v1.21.0
|
||||
github.com/yookoala/realpath v1.0.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
internal/fileflag v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spf13/cobra v1.10.2 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/spf13/viper v1.21.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
)
|
||||
|
||||
replace internal/fileflag => ./internal/fileflag
|
||||
|
|
|
|||
33
go.sum
33
go.sum
|
|
@ -1,12 +1,29 @@
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
|
|
@ -23,12 +40,20 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
|||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/yookoala/realpath v1.0.0 h1:7OA9pj4FZd+oZDsyvXWQvjn5oBdcHRTV44PpdMSuImQ=
|
||||
github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
BIN
helmfile2argo
BIN
helmfile2argo
Binary file not shown.
4
main.go
4
main.go
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright © 2026 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
Copyright © 2026 Martyn Ranyard <m@rtyn.berlin>
|
||||
GPLv3 licensed
|
||||
*/
|
||||
package main
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue