fix: allow platform-only reconcile
This commit is contained in:
parent
ba79613064
commit
dbd370b20d
|
|
@ -27,6 +27,8 @@ var bootstrapMergeBootstrapPR bool
|
|||
var bootstrapManageNetworkBridges bool
|
||||
|
||||
var upsertOperationalSecret = bootstrap.UpsertOperationalSecret
|
||||
var loadPublishAppConfig = config.Load
|
||||
var ensurePublishAppCheckoutClean = forgejo.EnsureCleanCheckout
|
||||
|
||||
var bootstrapCmd = &cobra.Command{
|
||||
Use: "bootstrap",
|
||||
|
|
@ -63,6 +65,9 @@ func runBootstrap(cmd *cobra.Command, args []string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := config.ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bootstrap.EnsureTemplateRevisions(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -76,6 +81,9 @@ func runBootstrap(cmd *cobra.Command, args []string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := config.ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
authorization, err := bootstrap.NewWebhookAuthorization()
|
||||
if err != nil {
|
||||
return fmt.Errorf("generate Forgejo webhook authorization: %w", err)
|
||||
|
|
@ -118,11 +126,14 @@ func runBootstrap(cmd *cobra.Command, args []string) error {
|
|||
if bootstrapConfigPath == "" {
|
||||
return fmt.Errorf("--publish-app-from requires --config")
|
||||
}
|
||||
cfg, err = config.Load(bootstrapConfigPath)
|
||||
cfg, err = loadPublishAppConfig(bootstrapConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := forgejo.EnsureCleanCheckout(bootstrapPublishAppFrom); err != nil {
|
||||
if err := config.ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensurePublishAppCheckoutClean(bootstrapPublishAppFrom); err != nil {
|
||||
return err
|
||||
}
|
||||
origin, err := forgejo.CheckoutOrigin(bootstrapPublishAppFrom)
|
||||
|
|
@ -180,6 +191,9 @@ func runBootstrap(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
cfg, err = config.Resolve(cfg)
|
||||
}
|
||||
if err == nil && bootstrapPromptOperationalSecrets {
|
||||
err = config.ValidateDelivery(cfg)
|
||||
}
|
||||
if err == nil && bootstrapPromptOperationalSecrets {
|
||||
var secrets map[string]map[string]string
|
||||
secrets, err = ui.PromptOperationalSecrets(cfg)
|
||||
|
|
@ -221,6 +235,9 @@ func runBootstrap(cmd *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
if bootstrapRegisterWebhook {
|
||||
if err := config.ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := seedForgejoOperationalCredentials(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,31 @@ func TestCreateForgejoRegistryTokenRequiresConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPublishAppRequiresDeliveryConfigBeforeCheckout(t *testing.T) {
|
||||
originalConfigPath, originalPublish := bootstrapConfigPath, bootstrapPublishAppFrom
|
||||
originalLoad, originalClean := loadPublishAppConfig, ensurePublishAppCheckoutClean
|
||||
t.Cleanup(func() {
|
||||
bootstrapConfigPath = originalConfigPath
|
||||
bootstrapPublishAppFrom = originalPublish
|
||||
loadPublishAppConfig = originalLoad
|
||||
ensurePublishAppCheckoutClean = originalClean
|
||||
})
|
||||
bootstrapConfigPath = "test-config.yaml"
|
||||
bootstrapPublishAppFrom = "app-checkout"
|
||||
loadPublishAppConfig = func(string) (config.Config, error) {
|
||||
return config.Config{Git: config.GitConfig{BaseURL: "https://git.example.test"}}, nil
|
||||
}
|
||||
ensurePublishAppCheckoutClean = func(string) error {
|
||||
t.Fatal("publish inspected the checkout before validating delivery config")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := runBootstrap(nil, nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "delivery appName") {
|
||||
t.Fatalf("runBootstrap() error = %v, want incomplete delivery error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedForgejoOperationalCredentialsUsesEncryptedUpsertBoundary(t *testing.T) {
|
||||
original := upsertOperationalSecret
|
||||
t.Cleanup(func() { upsertOperationalSecret = original })
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ var webhookTargetPollInterval = 2 * time.Second
|
|||
|
||||
var templateBaseComponents = []string{"snapshot-crds", "democratic-csi", "cert-manager", "cluster-issuers", "gateway-api", "gateway", "monitoring", "openbao", "external-secrets", "cnpg", "cloudflare-tunnel", "external-dns", "tekton", "tekton-triggers"}
|
||||
|
||||
var deliveryTemplateBaseComponents = map[string]bool{"gateway": true, "tekton": true, "tekton-triggers": true}
|
||||
|
||||
var generatedTemplateFiles = map[string]map[string]bool{
|
||||
"democratic-csi": {"secret.sops.yaml": true},
|
||||
"openbao": {"unseal.sops.yaml": true},
|
||||
|
|
@ -120,6 +122,12 @@ func (r Runner) Run() error {
|
|||
return err
|
||||
}
|
||||
r.Config = resolved
|
||||
deliveryConfigured := r.Config.Delivery.Configured()
|
||||
if r.RegisterWebhook || r.Config.Talos.AutoBootstrapFlux {
|
||||
if err := config.ValidateDelivery(r.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := preflight(r.Config); err != nil {
|
||||
return fmt.Errorf("preflight: %w", err)
|
||||
}
|
||||
|
|
@ -180,16 +188,23 @@ func (r Runner) Run() error {
|
|||
},
|
||||
func(dir string) error {
|
||||
clusterDir := filepath.Join(dir, strings.TrimPrefix(r.Config.Flux.ClusterPath, "./"))
|
||||
if deliveryConfigured {
|
||||
if err := copyDir(filepath.Join(cicdTemplateDir, "base"), filepath.Join(dir, "base"), false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyTemplateBaseComponents(cicdTemplateDir, dir); err != nil {
|
||||
} else if err := copyDirExcept(filepath.Join(cicdTemplateDir, "base"), filepath.Join(dir, "base"), false, deliveryTemplateBaseComponents); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyTemplateBaseComponents(cicdTemplateDir, dir, deliveryConfigured); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copyClusterTemplate(filepath.Join(cicdTemplateDir, "clusters", "template"), clusterDir); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range []string{"external-secrets", "cnpg", "cloudflare-tunnel", "external-dns", "monitoring", "tekton"} {
|
||||
if !deliveryConfigured && name == "tekton" {
|
||||
continue
|
||||
}
|
||||
content, err := os.ReadFile(filepath.Join(cicdTemplateDir, "clusters", "template", name+"-kustomization.yaml"))
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -208,9 +223,11 @@ func (r Runner) Run() error {
|
|||
if err := copyAndRenderCiliumBases(cicdTemplateDir, dir, r.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
if deliveryConfigured {
|
||||
if err := copyAndRenderDeliveryBases(cicdTemplateDir, dir, r.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writeDemocraticCSISecret(filepath.Join(dir, "base", "democratic-csi", "secret.sops.yaml"), r.Config.DemocraticCSI, r.Config.SOPS.AgeKeyPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -221,7 +238,7 @@ func (r Runner) Run() error {
|
|||
if err := ensureOpenBaoUnsealKustomization(filepath.Join(openbaoDir, "kustomization.yaml")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensureClusterKustomizations(clusterDir); err != nil {
|
||||
if err := ensureClusterKustomizations(clusterDir, deliveryConfigured); err != nil {
|
||||
return err
|
||||
}
|
||||
return ghrepo.WriteFluxStructure(dir, r.Config.Flux.RepoName, r.Config.Flux.ClusterPath, fluxConfig)
|
||||
|
|
@ -381,6 +398,9 @@ func renderDeliveryConfig(dir string, cfg config.Config) error {
|
|||
}
|
||||
|
||||
func copyAndRenderDeliveryBases(templateDir, repoDir string, cfg config.Config) error {
|
||||
if err := config.ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
bases := []string{"gateway", "tekton", "tekton-triggers"}
|
||||
for _, base := range bases {
|
||||
baseDir := filepath.Join(repoDir, "base", base)
|
||||
|
|
@ -464,6 +484,9 @@ var deliveryAppName = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`)
|
|||
|
||||
// GenerateAppDelivery writes the source-owned Tekton delivery contract for an app checkout.
|
||||
func GenerateAppDelivery(dir string, cfg config.Config) error {
|
||||
if err := config.ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
content, err := renderAppDelivery(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -964,7 +987,7 @@ func waitForWebhookAuthorization(dir, authorization string) error {
|
|||
}
|
||||
}
|
||||
|
||||
func ensureClusterKustomizations(clusterDir string) error {
|
||||
func ensureClusterKustomizations(clusterDir string, includeDelivery bool) error {
|
||||
path := filepath.Join(clusterDir, "kustomization.yaml")
|
||||
content, err := os.ReadFile(path)
|
||||
if os.IsNotExist(err) {
|
||||
|
|
@ -978,6 +1001,9 @@ func ensureClusterKustomizations(clusterDir string) error {
|
|||
updated := string(content)
|
||||
updated = strings.ReplaceAll(updated, " - bootstrap-secrets.sops.yaml\n", "")
|
||||
for _, resource := range requiredClusterKustomizations {
|
||||
if !includeDelivery && (resource == "gateway-kustomization.yaml" || resource == "tekton-kustomization.yaml" || resource == "tekton-triggers-kustomization.yaml") {
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(updated, resource) {
|
||||
updated += " - " + resource + "\n"
|
||||
}
|
||||
|
|
@ -988,8 +1014,11 @@ func ensureClusterKustomizations(clusterDir string) error {
|
|||
return os.WriteFile(path, []byte(updated), 0644)
|
||||
}
|
||||
|
||||
func copyTemplateBaseComponents(templateDir, repoDir string) error {
|
||||
func copyTemplateBaseComponents(templateDir, repoDir string, includeDelivery bool) error {
|
||||
for _, component := range templateBaseComponents {
|
||||
if !includeDelivery && deliveryTemplateBaseComponents[component] {
|
||||
continue
|
||||
}
|
||||
if err := copyDirExcept(filepath.Join(templateDir, "base", component), filepath.Join(repoDir, "base", component), true, generatedTemplateFiles[component]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func TestGeneratedDeliveryIsGenericAndUsesSafePreviewCleanupContract(t *testing.
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, expected := range []string{"maidn-node-static-image", "maidn-preview-orphan-reconciler", "valid_pr_number()", "valid_commit()", "values: [promotion]", "values: [\"production\"]", "environment\n value: production", "cmp -s \"$expected_marker\" \"$marker\"", "values: [closed]"} {
|
||||
for _, expected := range []string{"maidn-node-static-image", "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) {
|
||||
t.Fatalf("generated delivery does not contain %q", expected)
|
||||
}
|
||||
|
|
@ -78,6 +78,17 @@ func TestGeneratedDeliveryIsGenericAndUsesSafePreviewCleanupContract(t *testing.
|
|||
}
|
||||
}
|
||||
|
||||
func TestGenerateAppDeliveryRequiresCompleteConfig(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
err := GenerateAppDelivery(dir, config.Config{Git: config.GitConfig{BaseURL: "https://git.example.test"}})
|
||||
if err == nil || !strings.Contains(err.Error(), "delivery appName") {
|
||||
t.Fatalf("GenerateAppDelivery() error = %v, want incomplete delivery error", err)
|
||||
}
|
||||
if _, statErr := os.Stat(filepath.Join(dir, ".tekton")); !os.IsNotExist(statErr) {
|
||||
t.Fatal("GenerateAppDelivery() wrote delivery files before rejecting incomplete config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWritePreviewDeliveryConfigIsTrustedAndNonSecret(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(dir, "kustomization.yaml"), []byte("resources:\n"), 0644); err != nil {
|
||||
|
|
@ -141,7 +152,7 @@ func TestCopyAndRenderDeliveryBasesOverwritesExistingMigrationOutput(t *testing.
|
|||
cfg := config.Config{
|
||||
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "user-org"},
|
||||
Flux: config.FluxConfig{TektonCatalogRepo: "my-tekton-catalog", ManifestsRepo: "manifests", Branch: "main"},
|
||||
Delivery: config.DeliveryConfig{AppName: "demo", AppRepoURL: "https://git.example.test/demo.git", WebhookHostname: "tekton.example.test", WebhookPath: "/hooks/forgejo"},
|
||||
Delivery: config.DeliveryConfig{AppName: "demo", AppRepoURL: "https://git.example.test/demo.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/demo", BuildOutputDirectory: "dist", BuildConfiguration: "production", WebhookHostname: "tekton.example.test", WebhookPath: "/hooks/forgejo"},
|
||||
Templates: config.TemplateConfig{TektonCatalogRepoRef: "release"},
|
||||
}
|
||||
if err := copyAndRenderDeliveryBases(templateDir, repoDir, cfg); err != nil {
|
||||
|
|
@ -209,7 +220,7 @@ func TestCopyTemplateBaseComponentsRefreshesCNPGAndPreservesGeneratedSecrets(t *
|
|||
}
|
||||
}
|
||||
|
||||
if err := copyTemplateBaseComponents(templateDir, repoDir); err != nil {
|
||||
if err := copyTemplateBaseComponents(templateDir, repoDir, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
content, err := os.ReadFile(cnpgDestination)
|
||||
|
|
@ -625,7 +636,7 @@ func TestEnsureClusterKustomizationsUsesTemplateExternalSecretsResource(t *testi
|
|||
if err := os.WriteFile(path, []byte("resources:\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ensureClusterKustomizations(dir); err != nil {
|
||||
if err := ensureClusterKustomizations(dir, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
content, err := os.ReadFile(path)
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ func applyDefaults(cfg *Config) {
|
|||
if cfg.DemocraticCSI.InitiatorGroup == "" {
|
||||
cfg.DemocraticCSI.InitiatorGroup = "1"
|
||||
}
|
||||
if cfg.Delivery.Configured() {
|
||||
if cfg.Delivery.AppRepoRef == "" {
|
||||
cfg.Delivery.AppRepoRef = cfg.Flux.Branch
|
||||
}
|
||||
|
|
@ -173,6 +174,7 @@ func applyDefaults(cfg *Config) {
|
|||
if cfg.Delivery.WebhookPath == "" {
|
||||
cfg.Delivery.WebhookPath = "/"
|
||||
}
|
||||
}
|
||||
if cfg.Talos.RepoDirName == "" {
|
||||
cfg.Talos.RepoDirName = "maidn-talos-proxmox"
|
||||
}
|
||||
|
|
@ -245,23 +247,10 @@ func Validate(cfg Config) error {
|
|||
if len(cfg.Flux.ClusterDomain) > 253 || !regexp.MustCompile(`^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?(\.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*$`).MatchString(cfg.Flux.ClusterDomain) {
|
||||
return errors.New("flux clusterDomain must be a lowercase DNS subdomain")
|
||||
}
|
||||
if cfg.Delivery.AppName == "" || cfg.Delivery.AppRepoURL == "" || cfg.Delivery.AppRepoRef == "" || cfg.Delivery.ProductionBranch == "" || cfg.Delivery.ImageRepository == "" || cfg.Delivery.BuildOutputDirectory == "" || cfg.Delivery.BuildConfiguration == "" || cfg.Delivery.WebhookHostname == "" || cfg.Delivery.WebhookPath == "" {
|
||||
return errors.New("delivery appName, appRepoUrl, appRepoRef, productionBranch, imageRepository, buildOutputDirectory, buildConfiguration, webhookHostname, and webhookPath are required")
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`).MatchString(cfg.Delivery.AppName) {
|
||||
return errors.New("delivery appName must be a lowercase DNS label")
|
||||
}
|
||||
if cfg.Delivery.ProductionBranch == cfg.Delivery.AppRepoRef || !validDeliveryBranch(cfg.Delivery.ProductionBranch) {
|
||||
return errors.New("delivery productionBranch must be a valid branch distinct from appRepoRef")
|
||||
}
|
||||
if RedactURL(cfg.Delivery.AppRepoURL) != cfg.Delivery.AppRepoURL {
|
||||
return errors.New("delivery appRepoUrl must not contain credentials, a query, or a fragment")
|
||||
}
|
||||
if err := validateDeliveryRepositoryOrigin(cfg.Git.BaseURL, cfg.Delivery.AppRepoURL); err != nil {
|
||||
if cfg.Delivery.Configured() {
|
||||
if err := ValidateDelivery(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.ContainsAny(cfg.Delivery.WebhookHostname, "/:@?#") || !strings.HasPrefix(cfg.Delivery.WebhookPath, "/") || strings.ContainsAny(cfg.Delivery.WebhookPath, "?#") {
|
||||
return errors.New("delivery webhookHostname must be a hostname and webhookPath must be an absolute path")
|
||||
}
|
||||
if cfg.Templates.TalosRepoURL == "" || cfg.Templates.TalosRepoRef == "" || cfg.Templates.CICDRepoURL == "" || cfg.Templates.CICDRepoRef == "" || cfg.Templates.ManifestsRepoURL == "" || cfg.Templates.ManifestsRepoRef == "" || cfg.Templates.TektonCatalogRepoURL == "" || cfg.Templates.TektonCatalogRepoRef == "" {
|
||||
return errors.New("all template repository URLs and refs are required")
|
||||
|
|
@ -384,6 +373,29 @@ func Validate(cfg Config) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateDelivery requires the complete app-delivery contract before rendering or publishing it.
|
||||
func ValidateDelivery(cfg Config) error {
|
||||
if cfg.Delivery.AppName == "" || cfg.Delivery.AppRepoURL == "" || cfg.Delivery.AppRepoRef == "" || cfg.Delivery.ProductionBranch == "" || cfg.Delivery.ImageRepository == "" || cfg.Delivery.BuildOutputDirectory == "" || cfg.Delivery.BuildConfiguration == "" || cfg.Delivery.WebhookHostname == "" || cfg.Delivery.WebhookPath == "" {
|
||||
return errors.New("delivery appName, appRepoUrl, appRepoRef, productionBranch, imageRepository, buildOutputDirectory, buildConfiguration, webhookHostname, and webhookPath are required")
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`).MatchString(cfg.Delivery.AppName) {
|
||||
return errors.New("delivery appName must be a lowercase DNS label")
|
||||
}
|
||||
if cfg.Delivery.ProductionBranch == cfg.Delivery.AppRepoRef || !validDeliveryBranch(cfg.Delivery.ProductionBranch) {
|
||||
return errors.New("delivery productionBranch must be a valid branch distinct from appRepoRef")
|
||||
}
|
||||
if RedactURL(cfg.Delivery.AppRepoURL) != cfg.Delivery.AppRepoURL {
|
||||
return errors.New("delivery appRepoUrl must not contain credentials, a query, or a fragment")
|
||||
}
|
||||
if err := validateDeliveryRepositoryOrigin(cfg.Git.BaseURL, cfg.Delivery.AppRepoURL); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.ContainsAny(cfg.Delivery.WebhookHostname, "/:@?#") || !strings.HasPrefix(cfg.Delivery.WebhookPath, "/") || strings.ContainsAny(cfg.Delivery.WebhookPath, "?#") {
|
||||
return errors.New("delivery webhookHostname must be a hostname and webhookPath must be an absolute path")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateDeliveryRepositoryOrigin(baseURL, repositoryURL string) error {
|
||||
base, err := url.Parse(baseURL)
|
||||
if err != nil || base.Scheme != "https" || base.Host == "" || base.User != nil || base.RawPath != "" || base.RawQuery != "" || base.Fragment != "" || strings.Trim(base.Path, "/") != "" {
|
||||
|
|
|
|||
|
|
@ -28,13 +28,31 @@ func validConfig(t *testing.T) Config {
|
|||
}
|
||||
}
|
||||
|
||||
func TestResolveDoesNotInventAnApplication(t *testing.T) {
|
||||
func TestResolveAcceptsPlatformOnlyConfig(t *testing.T) {
|
||||
cfg := validConfig(t)
|
||||
cfg.Delivery.AppName = ""
|
||||
cfg.Delivery.AppRepoURL = ""
|
||||
cfg.Delivery.AppRepoRef = ""
|
||||
cfg.Delivery.ProductionBranch = ""
|
||||
cfg.Delivery.ImageRepository = ""
|
||||
if _, err := Resolve(cfg); err == nil {
|
||||
t.Fatal("Resolve() accepted a configuration without an explicit application")
|
||||
cfg.Delivery.BuildOutputDirectory = ""
|
||||
cfg.Delivery.BuildConfiguration = ""
|
||||
cfg.Delivery.WebhookHostname = ""
|
||||
cfg.Delivery.WebhookPath = ""
|
||||
resolved, err := Resolve(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve() rejected platform-only config: %v", err)
|
||||
}
|
||||
if resolved.Delivery.Configured() {
|
||||
t.Fatal("Resolve() invented delivery settings for a platform-only config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDeliveryRequiresCompleteConfig(t *testing.T) {
|
||||
cfg := validConfig(t)
|
||||
cfg.Delivery.ImageRepository = ""
|
||||
if err := ValidateDelivery(cfg); err == nil || !strings.Contains(err.Error(), "imageRepository") {
|
||||
t.Fatalf("ValidateDelivery() error = %v, want incomplete delivery error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ type DeliveryConfig struct {
|
|||
WebhookPath string `yaml:"webhookPath"`
|
||||
}
|
||||
|
||||
// Configured reports whether the configuration contains any app-delivery setting.
|
||||
func (c DeliveryConfig) Configured() bool {
|
||||
return c.AppName != "" || c.AppRepoURL != "" || c.AppRepoRef != "" || c.ProductionBranch != "" || c.ImageRepository != "" || c.BuildOutputDirectory != "" || c.BuildConfiguration != "" || c.WebhookHostname != "" || c.WebhookPath != ""
|
||||
}
|
||||
|
||||
func (c DeliveryConfig) WebhookURL() string {
|
||||
return (&url.URL{Scheme: "https", Host: c.WebhookHostname, Path: c.WebhookPath}).String()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue