Skip to content

Commit

Permalink
feat: Handle repository aliases
Browse files Browse the repository at this point in the history
Signed-off-by: Allan Jacquet-Cretides <allan.jacquet@qonto.com>
  • Loading branch information
Jumanjii committed Oct 4, 2024
1 parent 445f1c1 commit 2feb5d5
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 27 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
test:
go test -v -cover -race ./...

dev:
go run main.go start -v debug --config-file config/config.yml

start:
go run main.go start --debug
go run main.go start -v debug

lint:
golangci-lint run
Expand Down
1 change: 1 addition & 0 deletions config/_testdata/config-success.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ sources:
- "./internal/app/_testdata/test_chart2/Chart.yaml"
- "./internal/app/_testdata/test_chart3/Chart.yaml"
- "./internal/app/_testdata/test_chart4/Chart.yaml"
- "./internal/app/_testdata/test_chart5/Chart.yaml"
filters:
stabilityDays: 21
skipPrerelease: true
Expand Down
29 changes: 29 additions & 0 deletions config/dev.config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
global:
interval: 10m
aws:
region: us-east-1
sources:
argocdHelm:
- enabled: false
filesystemHelm:
- enabled: true
paths:
- "./internal/app/_testdata/test_chart/Chart.yaml"
- "./internal/app/_testdata/test_chart2/Chart.yaml"
- "./internal/app/_testdata/test_chart3/Chart.yaml"
- "./internal/app/_testdata/test_chart4/Chart.yaml"
- "./internal/app/_testdata/test_chart5/Chart.yaml"
filters:
semver-versions:
remove-pre-release: true
remove-first-major-version: true
recent-versions:
days: 21
repositories-aliases:
"@my-alias": "https://prometheus-community.github.io/helm-charts"
http:
host: 0.0.0.0
port: 10000
write-timeout: 10
read-timeout: 10
read-header-timeout: 10
4 changes: 2 additions & 2 deletions internal/app/_testdata/test_chart4/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
appVersion: v2.3.3
description: A Helm chart for ArgoCD, a declarative, GitOps continuous delivery tool for Kubernetes.
name: argo-cd
description: kube-prometheus-stack collects Kubernetes manifests, Grafana dashboards, and Prometheus rules
name: test-app-5
version: 4.5.8
dependencies:
- name: kube-prometheus-stack
Expand Down
9 changes: 9 additions & 0 deletions internal/app/_testdata/test_chart5/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v2
appVersion: v2.3.3
description: A Helm chart for ArgoCD, a declarative, GitOps continuous delivery tool for Kubernetes.
name: TestApp5
version: 4.5.8
dependencies:
- name: kube-prometheus-stack
version: 60.0.0
repository: '@my-alias'
15 changes: 8 additions & 7 deletions internal/app/sources/argohelm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import (
)

type Config struct {
Enabled bool `yaml:"enabled"`
Name string `yaml:"name"`
ClusterURL string `yaml:"cluster-url"`
ArgoCDNamespace string `yaml:"argocd-namespace" validate:"required"`
GitSecretsNamespace string `yaml:"git-credentials-secrets-namespace" validate:"required"`
GitCredentialsSecretsPattern string `yaml:"git-credentials-secrets-pattern" validate:"required"`
Filters FiltersConfig `yaml:"filters"`
Enabled bool `yaml:"enabled"`
Name string `yaml:"name"`
ClusterURL string `yaml:"cluster-url"`
ArgoCDNamespace string `yaml:"argocd-namespace" validate:"required"`
GitSecretsNamespace string `yaml:"git-credentials-secrets-namespace" validate:"required"`
GitCredentialsSecretsPattern string `yaml:"git-credentials-secrets-pattern" validate:"required"`
Filters FiltersConfig `yaml:"filters"`
RepositoriesAliases map[string]string `yaml:"repositories-aliases"`
}

