feat: select runtime delivery builds #56
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var freshConfigPath, freshOrganization, onboardConfigPath, onboardFrom string
|
var freshConfigPath, freshOrganization, onboardConfigPath, onboardFrom string
|
||||||
var onboardAppName, onboardAppRepoURL, onboardImageRepository string
|
var onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy string
|
||||||
var freshCreateOrganization, freshEnableDelivery, freshYes bool
|
var freshCreateOrganization, freshEnableDelivery, freshYes bool
|
||||||
var freshMode string
|
var freshMode string
|
||||||
|
|
||||||
|
|
@ -54,6 +54,7 @@ func init() {
|
||||||
appOnboardCmd.Flags().StringVar(&onboardAppName, "app-name", "", "Application name override")
|
appOnboardCmd.Flags().StringVar(&onboardAppName, "app-name", "", "Application name override")
|
||||||
appOnboardCmd.Flags().StringVar(&onboardAppRepoURL, "app-repo-url", "", "Application repository URL override")
|
appOnboardCmd.Flags().StringVar(&onboardAppRepoURL, "app-repo-url", "", "Application repository URL override")
|
||||||
appOnboardCmd.Flags().StringVar(&onboardImageRepository, "image-repository", "", "OCI image repository override")
|
appOnboardCmd.Flags().StringVar(&onboardImageRepository, "image-repository", "", "OCI image repository override")
|
||||||
|
appOnboardCmd.Flags().StringVar(&onboardBuildStrategy, "build-strategy", "", "Build strategy override: static or runtime")
|
||||||
_ = appOnboardCmd.MarkFlagRequired("config")
|
_ = appOnboardCmd.MarkFlagRequired("config")
|
||||||
_ = appOnboardCmd.MarkFlagRequired("from")
|
_ = appOnboardCmd.MarkFlagRequired("from")
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +88,9 @@ func runAppOnboard(_ *cobra.Command, _ []string) error {
|
||||||
if onboardImageRepository != "" {
|
if onboardImageRepository != "" {
|
||||||
cfg.Delivery.ImageRepository = onboardImageRepository
|
cfg.Delivery.ImageRepository = onboardImageRepository
|
||||||
}
|
}
|
||||||
|
if onboardBuildStrategy != "" {
|
||||||
|
cfg.Delivery.BuildStrategy = onboardBuildStrategy
|
||||||
|
}
|
||||||
cfg, err = resolveAppOnboarding(cfg)
|
cfg, err = resolveAppOnboarding(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,11 @@ func TestBootstrapInitAppliesFluxDefaultsBeforeFreshValidation(t *testing.T) {
|
||||||
func TestAppOnboardValidatesConfigBeforeExternalWork(t *testing.T) {
|
func TestAppOnboardValidatesConfigBeforeExternalWork(t *testing.T) {
|
||||||
originalConfig, originalResolve, originalOnboard := loadAppOnboardConfig, resolveAppOnboarding, onboardApp
|
originalConfig, originalResolve, originalOnboard := loadAppOnboardConfig, resolveAppOnboarding, onboardApp
|
||||||
originalConfigPath, originalFrom := onboardConfigPath, onboardFrom
|
originalConfigPath, originalFrom := onboardConfigPath, onboardFrom
|
||||||
originalName, originalRepo, originalImage := onboardAppName, onboardAppRepoURL, onboardImageRepository
|
originalName, originalRepo, originalImage, originalBuildStrategy := onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
loadAppOnboardConfig, resolveAppOnboarding, onboardApp = originalConfig, originalResolve, originalOnboard
|
loadAppOnboardConfig, resolveAppOnboarding, onboardApp = originalConfig, originalResolve, originalOnboard
|
||||||
onboardConfigPath, onboardFrom = originalConfigPath, originalFrom
|
onboardConfigPath, onboardFrom = originalConfigPath, originalFrom
|
||||||
onboardAppName, onboardAppRepoURL, onboardImageRepository = originalName, originalRepo, originalImage
|
onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy = originalName, originalRepo, originalImage, originalBuildStrategy
|
||||||
})
|
})
|
||||||
loadAppOnboardConfig = func(string) (config.Config, error) { return config.Config{}, nil }
|
loadAppOnboardConfig = func(string) (config.Config, error) { return config.Config{}, nil }
|
||||||
resolveAppOnboarding = func(config.Config) (config.Config, error) { return config.Config{}, errors.New("incomplete delivery") }
|
resolveAppOnboarding = func(config.Config) (config.Config, error) { return config.Config{}, errors.New("incomplete delivery") }
|
||||||
|
|
@ -78,7 +78,7 @@ func TestAppOnboardValidatesConfigBeforeExternalWork(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
onboardConfigPath, onboardFrom = "private.yaml", "app-checkout"
|
onboardConfigPath, onboardFrom = "private.yaml", "app-checkout"
|
||||||
onboardAppName, onboardAppRepoURL, onboardImageRepository = "", "", ""
|
onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy = "", "", "", ""
|
||||||
if err := runAppOnboard(nil, nil); err == nil {
|
if err := runAppOnboard(nil, nil); err == nil {
|
||||||
t.Fatal("onboarding accepted invalid configuration")
|
t.Fatal("onboarding accepted invalid configuration")
|
||||||
}
|
}
|
||||||
|
|
@ -87,25 +87,25 @@ func TestAppOnboardValidatesConfigBeforeExternalWork(t *testing.T) {
|
||||||
func TestAppOnboardPassesOnlyValidatedConfigAndCheckout(t *testing.T) {
|
func TestAppOnboardPassesOnlyValidatedConfigAndCheckout(t *testing.T) {
|
||||||
originalConfig, originalResolve, originalOnboard := loadAppOnboardConfig, resolveAppOnboarding, onboardApp
|
originalConfig, originalResolve, originalOnboard := loadAppOnboardConfig, resolveAppOnboarding, onboardApp
|
||||||
originalConfigPath, originalFrom := onboardConfigPath, onboardFrom
|
originalConfigPath, originalFrom := onboardConfigPath, onboardFrom
|
||||||
originalName, originalRepo, originalImage := onboardAppName, onboardAppRepoURL, onboardImageRepository
|
originalName, originalRepo, originalImage, originalBuildStrategy := onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
loadAppOnboardConfig, resolveAppOnboarding, onboardApp = originalConfig, originalResolve, originalOnboard
|
loadAppOnboardConfig, resolveAppOnboarding, onboardApp = originalConfig, originalResolve, originalOnboard
|
||||||
onboardConfigPath, onboardFrom = originalConfigPath, originalFrom
|
onboardConfigPath, onboardFrom = originalConfigPath, originalFrom
|
||||||
onboardAppName, onboardAppRepoURL, onboardImageRepository = originalName, originalRepo, originalImage
|
onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy = originalName, originalRepo, originalImage, originalBuildStrategy
|
||||||
})
|
})
|
||||||
cfg := config.Config{Delivery: config.DeliveryConfig{AppRepoURL: "https://git.example.test/new-org/app.git", AppRepoRef: "main"}}
|
cfg := config.Config{Delivery: config.DeliveryConfig{AppRepoURL: "https://git.example.test/new-org/app.git", AppRepoRef: "main"}}
|
||||||
loadAppOnboardConfig = func(string) (config.Config, error) { return cfg, nil }
|
loadAppOnboardConfig = func(string) (config.Config, error) { return cfg, nil }
|
||||||
resolveAppOnboarding = func(got config.Config) (config.Config, error) { return got, nil }
|
resolveAppOnboarding = func(got config.Config) (config.Config, error) { return got, nil }
|
||||||
calls := 0
|
calls := 0
|
||||||
onboardApp = func(got config.Config, checkout string) error {
|
onboardApp = func(got config.Config, checkout string) error {
|
||||||
if checkout != "app-checkout" || got.Delivery.AppName != "fixture" || got.Delivery.AppRepoURL != "https://git.example.test/new-org/fixture.git" || got.Delivery.ImageRepository != "registry.example.test/new-org/fixture" {
|
if checkout != "app-checkout" || got.Delivery.AppName != "fixture" || got.Delivery.AppRepoURL != "https://git.example.test/new-org/fixture.git" || got.Delivery.ImageRepository != "registry.example.test/new-org/fixture" || got.Delivery.BuildStrategy != "runtime" {
|
||||||
t.Fatal("onboarding used the wrong checkout or config")
|
t.Fatal("onboarding used the wrong checkout or config")
|
||||||
}
|
}
|
||||||
calls++
|
calls++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
onboardConfigPath, onboardFrom = "private.yaml", "app-checkout"
|
onboardConfigPath, onboardFrom = "private.yaml", "app-checkout"
|
||||||
onboardAppName, onboardAppRepoURL, onboardImageRepository = "fixture", "https://git.example.test/new-org/fixture.git", "registry.example.test/new-org/fixture"
|
onboardAppName, onboardAppRepoURL, onboardImageRepository, onboardBuildStrategy = "fixture", "https://git.example.test/new-org/fixture.git", "registry.example.test/new-org/fixture", "runtime"
|
||||||
if err := runAppOnboard(nil, nil); err != nil || calls != 1 {
|
if err := runAppOnboard(nil, nil); err != nil || calls != 1 {
|
||||||
t.Fatalf("runAppOnboard() = %v, calls = %d", err, calls)
|
t.Fatalf("runAppOnboard() = %v, calls = %d", err, calls)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -635,7 +635,7 @@ spec:
|
||||||
operator: notin
|
operator: notin
|
||||||
values: [closed]
|
values: [closed]
|
||||||
taskRef:
|
taskRef:
|
||||||
name: maidn-node-static-image
|
name: {{ if eq .BuildStrategy "static" }}maidn-node-static-image{{ else }}maidn-node-runtime-image{{ end }}
|
||||||
params:
|
params:
|
||||||
- name: url
|
- name: url
|
||||||
value: {{ quote .AppRepoURL }}
|
value: {{ quote .AppRepoURL }}
|
||||||
|
|
@ -643,10 +643,12 @@ spec:
|
||||||
value: $(params.git-revision)
|
value: $(params.git-revision)
|
||||||
- name: image
|
- name: image
|
||||||
value: $(params.image)
|
value: $(params.image)
|
||||||
|
{{ if eq .BuildStrategy "static" }}
|
||||||
- name: output-directory
|
- name: output-directory
|
||||||
value: {{ quote .BuildOutputDirectory }}
|
value: {{ quote .BuildOutputDirectory }}
|
||||||
- name: build-configuration
|
- name: build-configuration
|
||||||
value: {{ quote .BuildConfiguration }}
|
value: {{ quote .BuildConfiguration }}
|
||||||
|
{{ end }}
|
||||||
- name: update-preview
|
- name: update-preview
|
||||||
runAfter: [build-layer]
|
runAfter: [build-layer]
|
||||||
when:
|
when:
|
||||||
|
|
|
||||||
|
|
@ -624,6 +624,7 @@ type appDeliveryTemplateConfig struct {
|
||||||
AppRepoRef string
|
AppRepoRef string
|
||||||
ProductionBranch string
|
ProductionBranch string
|
||||||
ImageRepository string
|
ImageRepository string
|
||||||
|
BuildStrategy string
|
||||||
BuildOutputDirectory string
|
BuildOutputDirectory string
|
||||||
BuildConfiguration string
|
BuildConfiguration string
|
||||||
ForgejoBaseURL string
|
ForgejoBaseURL string
|
||||||
|
|
@ -693,6 +694,9 @@ func renderAppDelivery(cfg config.Config) ([]byte, error) {
|
||||||
if !deliveryAppName.MatchString(cfg.Delivery.AppName) {
|
if !deliveryAppName.MatchString(cfg.Delivery.AppName) {
|
||||||
return nil, errors.New("delivery appName must be a lowercase DNS label")
|
return nil, errors.New("delivery appName must be a lowercase DNS label")
|
||||||
}
|
}
|
||||||
|
if cfg.Delivery.BuildStrategy != "static" && cfg.Delivery.BuildStrategy != "runtime" {
|
||||||
|
return nil, errors.New("delivery buildStrategy must be static or runtime")
|
||||||
|
}
|
||||||
appRepository, err := deliveryRepository(cfg.Git.BaseURL, cfg.Delivery.AppRepoURL)
|
appRepository, err := deliveryRepository(cfg.Git.BaseURL, cfg.Delivery.AppRepoURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -704,7 +708,7 @@ func renderAppDelivery(cfg config.Config) ([]byte, error) {
|
||||||
values := appDeliveryTemplateConfig{
|
values := appDeliveryTemplateConfig{
|
||||||
AppName: cfg.Delivery.AppName, AppRepository: appRepository, AppRepoURL: cfg.Delivery.AppRepoURL,
|
AppName: cfg.Delivery.AppName, AppRepository: appRepository, AppRepoURL: cfg.Delivery.AppRepoURL,
|
||||||
AppRepoRef: cfg.Delivery.AppRepoRef, ProductionBranch: cfg.Delivery.ProductionBranch, ImageRepository: cfg.Delivery.ImageRepository,
|
AppRepoRef: cfg.Delivery.AppRepoRef, ProductionBranch: cfg.Delivery.ProductionBranch, ImageRepository: cfg.Delivery.ImageRepository,
|
||||||
BuildOutputDirectory: cfg.Delivery.BuildOutputDirectory, BuildConfiguration: cfg.Delivery.BuildConfiguration,
|
BuildStrategy: cfg.Delivery.BuildStrategy, BuildOutputDirectory: cfg.Delivery.BuildOutputDirectory, BuildConfiguration: cfg.Delivery.BuildConfiguration,
|
||||||
ForgejoBaseURL: origin, ForgejoOwner: cfg.Git.Owner, ManifestsURL: forgejo.CloneURL(origin, cfg.Git.Owner, cfg.Flux.ManifestsRepo), ManifestsRepo: cfg.Flux.ManifestsRepo, ManifestsBranch: cfg.Flux.Branch,
|
ForgejoBaseURL: origin, ForgejoOwner: cfg.Git.Owner, ManifestsURL: forgejo.CloneURL(origin, cfg.Git.Owner, cfg.Flux.ManifestsRepo), ManifestsRepo: cfg.Flux.ManifestsRepo, ManifestsBranch: cfg.Flux.Branch,
|
||||||
}
|
}
|
||||||
for name, value := range map[string]string{"appRepository": values.AppRepository, "appRepoUrl": values.AppRepoURL, "appRepoRef": values.AppRepoRef, "productionBranch": values.ProductionBranch, "imageRepository": values.ImageRepository, "buildOutputDirectory": values.BuildOutputDirectory, "buildConfiguration": values.BuildConfiguration, "forgejoBaseUrl": values.ForgejoBaseURL, "forgejoOwner": values.ForgejoOwner, "manifestsUrl": values.ManifestsURL, "manifestsRepo": values.ManifestsRepo, "manifestsBranch": values.ManifestsBranch} {
|
for name, value := range map[string]string{"appRepository": values.AppRepository, "appRepoUrl": values.AppRepoURL, "appRepoRef": values.AppRepoRef, "productionBranch": values.ProductionBranch, "imageRepository": values.ImageRepository, "buildOutputDirectory": values.BuildOutputDirectory, "buildConfiguration": values.BuildConfiguration, "forgejoBaseUrl": values.ForgejoBaseURL, "forgejoOwner": values.ForgejoOwner, "manifestsUrl": values.ManifestsURL, "manifestsRepo": values.ManifestsRepo, "manifestsBranch": values.ManifestsBranch} {
|
||||||
|
|
|
||||||
|
|
@ -112,13 +112,13 @@ func TestGeneratedDeliveryUsesCombinedStaticBuildArtifactContract(t *testing.T)
|
||||||
cfg := config.Config{
|
cfg := config.Config{
|
||||||
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
|
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
|
||||||
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"},
|
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"},
|
||||||
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"},
|
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"},
|
||||||
}
|
}
|
||||||
content, err := renderAppDelivery(cfg)
|
content, err := renderAppDelivery(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for _, expected := range []string{"name: build-layer", "maidn-node-static-image", "name: url\n value: \"https://git.example.test/apps/web-ui.git\"", "name: revision\n value: $(params.git-revision)", "name: image\n value: $(params.image)", "runAfter: [build-layer]", "maidn-preview-orphan-reconciler", "valid_pr_number()", "valid_commit()", "values: [promotion]", "values: [\"production\"]", "cmp -s \"$expected_marker\" \"$marker\"", "values: [closed]"} {
|
for _, expected := range []string{"name: build-layer", "maidn-node-static-image", "name: url\n value: \"https://git.example.test/apps/web-ui.git\"", "name: revision\n value: $(params.git-revision)", "name: image\n value: $(params.image)", "name: output-directory\n value: \"dist/web-ui\"", "name: build-configuration\n value: \"production\"", "runAfter: [build-layer]", "maidn-preview-orphan-reconciler", "valid_pr_number()", "valid_commit()", "values: [promotion]", "values: [\"production\"]", "cmp -s \"$expected_marker\" \"$marker\"", "values: [closed]"} {
|
||||||
if !strings.Contains(string(content), expected) {
|
if !strings.Contains(string(content), expected) {
|
||||||
t.Fatalf("generated delivery does not contain %q", expected)
|
t.Fatalf("generated delivery does not contain %q", expected)
|
||||||
}
|
}
|
||||||
|
|
@ -130,11 +130,33 @@ func TestGeneratedDeliveryUsesCombinedStaticBuildArtifactContract(t *testing.T)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGeneratedDeliveryUsesRuntimeImageWithoutStaticParameters(t *testing.T) {
|
||||||
|
cfg := config.Config{
|
||||||
|
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
|
||||||
|
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"},
|
||||||
|
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "runtime", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"},
|
||||||
|
}
|
||||||
|
content, err := renderAppDelivery(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, expected := range []string{"maidn-node-runtime-image", "name: url\n value: \"https://git.example.test/apps/web-ui.git\"", "name: revision\n value: $(params.git-revision)", "name: image\n value: $(params.image)"} {
|
||||||
|
if !strings.Contains(string(content), expected) {
|
||||||
|
t.Fatalf("generated runtime delivery does not contain %q", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, unexpected := range []string{"maidn-node-static-image", "name: output-directory", "name: build-configuration"} {
|
||||||
|
if strings.Contains(string(content), unexpected) {
|
||||||
|
t.Fatalf("generated runtime delivery contains static-only %q", unexpected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGeneratedDeliveryInitializesStagingAndPromotesByPullRequest(t *testing.T) {
|
func TestGeneratedDeliveryInitializesStagingAndPromotesByPullRequest(t *testing.T) {
|
||||||
cfg := config.Config{
|
cfg := config.Config{
|
||||||
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
|
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
|
||||||
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"},
|
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"},
|
||||||
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildOutputDirectory: "dist", BuildConfiguration: "production"},
|
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist", BuildConfiguration: "production"},
|
||||||
}
|
}
|
||||||
content, err := renderAppDelivery(cfg)
|
content, err := renderAppDelivery(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func onboardingConfig() config.Config {
|
||||||
Flux: config.FluxConfig{Branch: "main", RepoName: "cluster", ManifestsRepo: "manifests", ClusterDomain: "example.test"},
|
Flux: config.FluxConfig{Branch: "main", RepoName: "cluster", ManifestsRepo: "manifests", ClusterDomain: "example.test"},
|
||||||
Delivery: config.DeliveryConfig{
|
Delivery: config.DeliveryConfig{
|
||||||
AppName: "web-ui", AppRepoURL: "https://git.example.test/test-org-2/web-ui.git", AppRepoRef: "main", ProductionBranch: "production",
|
AppName: "web-ui", AppRepoURL: "https://git.example.test/test-org-2/web-ui.git", AppRepoRef: "main", ProductionBranch: "production",
|
||||||
ImageRepository: "registry.example.test/test-org-2/web-ui", BuildOutputDirectory: "dist", BuildConfiguration: "production",
|
ImageRepository: "registry.example.test/test-org-2/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist", BuildConfiguration: "production",
|
||||||
WebhookHostname: "tekton.example.test", WebhookPath: "/",
|
WebhookHostname: "tekton.example.test", WebhookPath: "/",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,9 @@ func validateRepositoryURL(value string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyDefaults(cfg *Config) {
|
func applyDefaults(cfg *Config) {
|
||||||
|
if cfg.Delivery.BuildStrategy == "" {
|
||||||
|
cfg.Delivery.BuildStrategy = "static"
|
||||||
|
}
|
||||||
if cfg.ClusterID == "" {
|
if cfg.ClusterID == "" {
|
||||||
cfg.ClusterID = cfg.Talos.Cluster.Name
|
cfg.ClusterID = cfg.Talos.Cluster.Name
|
||||||
}
|
}
|
||||||
|
|
@ -317,6 +320,9 @@ func applyDefaults(cfg *Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyDeliveryDefaults(cfg *Config) {
|
func applyDeliveryDefaults(cfg *Config) {
|
||||||
|
if cfg.Delivery.BuildStrategy == "" {
|
||||||
|
cfg.Delivery.BuildStrategy = "static"
|
||||||
|
}
|
||||||
if cfg.Delivery.AppRepoRef == "" {
|
if cfg.Delivery.AppRepoRef == "" {
|
||||||
cfg.Delivery.AppRepoRef = cfg.Flux.Branch
|
cfg.Delivery.AppRepoRef = cfg.Flux.Branch
|
||||||
}
|
}
|
||||||
|
|
@ -542,6 +548,9 @@ func ValidateDelivery(cfg Config) error {
|
||||||
if !regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,45}[a-z0-9])?$`).MatchString(cfg.Delivery.AppName) {
|
if !regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,45}[a-z0-9])?$`).MatchString(cfg.Delivery.AppName) {
|
||||||
return errors.New("delivery appName must be a lowercase DNS label of at most 47 characters")
|
return errors.New("delivery appName must be a lowercase DNS label of at most 47 characters")
|
||||||
}
|
}
|
||||||
|
if cfg.Delivery.BuildStrategy != "static" && cfg.Delivery.BuildStrategy != "runtime" {
|
||||||
|
return errors.New("delivery buildStrategy must be static or runtime")
|
||||||
|
}
|
||||||
if cfg.Delivery.ProductionBranch == cfg.Delivery.AppRepoRef || !validDeliveryBranch(cfg.Delivery.ProductionBranch) {
|
if cfg.Delivery.ProductionBranch == cfg.Delivery.AppRepoRef || !validDeliveryBranch(cfg.Delivery.ProductionBranch) {
|
||||||
return errors.New("delivery productionBranch must be a valid branch distinct from appRepoRef")
|
return errors.New("delivery productionBranch must be a valid branch distinct from appRepoRef")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func validConfig(t *testing.T) Config {
|
||||||
Templates: TemplateConfig{TalosRepoURL: "https://git.example.test/talos.git", TalosRepoRef: "main", CICDRepoURL: "https://git.example.test/template.git", CICDRepoRef: "main", ManifestsRepoURL: "https://git.example.test/manifests.git", ManifestsRepoRef: "main"},
|
Templates: TemplateConfig{TalosRepoURL: "https://git.example.test/talos.git", TalosRepoRef: "main", CICDRepoURL: "https://git.example.test/template.git", CICDRepoRef: "main", ManifestsRepoURL: "https://git.example.test/manifests.git", ManifestsRepoRef: "main"},
|
||||||
Cilium: CiliumConfig{TrafficInterface: "eth1", LoadBalancerStart: "192.168.45.19", LoadBalancerEnd: "192.168.45.30"},
|
Cilium: CiliumConfig{TrafficInterface: "eth1", LoadBalancerStart: "192.168.45.19", LoadBalancerEnd: "192.168.45.30"},
|
||||||
DemocraticCSI: DemocraticCSIConfig{TrueNASAPIKey: "api-key", TrueNASHost: "truenas.example.test", TargetPortal: "truenas.example.test:3260", ShareHost: "truenas.example.test", DatasetParentNFS: "pool/kubernetes/nfs/v", DatasetSnapshotsNFS: "pool/kubernetes/nfs/s", AllowedNetworks: "192.168.45.0/24", NameSuffix: "-test", PortalGroup: "1", InitiatorGroup: "1"},
|
DemocraticCSI: DemocraticCSIConfig{TrueNASAPIKey: "api-key", TrueNASHost: "truenas.example.test", TargetPortal: "truenas.example.test:3260", ShareHost: "truenas.example.test", DatasetParentNFS: "pool/kubernetes/nfs/v", DatasetSnapshotsNFS: "pool/kubernetes/nfs/s", AllowedNetworks: "192.168.45.0/24", NameSuffix: "-test", PortalGroup: "1", InitiatorGroup: "1"},
|
||||||
Delivery: DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/test-org/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/test-org/web-ui", BuildOutputDirectory: "dist", BuildConfiguration: "production", WebhookHostname: "tekton.example.test", WebhookPath: "/"},
|
Delivery: DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/test-org/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/test-org/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist", BuildConfiguration: "production", WebhookHostname: "tekton.example.test", WebhookPath: "/"},
|
||||||
Talos: TalosConfig{
|
Talos: TalosConfig{
|
||||||
RepoDirName: "talos", TerraformDir: "terraform", GeneratedDir: "generated", ConfigFileName: "terraform.tfvars",
|
RepoDirName: "talos", TerraformDir: "terraform", GeneratedDir: "generated", ConfigFileName: "terraform.tfvars",
|
||||||
Proxmox: TalosProxmoxConfig{APIURL: "https://proxmox.example.test:8006", APITokenID: "id", APITokenSecret: "secret"},
|
Proxmox: TalosProxmoxConfig{APIURL: "https://proxmox.example.test:8006", APITokenID: "id", APITokenSecret: "secret"},
|
||||||
|
|
@ -64,6 +64,7 @@ func TestResolveDeliveryAppliesDefaultsOnlyForExplicitAppOperations(t *testing.T
|
||||||
cfg.Delivery.AppRepoRef = ""
|
cfg.Delivery.AppRepoRef = ""
|
||||||
cfg.Delivery.BuildOutputDirectory = ""
|
cfg.Delivery.BuildOutputDirectory = ""
|
||||||
cfg.Delivery.BuildConfiguration = ""
|
cfg.Delivery.BuildConfiguration = ""
|
||||||
|
cfg.Delivery.BuildStrategy = ""
|
||||||
cfg.Delivery.WebhookHostname = ""
|
cfg.Delivery.WebhookHostname = ""
|
||||||
cfg.Delivery.WebhookPath = ""
|
cfg.Delivery.WebhookPath = ""
|
||||||
|
|
||||||
|
|
@ -78,11 +79,25 @@ func TestResolveDeliveryAppliesDefaultsOnlyForExplicitAppOperations(t *testing.T
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !delivery.Delivery.Configured() || delivery.Delivery.AppRepoRef != "main" || delivery.Delivery.BuildOutputDirectory != "dist" || delivery.Delivery.BuildConfiguration != "production" || delivery.Delivery.WebhookURL() != "https://tekton.example.test/" {
|
if !delivery.Delivery.Configured() || delivery.Delivery.BuildStrategy != "static" || delivery.Delivery.AppRepoRef != "main" || delivery.Delivery.BuildOutputDirectory != "dist" || delivery.Delivery.BuildConfiguration != "production" || delivery.Delivery.WebhookURL() != "https://tekton.example.test/" {
|
||||||
t.Fatalf("ResolveDelivery() did not apply the complete delivery contract: %#v", delivery.Delivery)
|
t.Fatalf("ResolveDelivery() did not apply the complete delivery contract: %#v", delivery.Delivery)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateDeliveryBuildStrategy(t *testing.T) {
|
||||||
|
cfg := validConfig(t)
|
||||||
|
for _, strategy := range []string{"static", "runtime"} {
|
||||||
|
cfg.Delivery.BuildStrategy = strategy
|
||||||
|
if err := ValidateDelivery(cfg); err != nil {
|
||||||
|
t.Fatalf("ValidateDelivery() rejected %q: %v", strategy, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfg.Delivery.BuildStrategy = "container"
|
||||||
|
if err := ValidateDelivery(cfg); err == nil || !strings.Contains(err.Error(), "buildStrategy") {
|
||||||
|
t.Fatalf("ValidateDelivery() accepted invalid build strategy: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateDeliveryRequiresCompleteConfig(t *testing.T) {
|
func TestValidateDeliveryRequiresCompleteConfig(t *testing.T) {
|
||||||
cfg := validConfig(t)
|
cfg := validConfig(t)
|
||||||
cfg.Delivery.ImageRepository = ""
|
cfg.Delivery.ImageRepository = ""
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ type DeliveryConfig struct {
|
||||||
AppRepoRef string `yaml:"appRepoRef"`
|
AppRepoRef string `yaml:"appRepoRef"`
|
||||||
ProductionBranch string `yaml:"productionBranch"`
|
ProductionBranch string `yaml:"productionBranch"`
|
||||||
ImageRepository string `yaml:"imageRepository"`
|
ImageRepository string `yaml:"imageRepository"`
|
||||||
|
BuildStrategy string `yaml:"buildStrategy"`
|
||||||
BuildOutputDirectory string `yaml:"buildOutputDirectory"`
|
BuildOutputDirectory string `yaml:"buildOutputDirectory"`
|
||||||
BuildConfiguration string `yaml:"buildConfiguration"`
|
BuildConfiguration string `yaml:"buildConfiguration"`
|
||||||
TektonDashboardURL string `yaml:"tektonDashboardUrl,omitempty"`
|
TektonDashboardURL string `yaml:"tektonDashboardUrl,omitempty"`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue