Compare commits
39 Commits
v3.0.0-rc1
...
feat-compo
Author | SHA1 | Date | |
---|---|---|---|
1fa07c29e5 | |||
41a4292939 | |||
131ea5d569 | |||
e36bbf41f4 | |||
d27ed76cf4 | |||
17b6ea51af | |||
dcd282779f | |||
b93a3df98c | |||
4768330c1a | |||
23d0afd85f | |||
5c939383be | |||
4d0e5b2e6a | |||
58d1e8e450 | |||
d0790f37a8 | |||
62b0576c2d | |||
e574a2e2a8 | |||
eb760d4299 | |||
3833037862 | |||
6dc92df4b5 | |||
d458cdbd73 | |||
628b35d471 | |||
84363be0e8 | |||
5284cdf5cc | |||
632ffc2b66 | |||
2ff705164e | |||
73ab867509 | |||
45e44dee14 | |||
689c2a4803 | |||
e023544c8a | |||
957cc4bcf6 | |||
6b301f3171 | |||
5f20585fb2 | |||
456e7f41f2 | |||
49045a2ccd | |||
315f5da970 | |||
427f2909d5 | |||
6023ca4508 | |||
e0c829c2ce | |||
10b9342607 |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@@ -9,3 +9,4 @@ updates:
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
target-branch: develop
|
||||
|
17
.github/workflows/go-test.yaml
vendored
17
.github/workflows/go-test.yaml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
- master
|
||||
- develop
|
||||
jobs:
|
||||
test:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -24,7 +24,22 @@ jobs:
|
||||
./get_helm.sh
|
||||
- name: Launch Test
|
||||
run: |
|
||||
go mod tidy
|
||||
go vet ./... && go test -coverprofile=coverprofile.out -json -v ./... > gotest.json
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tests-results
|
||||
path: |
|
||||
coverprofile.out
|
||||
gotest.json
|
||||
sonar:
|
||||
runs-on: ubuntu-latest
|
||||
needs: tests
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: tests-results
|
||||
- name: SonarCloud Scan
|
||||
uses: SonarSource/sonarcloud-github-action@master
|
||||
env:
|
||||
|
26
README.md
26
README.md
@@ -2,11 +2,22 @@
|
||||
<img src="./doc/docs/statics/logo-vertical.svg" alt="Katenary Logo" style="max-width: 90%" align="center"/>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center; margin: auto 0 4em 0" align="center">
|
||||
|
||||
[](https://katenary.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://goreportcard.com/report/github.com/metal3d/katenary)
|
||||
[](https://github.com/metal3d/katenary/releases)
|
||||
[](https://sonarcloud.io/summary/new_code?id=metal3d_katenary)
|
||||
[](https://sonarcloud.io/summary/new_code?id=metal3d_katenary)
|
||||
[](https://sonarcloud.io/summary/new_code?id=metal3d_katenary)
|
||||
|
||||
🚀 Unleash Productivity with Katenary! 🚀
|
||||
[](https://sonarcloud.io/summary/new_code?id=metal3d_katenary)
|
||||
|
||||
</div>
|
||||
|
||||
<div style="text-align:center; margin: auto 0 4em 0" align="center">
|
||||
<h3>🚀 Unleash Productivity with Katenary! 🚀</h3>
|
||||
</div>
|
||||
|
||||
Tired of manual conversions? Katenary harnesses the labels from your "`compose`" file to craft complete Helm Charts
|
||||
effortlessly, saving you time and energy.
|
||||
@@ -161,12 +172,13 @@ services:
|
||||
katenary.v3/ingress: |-
|
||||
hostname: myapp.example.com
|
||||
port: 80
|
||||
# make adaptations, DB_HOST environment is actually the service name
|
||||
katenary.v3/map-env: |-
|
||||
# make adaptations, DB_HOST environment is actually the service name
|
||||
DB_HOST: '{{ .Release.Name }}-database'
|
||||
# get the values from the "database" service
|
||||
# this will use the database secrets and environment,
|
||||
# see the "database" service to see the values
|
||||
katenary.v3/values-from: |-
|
||||
# get the values from the "database" service
|
||||
# this will use the databas secret, see below
|
||||
DB_USER: databse.MARIADB_USER
|
||||
DB_PASSWORD: database.MARIADB_PASSWORD
|
||||
|
||||
@@ -260,7 +272,7 @@ return {
|
||||
settings = {
|
||||
yaml = {
|
||||
schemas = {
|
||||
["https://raw.githubusercontent.com/metal3d/katenary/refs/heads/master/katenary.json"] = "katenary.yaml",
|
||||
["https://raw.githubusercontent.com/metal3d/katenary/master/katenary.json"] = "katenary.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -276,12 +288,12 @@ Use this address to validate the `katenary.yaml` file in VSCode:
|
||||
```json
|
||||
{
|
||||
"yaml.schemas": {
|
||||
"https://raw.githubusercontent.com/metal3d/katenary/refs/heads/master/katenary.json": "katenary.yaml"
|
||||
"https://raw.githubusercontent.com/metal3d/katenary/master/katenary.json": "katenary.yaml"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> You can, of course, replace the `refs/heads/master` with a specific tag or branch.
|
||||
> You can, of course, replace the `master` with a specific tag or branch.
|
||||
|
||||
## What a name…
|
||||
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/v2/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -141,11 +141,11 @@ func generateConvertCommand() *cobra.Command {
|
||||
convertCmd := &cobra.Command{
|
||||
Use: "convert",
|
||||
Short: "Converts a docker-compose file to a Helm Chart",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if givenAppVersion != "" {
|
||||
appVersion = &givenAppVersion
|
||||
}
|
||||
generator.Convert(generator.ConvertOptions{
|
||||
return generator.Convert(generator.ConvertOptions{
|
||||
Force: force,
|
||||
OutputDir: outputDir,
|
||||
Profiles: profiles,
|
||||
|
@@ -38,7 +38,7 @@ var Version = "master" // changed at compile time
|
||||
## func [Convert](<https://github.com/metal3d/katenary/blob/develop/generator/converter.go#L93>)
|
||||
|
||||
```go
|
||||
func Convert(config ConvertOptions, dockerComposeFile ...string)
|
||||
func Convert(config ConvertOptions, dockerComposeFile ...string) error
|
||||
```
|
||||
|
||||
Convert a compose \(docker, podman...\) project to a helm chart. It calls Generate\(\) to generate the chart and then write it to the disk.
|
||||
@@ -119,7 +119,7 @@ type ChartTemplate struct {
|
||||
```
|
||||
|
||||
<a name="ConfigMap"></a>
|
||||
## type [ConfigMap](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L35-L40>)
|
||||
## type [ConfigMap](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L37-L42>)
|
||||
|
||||
ConfigMap is a kubernetes ConfigMap. Implements the DataMap interface.
|
||||
|
||||
@@ -131,7 +131,7 @@ type ConfigMap struct {
|
||||
```
|
||||
|
||||
<a name="NewConfigMap"></a>
|
||||
### func [NewConfigMap](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L44>)
|
||||
### func [NewConfigMap](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L46>)
|
||||
|
||||
```go
|
||||
func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *ConfigMap
|
||||
@@ -140,7 +140,7 @@ func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *Co
|
||||
NewConfigMap creates a new ConfigMap from a compose service. The appName is the name of the application taken from the project name. The ConfigMap is filled by environment variables and labels "map\-env".
|
||||
|
||||
<a name="NewConfigMapFromDirectory"></a>
|
||||
### func [NewConfigMapFromDirectory](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L117>)
|
||||
### func [NewConfigMapFromDirectory](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L119>)
|
||||
|
||||
```go
|
||||
func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string) *ConfigMap
|
||||
@@ -148,8 +148,17 @@ func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string
|
||||
|
||||
NewConfigMapFromDirectory creates a new ConfigMap from a compose service. This path is the path to the file or directory. If the path is a directory, all files in the directory are added to the ConfigMap. Each subdirectory are ignored. Note that the Generate\(\) function will create the subdirectories ConfigMaps.
|
||||
|
||||
<a name="ConfigMap.AddBinaryData"></a>
|
||||
### func \(\*ConfigMap\) [AddBinaryData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L155>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AddBinaryData(key string, value []byte)
|
||||
```
|
||||
|
||||
AddBinaryData adds binary data to the configmap. Append or overwrite the value if the key already exists.
|
||||
|
||||
<a name="ConfigMap.AddData"></a>
|
||||
### func \(\*ConfigMap\) [AddData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L148>)
|
||||
### func \(\*ConfigMap\) [AddData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L150>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AddData(key, value string)
|
||||
@@ -158,25 +167,25 @@ func (c *ConfigMap) AddData(key, value string)
|
||||
AddData adds a key value pair to the configmap. Append or overwrite the value if the key already exists.
|
||||
|
||||
<a name="ConfigMap.AppendDir"></a>
|
||||
### func \(\*ConfigMap\) [AppendDir](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L154>)
|
||||
### func \(\*ConfigMap\) [AppendDir](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L164>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AppendDir(path string)
|
||||
func (c *ConfigMap) AppendDir(path string) error
|
||||
```
|
||||
|
||||
AddFile adds files from given path to the configmap. It is not recursive, to add all files in a directory, you need to call this function for each subdirectory.
|
||||
|
||||
<a name="ConfigMap.AppendFile"></a>
|
||||
### func \(\*ConfigMap\) [AppendFile](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L189>)
|
||||
### func \(\*ConfigMap\) [AppendFile](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L211>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) AppendFile(path string)
|
||||
func (c *ConfigMap) AppendFile(path string) error
|
||||
```
|
||||
|
||||
|
||||
|
||||
<a name="ConfigMap.Filename"></a>
|
||||
### func \(\*ConfigMap\) [Filename](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L207>)
|
||||
### func \(\*ConfigMap\) [Filename](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L235>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) Filename() string
|
||||
@@ -185,7 +194,7 @@ func (c *ConfigMap) Filename() string
|
||||
Filename returns the filename of the configmap. If the configmap is used for files, the filename contains the path.
|
||||
|
||||
<a name="ConfigMap.SetData"></a>
|
||||
### func \(\*ConfigMap\) [SetData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L217>)
|
||||
### func \(\*ConfigMap\) [SetData](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L245>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) SetData(data map[string]string)
|
||||
@@ -194,7 +203,7 @@ func (c *ConfigMap) SetData(data map[string]string)
|
||||
SetData sets the data of the configmap. It replaces the entire data.
|
||||
|
||||
<a name="ConfigMap.Yaml"></a>
|
||||
### func \(\*ConfigMap\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L222>)
|
||||
### func \(\*ConfigMap\) [Yaml](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L250>)
|
||||
|
||||
```go
|
||||
func (c *ConfigMap) Yaml() ([]byte, error)
|
||||
@@ -421,7 +430,7 @@ func (d *Deployment) Yaml() ([]byte, error)
|
||||
Yaml returns the yaml representation of the deployment.
|
||||
|
||||
<a name="FileMapUsage"></a>
|
||||
## type [FileMapUsage](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L19>)
|
||||
## type [FileMapUsage](<https://github.com/metal3d/katenary/blob/develop/generator/configMap.go#L21>)
|
||||
|
||||
FileMapUsage is the usage of the filemap.
|
||||
|
||||
|
@@ -196,13 +196,13 @@ type Icon string
|
||||
const (
|
||||
IconSuccess Icon = "✅"
|
||||
IconFailure Icon = "❌"
|
||||
IconWarning Icon = "⚠️'"
|
||||
IconWarning Icon = "❕"
|
||||
IconNote Icon = "📝"
|
||||
IconWorld Icon = "🌐"
|
||||
IconPlug Icon = "🔌"
|
||||
IconPackage Icon = "📦"
|
||||
IconCabinet Icon = "🗄️"
|
||||
IconInfo Icon = "❕"
|
||||
IconInfo Icon = "🔵"
|
||||
IconSecret Icon = "🔒"
|
||||
IconConfig Icon = "🔧"
|
||||
IconDependency Icon = "🔗"
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"katenary/generator/labels"
|
||||
"katenary/generator/labels/labelStructs"
|
||||
"katenary/utils"
|
||||
@@ -9,8 +10,9 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -149,58 +151,84 @@ func (c *ConfigMap) AddData(key, value string) {
|
||||
c.Data[key] = value
|
||||
}
|
||||
|
||||
// AddBinaryData adds binary data to the configmap. Append or overwrite the value if the key already exists.
|
||||
func (c *ConfigMap) AddBinaryData(key string, value []byte) {
|
||||
if c.BinaryData == nil {
|
||||
c.BinaryData = make(map[string][]byte)
|
||||
}
|
||||
c.BinaryData[key] = value
|
||||
}
|
||||
|
||||
// AddFile adds files from given path to the configmap. It is not recursive, to add all files in a directory,
|
||||
// you need to call this function for each subdirectory.
|
||||
func (c *ConfigMap) AppendDir(path string) {
|
||||
func (c *ConfigMap) AppendDir(path string) error {
|
||||
// read all files in the path and add them to the configmap
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
log.Fatalf("Path %s does not exist\n", path)
|
||||
return fmt.Errorf("Path %s does not exist, %w\n", path, err)
|
||||
}
|
||||
// recursively read all files in the path and add them to the configmap
|
||||
if stat.IsDir() {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
utils.Warn("Subdirectories are ignored for the moment, skipping", filepath.Join(path, file.Name()))
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(path, file.Name())
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
// remove the path from the file
|
||||
filename := filepath.Base(path)
|
||||
c.AddData(filename, string(content))
|
||||
if utf8.Valid(content) {
|
||||
c.AddData(filename, string(content))
|
||||
} else {
|
||||
c.AddBinaryData(filename, content)
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
// add the file to the configmap
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
filename := filepath.Base(path)
|
||||
if utf8.Valid(content) {
|
||||
c.AddData(filename, string(content))
|
||||
} else {
|
||||
c.AddBinaryData(filename, content)
|
||||
}
|
||||
c.AddData(filepath.Base(path), string(content))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConfigMap) AppendFile(path string) {
|
||||
func (c *ConfigMap) AppendFile(path string) error {
|
||||
// read all files in the path and add them to the configmap
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
log.Fatalf("Path %s does not exist\n", path)
|
||||
return fmt.Errorf("Path %s doesn not exists, %w", path, err)
|
||||
}
|
||||
// recursively read all files in the path and add them to the configmap
|
||||
if !stat.IsDir() {
|
||||
// add the file to the configmap
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
c.AddData(filepath.Base(path), string(content))
|
||||
if utf8.Valid(content) {
|
||||
c.AddData(filepath.Base(path), string(content))
|
||||
} else {
|
||||
c.AddBinaryData(filepath.Base(path), content)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filename returns the filename of the configmap. If the configmap is used for files, the filename contains the path.
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
@@ -73,3 +74,19 @@ services:
|
||||
t.Errorf("Expected FOO to be baz, got %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendBadFile(t *testing.T) {
|
||||
cm := NewConfigMap(types.ServiceConfig{}, "app", true)
|
||||
err := cm.AppendFile("foo")
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendBadDir(t *testing.T) {
|
||||
cm := NewConfigMap(types.ServiceConfig{}, "app", true)
|
||||
err := cm.AppendDir("foo")
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, got nil")
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
)
|
||||
|
||||
const ingressClassHelp = `# Default value for ingress.class annotation
|
||||
@@ -85,12 +85,18 @@ var unwantedLines = []string{
|
||||
"status:",
|
||||
}
|
||||
|
||||
var ingressTLSHelp = `# Ingress TLS configuration
|
||||
# If enabled, a secret containing the certificate and the key should be
|
||||
# created by the ingress controller. If the name if emtpy, so the secret
|
||||
# name is generated. You can specify the secret name to use your own secret.
|
||||
`
|
||||
|
||||
// keyRegExp checks if the line starts by a #
|
||||
var keyRegExp = regexp.MustCompile(`^\s*[^#]+:.*`)
|
||||
|
||||
// Convert a compose (docker, podman...) project to a helm chart.
|
||||
// It calls Generate() to generate the chart and then write it to the disk.
|
||||
func Convert(config ConvertOptions, dockerComposeFile ...string) {
|
||||
func Convert(config ConvertOptions, dockerComposeFile ...string) error {
|
||||
var (
|
||||
templateDir = filepath.Join(config.OutputDir, "templates")
|
||||
helpersPath = filepath.Join(config.OutputDir, "templates", "_helpers.tpl")
|
||||
@@ -105,7 +111,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
|
||||
// go to the root of the project
|
||||
if err := os.Chdir(filepath.Dir(dockerComposeFile[0])); err != nil {
|
||||
fmt.Println(utils.IconFailure, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
defer os.Chdir(currentDir) // after the generation, go back to the original directory
|
||||
|
||||
@@ -118,13 +124,13 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
|
||||
project, err := parser.Parse(config.Profiles, config.EnvFiles, dockerComposeFile...)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// check older version of labels
|
||||
if err := checkOldLabels(project); err != nil {
|
||||
fmt.Println(utils.IconFailure, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: use katenary.yaml file here to set the labels
|
||||
@@ -140,7 +146,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
|
||||
)
|
||||
if !overwrite {
|
||||
fmt.Println("Aborting")
|
||||
os.Exit(126) // 126 is the exit code for "Command invoked cannot execute"
|
||||
return nil
|
||||
}
|
||||
}
|
||||
fmt.Println() // clean line
|
||||
@@ -150,7 +156,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
|
||||
chart, err := Generate(project)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// if the app version is set from the command line, use it
|
||||
@@ -194,6 +200,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) {
|
||||
|
||||
// call helm update if needed
|
||||
callHelmUpdate(config)
|
||||
return nil
|
||||
}
|
||||
|
||||
func addChartDoc(values []byte, project *types.Project) []byte {
|
||||
@@ -485,6 +492,24 @@ func addYAMLSelectorPath(values []byte) []byte {
|
||||
return []byte(strings.Join(toReturn, "\n"))
|
||||
}
|
||||
|
||||
// addTLSHelp adds a comment to the values.yaml file to explain how to
|
||||
// use the tls option.
|
||||
func addTLSHelp(values []byte) []byte {
|
||||
lines := strings.Split(string(values), "\n")
|
||||
for i, line := range lines {
|
||||
if strings.Contains(line, "tls:") {
|
||||
spaces := utils.CountStartingSpaces(line)
|
||||
spacesString := strings.Repeat(" ", spaces)
|
||||
// indent ingressClassHelper comment
|
||||
ingressTLSHelp := strings.ReplaceAll(ingressTLSHelp, "\n", "\n"+spacesString)
|
||||
ingressTLSHelp = strings.TrimRight(ingressTLSHelp, " ")
|
||||
ingressTLSHelp = spacesString + ingressTLSHelp
|
||||
lines[i] = ingressTLSHelp + line
|
||||
}
|
||||
}
|
||||
return []byte(strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
func buildCharYamlFile(chart *HelmChart, project *types.Project, chartPath string) {
|
||||
// calculate the sha1 hash of the services
|
||||
yamlChart, err := utils.EncodeBasicYaml(chart)
|
||||
@@ -536,6 +561,7 @@ func buildValues(chart *HelmChart, project *types.Project, valuesPath string) {
|
||||
values = addVariablesDoc(values, project)
|
||||
values = addMainTagAppDoc(values, project)
|
||||
values = addResourceHelp(values)
|
||||
values = addTLSHelp(values)
|
||||
values = addYAMLSelectorPath(values)
|
||||
values = append([]byte(headerHelp), values...)
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
networkv1 "k8s.io/api/networking/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -17,6 +17,7 @@ var _ Yaml = (*Ingress)(nil)
|
||||
type Ingress struct {
|
||||
*networkv1.Ingress
|
||||
service *types.ServiceConfig `yaml:"-"`
|
||||
appName string `yaml:"-"`
|
||||
}
|
||||
|
||||
// NewIngress creates a new Ingress from a compose service.
|
||||
@@ -42,7 +43,11 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
|
||||
|
||||
// create the ingress
|
||||
pathType := networkv1.PathTypeImplementationSpecific
|
||||
serviceName := `{{ include "` + appName + `.fullname" . }}-` + service.Name
|
||||
|
||||
// fix the service name, and create the full name from variable name
|
||||
// which is injected in the YAML() method
|
||||
serviceName := strings.ReplaceAll(service.Name, "_", "-")
|
||||
fullName := `{{ $fullname }}-` + serviceName
|
||||
|
||||
// Add the ingress host to the values.yaml
|
||||
if Chart.Values[service.Name] == nil {
|
||||
@@ -63,7 +68,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
|
||||
|
||||
servicePortName := utils.GetServiceNameByPort(int(*mapping.Port))
|
||||
ingressService := &networkv1.IngressServiceBackend{
|
||||
Name: serviceName,
|
||||
Name: fullName,
|
||||
Port: networkv1.ServiceBackendPort{},
|
||||
}
|
||||
if servicePortName != "" {
|
||||
@@ -74,26 +79,27 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
|
||||
|
||||
ing := &Ingress{
|
||||
service: &service,
|
||||
appName: appName,
|
||||
Ingress: &networkv1.Ingress{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Ingress",
|
||||
APIVersion: "networking.k8s.io/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: utils.TplName(service.Name, appName),
|
||||
Labels: GetLabels(service.Name, appName),
|
||||
Name: fullName,
|
||||
Labels: GetLabels(serviceName, appName),
|
||||
Annotations: Annotations,
|
||||
},
|
||||
Spec: networkv1.IngressSpec{
|
||||
IngressClassName: &ingressClassName,
|
||||
Rules: []networkv1.IngressRule{
|
||||
{
|
||||
Host: utils.TplValue(service.Name, "ingress.host"),
|
||||
Host: utils.TplValue(serviceName, "ingress.host"),
|
||||
IngressRuleValue: networkv1.IngressRuleValue{
|
||||
HTTP: &networkv1.HTTPIngressRuleValue{
|
||||
Paths: []networkv1.HTTPIngressPath{
|
||||
{
|
||||
Path: utils.TplValue(service.Name, "ingress.path"),
|
||||
Path: utils.TplValue(serviceName, "ingress.path"),
|
||||
PathType: &pathType,
|
||||
Backend: networkv1.IngressBackend{
|
||||
Service: ingressService,
|
||||
@@ -107,9 +113,9 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress {
|
||||
TLS: []networkv1.IngressTLS{
|
||||
{
|
||||
Hosts: []string{
|
||||
`{{ tpl .Values.` + service.Name + `.ingress.host . }}`,
|
||||
`{{ tpl .Values.` + serviceName + `.ingress.host . }}`,
|
||||
},
|
||||
SecretName: `{{ include "` + appName + `.fullname" . }}-` + service.Name + `-tls`,
|
||||
SecretName: `{{ .Values.` + serviceName + `.ingress.tls.secretName | default $tlsname }}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -131,9 +137,7 @@ func (ingress *Ingress) Yaml() ([]byte, error) {
|
||||
}
|
||||
|
||||
serviceName := ingress.service.Name
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret = UnWrapTPL(ret)
|
||||
|
||||
lines := strings.Split(string(ret), "\n")
|
||||
@@ -141,9 +145,7 @@ func (ingress *Ingress) Yaml() ([]byte, error) {
|
||||
// first pass, wrap the tls part with `{{- if .Values.serviceName.ingress.tlsEnabled -}}`
|
||||
// and `{{- end -}}`
|
||||
|
||||
from := -1
|
||||
to := -1
|
||||
spaces := -1
|
||||
from, to, spaces := -1, -1, -1
|
||||
for i, line := range lines {
|
||||
if strings.Contains(line, "tls:") {
|
||||
from = i
|
||||
@@ -167,6 +169,8 @@ func (ingress *Ingress) Yaml() ([]byte, error) {
|
||||
|
||||
out := []string{
|
||||
`{{- if .Values.` + serviceName + `.ingress.enabled -}}`,
|
||||
`{{- $fullname := include "` + ingress.appName + `.fullname" . -}}`,
|
||||
`{{- $tlsname := printf "%s-%s-tls" $fullname "` + ingress.service.Name + `" -}}`,
|
||||
}
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "loadBalancer: ") {
|
||||
|
@@ -31,7 +31,11 @@ services:
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web/ingress.yaml", "--set", "web.ingress.enabled=true")
|
||||
output := internalCompileTest(
|
||||
t,
|
||||
"-s", "templates/web/ingress.yaml",
|
||||
"--set", "web.ingress.enabled=true",
|
||||
)
|
||||
ingress := v1.Ingress{}
|
||||
if err := yaml.Unmarshal([]byte(output), &ingress); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
@@ -43,3 +47,82 @@ services:
|
||||
t.Errorf("Expected host to be my.test.tld, got %s", ingress.Spec.Rules[0].Host)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLS(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web:
|
||||
image: nginx:1.29
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
labels:
|
||||
%s/ingress: |-
|
||||
hostname: my.test.tld
|
||||
port: 80
|
||||
`
|
||||
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
|
||||
tmpDir := setup(composeFile)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(
|
||||
t,
|
||||
"-s", "templates/web/ingress.yaml",
|
||||
"--set", "web.ingress.enabled=true",
|
||||
)
|
||||
ingress := v1.Ingress{}
|
||||
if err := yaml.Unmarshal([]byte(output), &ingress); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
// find the tls section
|
||||
tls := ingress.Spec.TLS
|
||||
if len(tls) != 1 {
|
||||
t.Errorf("Expected 1 tls section, got %d", len(tls))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSName(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web:
|
||||
image: nginx:1.29
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
labels:
|
||||
%s/ingress: |-
|
||||
hostname: my.test.tld
|
||||
port: 80
|
||||
`
|
||||
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
|
||||
tmpDir := setup(composeFile)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(
|
||||
t,
|
||||
"-s",
|
||||
"templates/web/ingress.yaml",
|
||||
"--set", "web.ingress.enabled=true",
|
||||
"--set", "web.ingress.tls.secretName=mysecret",
|
||||
)
|
||||
ingress := v1.Ingress{}
|
||||
if err := yaml.Unmarshal([]byte(output), &ingress); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
// find the tls section
|
||||
tls := ingress.Spec.TLS
|
||||
if len(tls) != 1 {
|
||||
t.Errorf("Expected 1 tls section, got %d", len(tls))
|
||||
}
|
||||
if tls[0].SecretName != "mysecret" {
|
||||
t.Errorf("Expected secretName to be mysecret, got %s", tls[0].SecretName)
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/invopop/jsonschema"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -72,27 +72,29 @@ func OverrideWithConfig(project *types.Project) {
|
||||
}
|
||||
for i, p := range project.Services {
|
||||
name := p.Name
|
||||
if project.Services[i].Labels == nil {
|
||||
project.Services[i].Labels = make(map[string]string)
|
||||
if p.Labels == nil {
|
||||
p.Labels = make(map[string]string)
|
||||
project.Services[i] = p
|
||||
}
|
||||
|
||||
if s, ok := services[name]; ok {
|
||||
getLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp)
|
||||
getLabelContent(s.Values, &project.Services[i], labels.LabelValues)
|
||||
getLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets)
|
||||
getLabelContent(s.Ports, &project.Services[i], labels.LabelPorts)
|
||||
getLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress)
|
||||
getLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck)
|
||||
getLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod)
|
||||
getLabelContent(s.Description, &project.Services[i], labels.LabelDescription)
|
||||
getLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore)
|
||||
getLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies)
|
||||
getLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles)
|
||||
getLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv)
|
||||
getLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob)
|
||||
getLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom)
|
||||
getLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume)
|
||||
getLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom)
|
||||
service := project.Services[i]
|
||||
getLabelContent(s.MainApp, &service, labels.LabelMainApp)
|
||||
getLabelContent(s.Values, &service, labels.LabelValues)
|
||||
getLabelContent(s.Secrets, &service, labels.LabelSecrets)
|
||||
getLabelContent(s.Ports, &service, labels.LabelPorts)
|
||||
getLabelContent(s.Ingress, &service, labels.LabelIngress)
|
||||
getLabelContent(s.HealthCheck, &service, labels.LabelHealthCheck)
|
||||
getLabelContent(s.SamePod, &service, labels.LabelSamePod)
|
||||
getLabelContent(s.Description, &service, labels.LabelDescription)
|
||||
getLabelContent(s.Ignore, &service, labels.LabelIgnore)
|
||||
getLabelContent(s.Dependencies, &service, labels.LabelDependencies)
|
||||
getLabelContent(s.ConfigMapFile, &service, labels.LabelConfigMapFiles)
|
||||
getLabelContent(s.MapEnv, &service, labels.LabelMapEnv)
|
||||
getLabelContent(s.CronJob, &service, labels.LabelCronJob)
|
||||
getLabelContent(s.EnvFrom, &service, labels.LabelEnvFrom)
|
||||
getLabelContent(s.ExchangeVolumes, &service, labels.LabelExchangeVolume)
|
||||
getLabelContent(s.ValuesFrom, &service, labels.LabelValueFrom)
|
||||
}
|
||||
}
|
||||
fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.")
|
||||
@@ -123,6 +125,9 @@ func getLabelContent(o any, service *types.ServiceConfig, labelName string) erro
|
||||
val = strings.TrimSpace(string(c))
|
||||
}
|
||||
|
||||
if service.Labels == nil {
|
||||
service.Labels = make(map[string]string)
|
||||
}
|
||||
service.Labels[labelName] = val
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
package katenaryfile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"katenary/generator/labels"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/v2/cli"
|
||||
)
|
||||
|
||||
func TestBuildSchema(t *testing.T) {
|
||||
@@ -33,7 +34,7 @@ webapp:
|
||||
// create /tmp/katenary-test-override directory, save the compose.yaml file
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-override")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
composeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
katenaryFile := filepath.Join(tmpDir, "katenary.yaml")
|
||||
@@ -56,10 +57,13 @@ webapp:
|
||||
cli.WithWorkingDirectory(tmpDir),
|
||||
cli.WithDefaultConfigPath,
|
||||
)
|
||||
project, err := cli.ProjectFromOptions(options)
|
||||
project, err := cli.ProjectFromOptions(context.TODO(), options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
OverrideWithConfig(project)
|
||||
w := project.Services[0].Labels
|
||||
w := project.Services["webapp"].Labels
|
||||
if v, ok := w[labels.LabelPorts]; !ok {
|
||||
t.Fatal("Expected ports to be defined", v)
|
||||
}
|
||||
@@ -83,7 +87,7 @@ webapp:
|
||||
// create /tmp/katenary-test-override directory, save the compose.yaml file
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-override")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
composeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
katenaryFile := filepath.Join(tmpDir, "katenary.yaml")
|
||||
@@ -106,10 +110,14 @@ webapp:
|
||||
cli.WithWorkingDirectory(tmpDir),
|
||||
cli.WithDefaultConfigPath,
|
||||
)
|
||||
project, err := cli.ProjectFromOptions(options)
|
||||
project, err := cli.ProjectFromOptions(context.TODO(), options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
OverrideWithConfig(project)
|
||||
w := project.Services[0].Labels
|
||||
log.Println(project.Services["webapp"].Labels)
|
||||
w := project.Services["webapp"].Labels
|
||||
if v, ok := w[labels.LabelPorts]; !ok {
|
||||
t.Fatal("Expected ports to be defined", v)
|
||||
}
|
||||
|
@@ -338,9 +338,9 @@
|
||||
MARIADB_USER: myuser
|
||||
MARIADB_PASSWORD: mypassword
|
||||
labels:
|
||||
# it can be a secret
|
||||
# we can declare secrets
|
||||
{{ .KatenaryPrefix }}/secrets: |-
|
||||
- DB_PASSWORD
|
||||
- MARIADB_PASSWORD
|
||||
php:
|
||||
image: php:7.4-fpm
|
||||
environment:
|
||||
|
@@ -3,7 +3,7 @@ package generator
|
||||
import (
|
||||
"katenary/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"katenary/utils"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
@@ -48,7 +48,9 @@ func internalCompileTest(t *testing.T, options ...string) string {
|
||||
AppVersion: appVersion,
|
||||
ChartVersion: chartVersion,
|
||||
}
|
||||
Convert(convertOptions, "compose.yml")
|
||||
if err := Convert(convertOptions, "compose.yml"); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// launch helm lint to check the generated chart
|
||||
if helmLint(convertOptions) != nil {
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
@@ -1,13 +1,14 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"katenary/generator/labels"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/v2/cli"
|
||||
)
|
||||
|
||||
func TestSplitPorts(t *testing.T) {
|
||||
@@ -21,7 +22,7 @@ services:
|
||||
composeFileContent = fmt.Sprintf(composeFileContent, labels.KatenaryLabelPrefix)
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-override")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
composeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
|
||||
@@ -37,12 +38,18 @@ services:
|
||||
cli.WithWorkingDirectory(tmpDir),
|
||||
cli.WithDefaultConfigPath,
|
||||
)
|
||||
project, err := cli.ProjectFromOptions(options)
|
||||
if err := fixPorts(&project.Services[0]); err != nil {
|
||||
project, err := cli.ProjectFromOptions(context.TODO(), options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := project.Services["foo"]
|
||||
if err := fixPorts(&service); err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
project.Services["foo"] = service
|
||||
found := 0
|
||||
for _, p := range project.Services[0].Ports {
|
||||
t.Log(service.Ports, project.Services["foo"].Ports)
|
||||
for _, p := range project.Services["foo"].Ports {
|
||||
switch p.Target {
|
||||
case 80, 443:
|
||||
found++
|
||||
@@ -66,7 +73,7 @@ services:
|
||||
composeFileContent = fmt.Sprintf(composeFileContent, labels.KatenaryLabelPrefix)
|
||||
tmpDir, err := os.MkdirTemp("", "katenary-test-override")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatal(err)
|
||||
}
|
||||
composeFile := filepath.Join(tmpDir, "compose.yaml")
|
||||
|
||||
@@ -82,12 +89,16 @@ services:
|
||||
cli.WithWorkingDirectory(tmpDir),
|
||||
cli.WithDefaultConfigPath,
|
||||
)
|
||||
project, err := cli.ProjectFromOptions(options)
|
||||
if err := fixPorts(&project.Services[0]); err != nil {
|
||||
project, err := cli.ProjectFromOptions(context.TODO(), options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := project.Services["foo"]
|
||||
if err := fixPorts(&service); err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
found := 0
|
||||
for _, p := range project.Services[0].Ports {
|
||||
for _, p := range service.Ports {
|
||||
switch p.Target {
|
||||
case 80, 443, 8080:
|
||||
found++
|
||||
|
@@ -3,7 +3,7 @@ package generator
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
)
|
||||
|
||||
// RepositoryValue is a docker repository image and tag that will be saved in values.yaml.
|
||||
@@ -21,7 +21,8 @@ type PersistenceValue struct {
|
||||
}
|
||||
|
||||
type TLS struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
SecretName string `yaml:"secretName"`
|
||||
}
|
||||
|
||||
// IngressValue is a ingress configuration that will be saved in values.yaml.
|
||||
@@ -92,6 +93,10 @@ func (v *Value) AddIngress(host, path string) {
|
||||
Host: host,
|
||||
Path: path,
|
||||
Class: "-",
|
||||
TLS: TLS{
|
||||
Enabled: true,
|
||||
SecretName: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"katenary/utils"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@@ -2,8 +2,13 @@ package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"katenary/generator/labels"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
@@ -11,7 +16,11 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const htmlContent = "<html><body><h1>Hello, World!</h1></body></html>"
|
||||
const (
|
||||
htmlContent = "<html><body><h1>Hello, World!</h1></body></html>"
|
||||
developementFile = "templates/web/deployment.yaml"
|
||||
indexHtmlFile = "index.html"
|
||||
)
|
||||
|
||||
func TestGenerateWithBoundVolume(t *testing.T) {
|
||||
composeFile := `
|
||||
@@ -30,7 +39,7 @@ volumes:
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web/deployment.yaml")
|
||||
output := internalCompileTest(t, "-s", developementFile)
|
||||
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
@@ -38,7 +47,7 @@ volumes:
|
||||
}
|
||||
|
||||
if dt.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name != "data" {
|
||||
t.Errorf("Expected volume name to be data: %v", dt)
|
||||
t.Errorf("Expected container volume name to be data: %v", dt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +80,7 @@ services:
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web/deployment.yaml")
|
||||
output := internalCompileTest(t, "-s", developementFile)
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
@@ -97,8 +106,8 @@ services:
|
||||
if len(data) != 1 {
|
||||
t.Errorf("Expected 1 data, got %d", len(data))
|
||||
}
|
||||
if data["index.html"] != htmlContent {
|
||||
t.Errorf("Expected index.html to be "+htmlContent+", got %s", data["index.html"])
|
||||
if data[indexHtmlFile] != htmlContent {
|
||||
t.Errorf("Expected index.html to be "+htmlContent+", got %s", data[indexHtmlFile])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +140,7 @@ services:
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web/deployment.yaml")
|
||||
output := internalCompileTest(t, "-s", developementFile)
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
@@ -144,11 +153,151 @@ services:
|
||||
}
|
||||
// but this time, we need a subpath
|
||||
subPath := dt.Spec.Template.Spec.Containers[0].VolumeMounts[0].SubPath
|
||||
if subPath != "index.html" {
|
||||
if subPath != indexHtmlFile {
|
||||
t.Errorf("Expected subpath to be index.html, got %s", subPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinaryMount(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
volumes:
|
||||
- ./images/foo.png:/var/www/foo
|
||||
labels:
|
||||
%[1]s/configmap-files: |-
|
||||
- ./images/foo.png
|
||||
`
|
||||
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
|
||||
tmpDir := setup(composeFile)
|
||||
log.Println(tmpDir)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
os.Mkdir(filepath.Join(tmpDir, "images"), 0o755)
|
||||
|
||||
// create a png image
|
||||
pngFile := tmpDir + "/images/foo.png"
|
||||
w, h := 100, 100
|
||||
img := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
red := color.RGBA{255, 0, 0, 255}
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
img.Set(x, y, red)
|
||||
}
|
||||
}
|
||||
|
||||
blue := color.RGBA{0, 0, 255, 255}
|
||||
for y := 30; y < 70; y++ {
|
||||
for x := 30; x < 70; x++ {
|
||||
img.Set(x, y, blue)
|
||||
}
|
||||
}
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
f, err := os.Create(pngFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
png.Encode(f, img)
|
||||
f.Close()
|
||||
output := internalCompileTest(t, "-s", developementFile)
|
||||
d := v1.Deployment{}
|
||||
yaml.Unmarshal([]byte(output), &d)
|
||||
volumes := d.Spec.Template.Spec.Volumes
|
||||
if len(volumes) != 1 {
|
||||
t.Errorf("Expected 1 volume, got %d", len(volumes))
|
||||
}
|
||||
|
||||
cm := corev1.ConfigMap{}
|
||||
cmContent, err := helmTemplate(ConvertOptions{
|
||||
OutputDir: "chart",
|
||||
}, "-s", "templates/web/statics/images/configmap.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
yaml.Unmarshal([]byte(cmContent), &cm)
|
||||
if im, ok := cm.BinaryData["foo.png"]; !ok {
|
||||
t.Errorf("Expected foo.png to be in the configmap")
|
||||
} else {
|
||||
if len(im) == 0 {
|
||||
t.Errorf("Expected image to be non-empty")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGloballyBinaryMount(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
volumes:
|
||||
- ./images:/var/www/foo
|
||||
labels:
|
||||
%[1]s/configmap-files: |-
|
||||
- ./images
|
||||
`
|
||||
composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix)
|
||||
tmpDir := setup(composeFile)
|
||||
log.Println(tmpDir)
|
||||
defer teardown(tmpDir)
|
||||
|
||||
os.Mkdir(filepath.Join(tmpDir, "images"), 0o755)
|
||||
|
||||
// create a png image
|
||||
pngFile := tmpDir + "/images/foo.png"
|
||||
w, h := 100, 100
|
||||
img := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
red := color.RGBA{255, 0, 0, 255}
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
img.Set(x, y, red)
|
||||
}
|
||||
}
|
||||
|
||||
blue := color.RGBA{0, 0, 255, 255}
|
||||
for y := 30; y < 70; y++ {
|
||||
for x := 30; x < 70; x++ {
|
||||
img.Set(x, y, blue)
|
||||
}
|
||||
}
|
||||
currentDir, _ := os.Getwd()
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
f, err := os.Create(pngFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
png.Encode(f, img)
|
||||
f.Close()
|
||||
output := internalCompileTest(t, "-s", developementFile)
|
||||
d := v1.Deployment{}
|
||||
yaml.Unmarshal([]byte(output), &d)
|
||||
volumes := d.Spec.Template.Spec.Volumes
|
||||
if len(volumes) != 1 {
|
||||
t.Errorf("Expected 1 volume, got %d", len(volumes))
|
||||
}
|
||||
|
||||
cm := corev1.ConfigMap{}
|
||||
cmContent, err := helmTemplate(ConvertOptions{
|
||||
OutputDir: "chart",
|
||||
}, "-s", "templates/web/statics/images/configmap.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
yaml.Unmarshal([]byte(cmContent), &cm)
|
||||
if im, ok := cm.BinaryData["foo.png"]; !ok {
|
||||
t.Errorf("Expected foo.png to be in the configmap")
|
||||
} else {
|
||||
if len(im) == 0 {
|
||||
t.Errorf("Expected image to be non-empty")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindFrom(t *testing.T) {
|
||||
composeFile := `
|
||||
services:
|
||||
@@ -178,17 +327,17 @@ volumes:
|
||||
os.Chdir(tmpDir)
|
||||
defer os.Chdir(currentDir)
|
||||
|
||||
output := internalCompileTest(t, "-s", "templates/web/deployment.yaml")
|
||||
output := internalCompileTest(t, "-s", developementFile)
|
||||
dt := v1.Deployment{}
|
||||
if err := yaml.Unmarshal([]byte(output), &dt); err != nil {
|
||||
t.Errorf(unmarshalError, err)
|
||||
}
|
||||
// both containers should have the same volume mount
|
||||
if dt.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name != "data" {
|
||||
t.Errorf("Expected volume name to be data: %v", dt)
|
||||
t.Errorf("Expected container 0 volume name to be data: %v", dt)
|
||||
}
|
||||
if dt.Spec.Template.Spec.Containers[1].VolumeMounts[0].Name != "data" {
|
||||
t.Errorf("Expected volume name to be data: %v", dt)
|
||||
t.Errorf("Expected container 1 volume name to be data: %v", dt)
|
||||
}
|
||||
}
|
||||
|
||||
|
32
go.mod
32
go.mod
@@ -1,19 +1,18 @@
|
||||
module katenary // github.com/metal3d/katenary
|
||||
|
||||
go 1.23
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.23.2
|
||||
toolchain go1.23.4
|
||||
|
||||
require (
|
||||
github.com/compose-spec/compose-go v1.20.2
|
||||
github.com/compose-spec/compose-go/v2 v2.4.6
|
||||
github.com/invopop/jsonschema v0.12.0
|
||||
github.com/mitchellh/go-wordwrap v1.0.1
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/thediveo/netdb v1.1.2
|
||||
golang.org/x/mod v0.22.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.31.2
|
||||
k8s.io/apimachinery v0.31.2
|
||||
k8s.io/api v0.32.0
|
||||
k8s.io/apimachinery v0.32.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
@@ -25,18 +24,17 @@ require (
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
@@ -44,14 +42,14 @@ require (
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
|
||||
golang.org/x/net v0.32.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||
)
|
||||
|
72
go.sum
72
go.sum
@@ -2,9 +2,10 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ=
|
||||
github.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||
github.com/compose-spec/compose-go/v2 v2.4.6 h1:QiqXQ2L/f0OCbAl41bPpeiGAWVRIQ+GEDrYxO+dRPhQ=
|
||||
github.com/compose-spec/compose-go/v2 v2.4.6/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -22,6 +23,8 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
@@ -30,15 +33,12 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
|
||||
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
@@ -47,27 +47,23 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
|
||||
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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=
|
||||
@@ -103,39 +99,37 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -150,17 +144,17 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
||||
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
|
||||
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
|
||||
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
|
||||
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
|
||||
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
|
||||
k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
|
||||
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno=
|
||||
k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
@@ -2,11 +2,12 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/cli"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -53,5 +54,5 @@ func Parse(profiles []string, envFiles []string, dockerComposeFile ...string) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cli.ProjectFromOptions(options)
|
||||
return cli.ProjectFromOptions(context.TODO(), options)
|
||||
}
|
||||
|
148
update/main.go
148
update/main.go
@@ -1,148 +0,0 @@
|
||||
/* Update package is used to check if a new version of katenary is available.*/
|
||||
package update
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
var (
|
||||
exe, _ = os.Executable()
|
||||
Version = "master" // reset by cmd/main.go
|
||||
)
|
||||
|
||||
// Asset is a github asset from release url.
|
||||
type Asset struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"browser_download_url"`
|
||||
}
|
||||
|
||||
// CheckLatestVersion check katenary latest version from release and propose to download it
|
||||
func CheckLatestVersion() (string, []Asset, error) {
|
||||
githuburl := "https://api.github.com/repos/metal3d/katenary/releases/latest"
|
||||
// Create a HTTP client with 1s timeout
|
||||
client := &http.Client{
|
||||
Timeout: time.Second * 1,
|
||||
}
|
||||
// Create a request
|
||||
req, err := http.NewRequest("GET", githuburl, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// Send the request via a client
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Get tag_name from the json response
|
||||
release := struct {
|
||||
TagName string `json:"tag_name"`
|
||||
Assets []Asset `json:"assets"`
|
||||
PreRelease bool `json:"prerelease"`
|
||||
}{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&release)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// if it's a prerelease, don't update
|
||||
if release.PreRelease {
|
||||
return "", nil, errors.New("prerelease detected, not updating")
|
||||
}
|
||||
|
||||
// no tag, don't update
|
||||
if release.TagName == "" {
|
||||
return "", nil, errors.New("no release found")
|
||||
}
|
||||
|
||||
// compare the current version, if the current version is the same or lower than the latest version, don't update
|
||||
versions := []string{Version, release.TagName}
|
||||
semver.Sort(versions)
|
||||
if versions[1] == Version {
|
||||
return "", nil, errors.New("current version is the latest version")
|
||||
}
|
||||
|
||||
return release.TagName, release.Assets, nil
|
||||
}
|
||||
|
||||
// DownloadLatestVersion will download the latest version of katenary.
|
||||
func DownloadLatestVersion(assets []Asset) error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
os.Rename(exe+".old", exe)
|
||||
}
|
||||
}()
|
||||
|
||||
// Download the latest version
|
||||
fmt.Println("Downloading the latest version...")
|
||||
|
||||
// ok, replace this from the current version to the latest version
|
||||
err := os.Rename(exe, exe+".old")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Download the latest version for the current OS
|
||||
for _, asset := range assets {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
if asset.Name == "katenary.exe" {
|
||||
err = DownloadFile(asset.URL, exe)
|
||||
}
|
||||
case "linux":
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
if asset.Name == "katenary-linux-amd64" {
|
||||
err = DownloadFile(asset.URL, exe)
|
||||
}
|
||||
case "arm64":
|
||||
if asset.Name == "katenary-linux-arm64" {
|
||||
err = DownloadFile(asset.URL, exe)
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
if asset.Name == "katenary-darwin" {
|
||||
err = DownloadFile(asset.URL, exe)
|
||||
}
|
||||
default:
|
||||
fmt.Println("Unsupported OS")
|
||||
err = errors.New("unsupported OS")
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
// remove the old version
|
||||
os.Remove(exe + ".old")
|
||||
} else {
|
||||
// restore the old version
|
||||
os.Rename(exe+".old", exe)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// DownloadFile will download a url to a local file. It also ensure that the file is executable.
|
||||
func DownloadFile(url, exe string) error {
|
||||
// Download the url binary to exe path
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
fp, err := os.OpenFile(exe, os.O_WRONLY|os.O_CREATE, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fp.Close()
|
||||
_, err = io.Copy(fp, resp.Body)
|
||||
return err
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
package update
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDownloadLatestRelease(t *testing.T) {
|
||||
// Reset the version to test the latest release
|
||||
Version = "0.0.0"
|
||||
|
||||
// change "exe" to /tmp/test-katenary
|
||||
exe = "/tmp/test-katenary"
|
||||
defer os.Remove(exe)
|
||||
|
||||
// Now call the CheckLatestVersion function
|
||||
version, assets, err := CheckLatestVersion()
|
||||
if err != nil {
|
||||
t.Errorf("Error getting latest version: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println("Version found", version)
|
||||
|
||||
// Touch exe binary
|
||||
f, _ := os.OpenFile(exe, os.O_RDONLY|os.O_CREATE, 0o755)
|
||||
f.Write(nil)
|
||||
f.Close()
|
||||
|
||||
err = DownloadLatestVersion(assets)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlreadyUpToDate(t *testing.T) {
|
||||
Version = "99999.999.99"
|
||||
exe = "/tmp/test-katenary"
|
||||
defer os.Remove(exe)
|
||||
|
||||
// Call the version check
|
||||
version, _, err := CheckLatestVersion()
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("Error: %s", err)
|
||||
}
|
||||
|
||||
t.Log("Version is already the most recent", version)
|
||||
}
|
@@ -9,13 +9,13 @@ type Icon string
|
||||
const (
|
||||
IconSuccess Icon = "✅"
|
||||
IconFailure Icon = "❌"
|
||||
IconWarning Icon = "⚠️'"
|
||||
IconWarning Icon = "❕"
|
||||
IconNote Icon = "📝"
|
||||
IconWorld Icon = "🌐"
|
||||
IconPlug Icon = "🔌"
|
||||
IconPackage Icon = "📦"
|
||||
IconCabinet Icon = "🗄️"
|
||||
IconInfo Icon = "❕"
|
||||
IconInfo Icon = "🔵"
|
||||
IconSecret Icon = "🔒"
|
||||
IconConfig Icon = "🔧"
|
||||
IconDependency Icon = "🔗"
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/mitchellh/go-wordwrap"
|
||||
"github.com/thediveo/netdb"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
Reference in New Issue
Block a user