type FiltersConfig struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/app/sources/argohelm/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ func (s *Source) Load() ([]*soft.Software, error) {
s.log.Warn(fmt.Sprintf("Could not convert argo app %s to software: %s", app.Name, err))
continue
}
err = versions.PopulateTopLevelSoftware(s.s3Api, s.log, topLevelSoftware, app.RepoURL, app.Chart, s.versionFilter)
err = versions.PopulateTopLevelSoftware(s.s3Api, s.log, s.cfg.RepositoriesAliases, topLevelSoftware, app.RepoURL, app.Chart, s.versionFilter)
if err != nil {
s.log.Warn(fmt.Sprintf("Could not populate top level software %s: %s", app.Name, err))
}
if chart != nil {
err = versions.PopulateSoftwareDependencies(s.s3Api, s.log, topLevelSoftware, chart, ArgoHelm, s.versionFilter)
err = versions.PopulateSoftwareDependencies(s.s3Api, s.log, s.cfg.RepositoriesAliases, topLevelSoftware, chart, ArgoHelm, s.versionFilter)
if err != nil {
s.log.Error(fmt.Sprintf("Could not load %s chart as software, error: %s", chart.Name(), err))
continue
Expand Down
11 changes: 6 additions & 5 deletions internal/app/sources/deployments/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
)

type Config struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
LabelSelector map[string]string `yaml:"label-selector"`
Registries map[string]registry.Config `yaml:"registries"`
Filters filters.Config `yaml:"filters"`
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
LabelSelector map[string]string `yaml:"label-selector"`
Registries map[string]registry.Config `yaml:"registries"`
Filters filters.Config `yaml:"filters"`
RepositoriesAliases map[string]string `yaml:"repositories-aliases"`
}
7 changes: 4 additions & 3 deletions internal/app/sources/filesystemhelm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import (
)

type Config struct {
Enabled bool `yaml:"enabled"`
Paths []string `yaml:"paths" validate:"dive,file"`
Filters filters.Config `yaml:"filters"`
Enabled bool `yaml:"enabled"`
Paths []string `yaml:"paths" validate:"dive,file"`
Filters filters.Config `yaml:"filters"`
RepositoriesAliases map[string]string `yaml:"repositories-aliases"`
}
2 changes: 1 addition & 1 deletion internal/app/sources/filesystemhelm/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (s *Source) Load() ([]*soft.Software, error) {
Type: FileSystemHelm,
}

