Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ func run(cfg *Config) error {
redirectRevisions,
cfg.Debug,
cfg.FailOnDuplicateGeneratedApplications,
cfg.SkipAppSetGenerationErrors,
appSelectionOptions,
)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions cmd/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ var (
DefaultOutputBranchManifests = false
DefaultTraverseAppOfApps = false
DefaultFailOnDuplicateGeneratedApplications = false
DefaultSkipAppSetGenerationErrors = false
)

// RawOptions holds the raw CLI/env inputs - used only for parsing
Expand Down Expand Up @@ -136,6 +137,7 @@ type RawOptions struct {
OutputBranchManifests bool `mapstructure:"output-branch-manifests"`
TraverseAppOfApps bool `mapstructure:"traverse-app-of-apps"`
FailOnDuplicateGeneratedApplications bool `mapstructure:"fail-on-duplicate-generated-applications"`
SkipAppSetGenerationErrors bool `mapstructure:"skip-appset-generation-errors"`
}

// Config is the final, validated, ready-to-use configuration
Expand Down Expand Up @@ -181,6 +183,7 @@ type Config struct {
OutputBranchManifests bool
TraverseAppOfApps bool
FailOnDuplicateGeneratedApplications bool
SkipAppSetGenerationErrors bool

// Parsed/processed fields - no "parsed" prefix needed
FileRegex *regexp.Regexp
Expand Down Expand Up @@ -278,6 +281,7 @@ func Parse() *Config {
viper.SetDefault("output-branch-manifests", DefaultOutputBranchManifests)
viper.SetDefault("traverse-app-of-apps", DefaultTraverseAppOfApps)
viper.SetDefault("fail-on-duplicate-generated-applications", DefaultFailOnDuplicateGeneratedApplications)
viper.SetDefault("skip-appset-generation-errors", DefaultSkipAppSetGenerationErrors)

// Basic flags
rootCmd.Flags().BoolP("debug", "d", false, "Activate debug mode")
Expand Down Expand Up @@ -338,6 +342,7 @@ func Parse() *Config {
rootCmd.Flags().Bool("output-branch-manifests", DefaultOutputBranchManifests, "Write all application manifests per branch to a single file (output/base-branch.yaml and output/target-branch.yaml)")
rootCmd.Flags().Bool("traverse-app-of-apps", DefaultTraverseAppOfApps, "Recursively render child Applications discovered in rendered manifests (app-of-apps pattern). Only supported with --render-method=repo-server-api")
rootCmd.Flags().Bool("fail-on-duplicate-generated-applications", DefaultFailOnDuplicateGeneratedApplications, "Fail when a single ApplicationSet generates multiple Applications with the same name")
rootCmd.Flags().Bool("skip-appset-generation-errors", DefaultSkipAppSetGenerationErrors, "Skip ApplicationSets that fail to generate (log a warning and continue) instead of aborting the whole run. Useful for ApplicationSets whose generators need cluster secrets or live data unavailable in the ephemeral cluster (e.g. pullRequest/scmProvider generators)")

// Check if version flag was specified directly
for _, arg := range os.Args[1:] {
Expand Down Expand Up @@ -427,6 +432,7 @@ func (o *RawOptions) ToConfig() (*Config, error) {
OutputBranchManifests: o.OutputBranchManifests,
TraverseAppOfApps: o.TraverseAppOfApps,
FailOnDuplicateGeneratedApplications: o.FailOnDuplicateGeneratedApplications,
SkipAppSetGenerationErrors: o.SkipAppSetGenerationErrors,
}

var err error
Expand Down Expand Up @@ -783,4 +789,7 @@ func (o *Config) LogConfig() {
if o.FailOnDuplicateGeneratedApplications {
log.Info().Msgf("✨ - fail-on-duplicate-generated-applications: %t", o.FailOnDuplicateGeneratedApplications)
}
if o.SkipAppSetGenerationErrors {
log.Info().Msgf("✨ - skip-appset-generation-errors: %t", o.SkipAppSetGenerationErrors)
}
}
1 change: 1 addition & 0 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ argocd-diff-preview [FLAGS] [OPTIONS] (--repo <repo> | --repo-regex <regex>) --t
| `--ignore-invalid-watch-pattern` | `IGNORE_INVALID_WATCH_PATTERN` | `false` | Ignore invalid watch-pattern Regex on Applications |
| `--keep-cluster-alive` | `KEEP_CLUSTER_ALIVE` | `false` | Keep cluster alive after the tool finishes |
| `--fail-on-duplicate-generated-applications` | `FAIL_ON_DUPLICATE_GENERATED_APPLICATIONS` | `false` | Fail when a single ApplicationSet generates multiple Applications with the same name |
| `--skip-appset-generation-errors` | `SKIP_APPSET_GENERATION_ERRORS` | `false` | Skip ApplicationSets that fail to generate (log a warning and continue) instead of aborting the run. Useful for generators that need cluster secrets or live data unavailable in the ephemeral cluster (e.g. `pullRequest`/`scmProvider`) |
| `--kind-internal` | `KIND_INTERNAL` | `false` | Use the kind cluster's internal address in the kubeconfig (allows connecting to the cluster when running the CLI in a container) |
| `--version`, `-v` | - | - | Prints version information |
| `--output-app-manifests` | `OUTPUT_APP_MANIFESTS` | `false` | Write each application's manifests to its own file under `output/base/` and `output/target/` |
Expand Down
20 changes: 18 additions & 2 deletions pkg/argoapplication/application_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func ConvertAppSetsToAppsInBothBranches(
redirectRevisions []string,
debug bool,
failOnDuplicateGeneratedApplications bool,
skipAppSetGenerationErrors bool,
appSelectionOptions ApplicationSelectionOptions,
) (*ArgoSelection, *ArgoSelection, time.Duration, error) {
startTime := time.Now()
Expand All @@ -40,6 +41,7 @@ func ConvertAppSetsToAppsInBothBranches(
baseTempFolder,
debug,
failOnDuplicateGeneratedApplications,
skipAppSetGenerationErrors,
appSelectionOptions,
repoSelector,
redirectRevisions,
Expand All @@ -58,6 +60,7 @@ func ConvertAppSetsToAppsInBothBranches(
targetTempFolder,
debug,
failOnDuplicateGeneratedApplications,
skipAppSetGenerationErrors,
appSelectionOptions,
repoSelector,
redirectRevisions,
Expand All @@ -79,6 +82,7 @@ func processAppSets(
tempFolder string,
debug bool,
failOnDuplicateGeneratedApplications bool,
skipAppSetGenerationErrors bool,
appSelectionOptions ApplicationSelectionOptions,
repoSelector repository.Selector,
redirectRevisions []string,
Expand All @@ -91,6 +95,7 @@ func processAppSets(
tempFolder,
debug,
failOnDuplicateGeneratedApplications,
skipAppSetGenerationErrors,
)
if err != nil {
log.Error().Str("branch", branch.Name).Msg("❌ Failed to generate apps")
Expand Down Expand Up @@ -207,6 +212,7 @@ func convertAppSetsToApps(
tempFolder string,
debug bool,
failOnDuplicateGeneratedApplications bool,
skipAppSetGenerationErrors bool,
) (*AppSetConversionResult, error) {

log.Debug().Str("branch", branch.Name).Msg("🤖 Generating Applications from ApplicationSets")
Expand Down Expand Up @@ -270,9 +276,19 @@ func convertAppSetsToApps(
// the original onlyAppSets slice, regardless of goroutine scheduling.
orderedResults := make([][]ArgoResource, len(onlyAppSets))

skippedAppSetsCount := 0
for res := range results {
if res.err != nil {
return nil, res.err
if !skipAppSetGenerationErrors {
return nil, res.err
}
log.Warn().
Err(res.err).
Str("branch", branch.Name).
Str(onlyAppSets[res.index].Kind.ShortName(), onlyAppSets[res.index].GetLongName()).
Msg("⚠️ Skipping ApplicationSet that failed to generate because --skip-appset-generation-errors is enabled")
skippedAppSetsCount++
continue
}
generatedApplicationsCount += len(res.apps)
orderedResults[res.index] = res.apps
Expand All @@ -285,7 +301,7 @@ func convertAppSetsToApps(
}

return &AppSetConversionResult{
appSetsProcessedCount: len(onlyAppSets),
appSetsProcessedCount: len(onlyAppSets) - skippedAppSetsCount,
originalApplicationsCount: len(plainApps),
generatedApplicationsCount: generatedApplicationsCount,
argoResource: appsNew,
Expand Down