err := versions.PopulateSoftwareDependencies(s.s3Api, s.log, topLevelSoftware, &chart, FileSystemHelm, s.filter)
err := versions.PopulateSoftwareDependencies(s.s3Api, s.log, s.cfg.RepositoriesAliases, topLevelSoftware, &chart, FileSystemHelm, s.filter)
if err != nil {
s.log.Error(fmt.Sprintf("Could not load %s chart as software, error: %s", chart.Name(), err))
continue
Expand Down
7 changes: 6 additions & 1 deletion internal/app/sources/helm/versions/repo_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ func getRepoBackendType(repoUrl string) (RepoBackendType, error) {
return "", fmt.Errorf("could not determine RepoBackendType for url %s", repoUrl)
}

func buildRepoBackend(repoURL string, chartName string, log *slog.Logger, s3Api aws.S3Api) (RepoBackend, error) {
func buildRepoBackend(repoAliases map[string]string, repoURL string, chartName string, log *slog.Logger, s3Api aws.S3Api) (RepoBackend, error) {
if repoAliases != nil && repoAliases[repoURL] != "" {
log.Debug(fmt.Sprintf("Repo URL %s resolved to %s", repoURL, repoAliases[repoURL]))
repoURL = repoAliases[repoURL]
}

repoType, err := getRepoBackendType(repoURL)
if err != nil {
return nil, err
Expand Down
97 changes: 96 additions & 1 deletion internal/app/sources/helm/versions/repo_backend_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package versions

import "testing"
import (
"log/slog"
"testing"

"github.com/qonto/upgrade-manager/internal/infra/aws"
"github.com/stretchr/testify/assert"
)

func TestGetRepoBackendType(t *testing.T) {
testCases := map[string]RepoBackendType{
Expand All @@ -24,3 +30,92 @@ func TestGetRepoBackendType(t *testing.T) {
}
}
}

func TestBuildRepoBackend(t *testing.T) {
logger := slog.Default()
mockS3Api := new(aws.S3Mock)

tests := []struct {
name string
repoAliases map[string]string
repoURL string
chartName string
expectedType interface{}
expectError bool
}{
{
name: "HelmRepo",
repoAliases: nil,
repoURL: "https://charts.helm.sh/stable",
chartName: "mysql",
expectedType: &HelmRepoBackend{},
expectError: false,
},
{
name: "S3HelmRepo",
repoAliases: nil,
repoURL: "s3://my-bucket/charts",
chartName: "my-chart",
expectedType: &S3HelmRepoBackend{},
expectError: false,
},
{
name: "GitRepo",
repoAliases: nil,
repoURL: "https://github.com/user/repo.git",
chartName: "my-chart",
expectedType: nil,
expectError: false,
},
{
name: "Invalid URL",
repoAliases: nil,
repoURL: "invalid://url",
chartName: "my-chart",
expectedType: nil,
expectError: true,
},
{
name: "With Repo Alias",
repoAliases: map[string]string{"alias": "https://charts.helm.sh/stable"},
repoURL: "alias",
chartName: "mysql",
expectedType: &HelmRepoBackend{},
expectError: false,
},
{
name: "With Repo Alias targetting a S3 bucket",

Check failure on line 87 in internal/app/sources/helm/versions/repo_backend_test.go

View workflow job for this annotation

GitHub Actions / lint

`targetting` is a misspelling of `targeting` (misspell)
repoAliases: map[string]string{"alias": "s3://my-bucket/charts"},
repoURL: "alias",
chartName: "my-chart",
expectedType: &S3HelmRepoBackend{},
expectError: false,
},
{
name: "With Repo Alias targetting a Git repo",

Check failure on line 95 in internal/app/sources/helm/versions/repo_backend_test.go

View workflow job for this annotation

GitHub Actions / lint

`targetting` is a misspelling of `targeting` (misspell)
repoAliases: map[string]string{"alias": "https://github.com/user/repo.git"},
repoURL: "alias",
chartName: "my-chart",
expectedType: nil,
expectError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
backend, err := buildRepoBackend(tt.repoAliases, tt.repoURL, tt.chartName, logger, mockS3Api)

if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}

if tt.expectedType == nil {
assert.Nil(t, backend)
} else {
assert.IsType(t, tt.expectedType, backend)
}
})
}
}
8 changes: 4 additions & 4 deletions internal/app/sources/helm/versions/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import (
"helm.sh/helm/v3/pkg/repo"
)

func PopulateTopLevelSoftware(s3Api aws.S3Api, log *slog.Logger, topLevelSoftware *soft.Software, repoURL string, chartName string, filter filters.Filter) error {
func PopulateTopLevelSoftware(s3Api aws.S3Api, log *slog.Logger, repoAliases map[string]string, topLevelSoftware *soft.Software, repoURL string, chartName string, filter filters.Filter) error {
log.Debug(fmt.Sprintf("Populate top level software for chart %s repo backend %s", chartName, repoURL))
repoBackend, err := buildRepoBackend(repoURL, chartName, log, s3Api)
repoBackend, err := buildRepoBackend(repoAliases, repoURL, chartName, log, s3Api)
if err != nil {
return err
}
Expand All @@ -34,7 +34,7 @@ func PopulateTopLevelSoftware(s3Api aws.S3Api, log *slog.Logger, topLevelSoftwar
return nil
}

func PopulateSoftwareDependencies(s3Api aws.S3Api, log *slog.Logger, topLevelSoftware *soft.Software, chart *chart.Chart, st soft.SoftwareType, filter filters.Filter) error {
func PopulateSoftwareDependencies(s3Api aws.S3Api, log *slog.Logger, repoAliases map[string]string, topLevelSoftware *soft.Software, chart *chart.Chart, st soft.SoftwareType, filter filters.Filter) error {
softwareDependencies := []*soft.Software{}
for _, dependency := range chart.Metadata.Dependencies {
var depName string
Expand All @@ -52,7 +52,7 @@ func PopulateSoftwareDependencies(s3Api aws.S3Api, log *slog.Logger, topLevelSof
}
log.Debug(fmt.Sprintf("Populate dependency software for dep %s repo backend %s", depName, dependency.Repository))

depRepoBackend, err := buildRepoBackend(dependency.Repository, dependency.Name, log, s3Api)
depRepoBackend, err := buildRepoBackend(repoAliases, dependency.Repository, dependency.Name, log, s3Api)
if err != nil {
return err
}
Expand Down

0 comments on commit 2feb5d5

Please sign in to comment.