Skip to content

Commit 90d4c0d

Browse files
authored
Feat | Add --repo-regex option and make --repo stricter (#436)
1 parent dce8515 commit 90d4c0d

15 files changed

Lines changed: 514 additions & 168 deletions

File tree

cmd/main.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func run(cfg *Config) error {
9898
baseBranch,
9999
targetBranch,
100100
appSelectionOptions,
101-
cfg.Repo,
101+
cfg.RepoSelector,
102102
redirectRevisions,
103103
)
104104
if err != nil {
@@ -246,7 +246,7 @@ func run(cfg *Config) error {
246246
targetApps,
247247
baseBranch,
248248
targetBranch,
249-
cfg.Repo,
249+
cfg.RepoSelector,
250250
tempFolder,
251251
redirectRevisions,
252252
cfg.Debug,
@@ -330,7 +330,7 @@ func run(cfg *Config) error {
330330
cfg.Concurrency,
331331
baseApps.SelectedApps,
332332
targetApps.SelectedApps,
333-
cfg.Repo,
333+
cfg.RepoSelector,
334334
appSelectionOptions,
335335
tempFolder,
336336
)
@@ -343,7 +343,7 @@ func run(cfg *Config) error {
343343
cfg.Concurrency,
344344
baseApps.SelectedApps,
345345
targetApps.SelectedApps,
346-
cfg.Repo,
346+
cfg.RepoSelector,
347347
)
348348
}
349349
} else {

cmd/options.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/dag-andersen/argocd-diff-preview/pkg/k3d"
2323
"github.com/dag-andersen/argocd-diff-preview/pkg/kind"
2424
"github.com/dag-andersen/argocd-diff-preview/pkg/minikube"
25+
"github.com/dag-andersen/argocd-diff-preview/pkg/repository"
2526
"github.com/dag-andersen/argocd-diff-preview/pkg/resource_filter"
2627
"github.com/dag-andersen/argocd-diff-preview/pkg/vars"
2728
)
@@ -97,6 +98,7 @@ type RawOptions struct {
9798
BaseBranch string `mapstructure:"base-branch"`
9899
TargetBranch string `mapstructure:"target-branch"`
99100
Repo string `mapstructure:"repo"`
101+
RepoRegex string `mapstructure:"repo-regex"`
100102
OutputFolder string `mapstructure:"output-folder"`
101103
SecretsFolder string `mapstructure:"secrets-folder"`
102104
CreateCluster bool `mapstructure:"create-cluster"`
@@ -146,7 +148,7 @@ type Config struct {
146148
LineCount uint
147149
BaseBranch string
148150
TargetBranch string
149-
Repo string
151+
RepoSelector repository.Selector
150152
OutputFolder string
151153
SecretsFolder string
152154
CreateCluster bool
@@ -302,7 +304,8 @@ func Parse() *Config {
302304
// Git related
303305
rootCmd.Flags().StringP("base-branch", "b", DefaultBaseBranch, "Base branch name")
304306
rootCmd.Flags().StringP("target-branch", "t", "", "Target branch name (required)")
305-
rootCmd.Flags().String("repo", "", "Git Repository. Format: OWNER/REPO (required)")
307+
rootCmd.Flags().String("repo", "", "Git repository. Format: OWNER/REPO. Mutually exclusive with --repo-regex")
308+
rootCmd.Flags().String("repo-regex", "", "Regex matched against normalized Argo CD repoURL values for templated repository URLs. Mutually exclusive with --repo")
306309

307310
// Folders
308311
rootCmd.Flags().StringP("output-folder", "o", DefaultOutputFolder, "Output folder where the diff will be saved")
@@ -327,7 +330,7 @@ func Parse() *Config {
327330
rootCmd.Flags().Bool("auto-detect-files-changed", DefaultAutoDetectFilesChanged, "Auto detect files changed between branches")
328331
rootCmd.Flags().Bool("ignore-invalid-watch-pattern", DefaultIgnoreInvalidWatchPattern, "Ignore invalid watch pattern Regex on Applications")
329332
rootCmd.Flags().Bool("watch-if-no-watch-pattern-found", DefaultWatchIfNoWatchPatternFound, "Render applications without watch pattern")
330-
rootCmd.Flags().String("redirect-target-revisions", "", "List of target revisions to redirect")
333+
rootCmd.Flags().String("redirect-target-revisions", "", "Comma-separated source targetRevision values to redirect to the target branch. Example: main,HEAD. By default, every targetRevision in matching repositories is redirected")
331334
rootCmd.Flags().String("title", DefaultTitle, "Custom title for the markdown output")
332335
rootCmd.Flags().Bool("hide-deleted-app-diff", DefaultHideDeletedAppDiff, "Hide diff content for fully deleted applications (only show deletion header)")
333336
rootCmd.Flags().String("argocd-ui-url", DefaultArgocdUIURL, "Argo CD URL to generate application links in diff output (e.g., https://argocd.example.com)")
@@ -373,8 +376,11 @@ func (o *RawOptions) checkRequired() []string {
373376
if o.TargetBranch == "" {
374377
errors = append(errors, "target-branch")
375378
}
376-
if o.Repo == "" {
377-
errors = append(errors, "repo")
379+
if o.Repo == "" && o.RepoRegex == "" {
380+
errors = append(errors, "repo or repo-regex")
381+
}
382+
if o.Repo != "" && o.RepoRegex != "" {
383+
errors = append(errors, "repo and repo-regex are mutually exclusive")
378384
}
379385
return errors
380386
}
@@ -390,7 +396,6 @@ func (o *RawOptions) ToConfig() (*Config, error) {
390396
LineCount: o.LineCount,
391397
BaseBranch: o.BaseBranch,
392398
TargetBranch: o.TargetBranch,
393-
Repo: o.Repo,
394399
OutputFolder: o.OutputFolder,
395400
SecretsFolder: o.SecretsFolder,
396401
CreateCluster: o.CreateCluster,
@@ -447,6 +452,11 @@ func (o *RawOptions) ToConfig() (*Config, error) {
447452
return nil, fmt.Errorf("invalid file-regex: %w", err)
448453
}
449454

455+
cfg.RepoSelector, err = o.parseRepositorySelector()
456+
if err != nil {
457+
return nil, err
458+
}
459+
450460
// Parse selectors
451461
cfg.Selectors, err = o.parseSelectors()
452462
if err != nil {
@@ -521,6 +531,15 @@ func (o *RawOptions) parseFileRegex() (*regexp.Regexp, error) {
521531
return regexp.Compile(o.FileRegex)
522532
}
523533

534+
// parseRepositorySelector returns a Repository Selector based on the repo or repo-regex flags
535+
func (o *RawOptions) parseRepositorySelector() (repository.Selector, error) {
536+
repoSelector, err := repository.NewSelector(o.Repo, o.RepoRegex)
537+
if err != nil {
538+
return repository.Selector{}, fmt.Errorf("invalid repo-regex: %w", err)
539+
}
540+
return *repoSelector, nil
541+
}
542+
524543
// parseRedirectRevisions parses the redirect-target-revisions string into a slice of strings
525544
func (o *RawOptions) parseRedirectRevisions() []string {
526545
if o.RedirectTargetRevisions == "" {
@@ -654,7 +673,12 @@ func (o *Config) LogConfig() {
654673
if o.ArgocdConfigPath != DefaultArgocdConfigPath {
655674
log.Info().Msgf("✨ - argocd-config-dir: %s", o.ArgocdConfigPath)
656675
}
657-
log.Info().Msgf("✨ - repo: %s", o.Repo)
676+
if o.RepoSelector.Repo != "" {
677+
log.Info().Msgf("✨ - repo: %s", o.RepoSelector.Repo)
678+
}
679+
if o.RepoSelector.Regex != nil {
680+
log.Info().Msgf("✨ - repo-regex: %s", o.RepoSelector.Regex.String())
681+
}
658682
log.Info().Msgf("✨ - timeout: %d seconds", o.Timeout)
659683
if o.LogFormat != DefaultLogFormat {
660684
log.Info().Msgf("✨ - log-format: %s", o.LogFormat)

docs/options.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ This document describes all the available options for `argocd-diff-preview`. Opt
55
## Usage
66

77
```bash
8-
argocd-diff-preview [FLAGS] [OPTIONS] --repo <repo> --target-branch <target-branch>
8+
argocd-diff-preview [FLAGS] [OPTIONS] (--repo <repo> | --repo-regex <regex>) --target-branch <target-branch>
99
```
1010

1111
## Required Options
1212

1313
| Flag | Environment Variable | Description |
1414
| --------------------------------------- | -------------------- | -------------------------------------------------------------------------------- |
15-
| `--repo <repo>` | `REPO` | Git Repository in format `OWNER/REPO` (e.g., `dag-andersen/argocd-diff-preview`) |
15+
| `--repo <repo>` or `--repo-regex <regex>` | `REPO` or `REPO_REGEX` | Git repository in format `OWNER/REPO`, or a regex for templated Argo CD repoURL values. These options are mutually exclusive |
1616
| `--target-branch <target-branch>`, `-t` | `TARGET_BRANCH` | Target branch name (the branch you want to compare with the base branch) |
1717

1818
## Flags
@@ -63,8 +63,9 @@ argocd-diff-preview [FLAGS] [OPTIONS] --repo <repo> --target-branch <target-bran
6363
| `--log-format <format>` | `LOG_FORMAT` | `human` | Log format. Options: `human`, `json` |
6464
| `--max-diff-length <length>` | `MAX_DIFF_LENGTH` | `65536` | Max diff message character count (only limits the generated Markdown file) |
6565
| `--output-folder <folder>`, `-o` | `OUTPUT_FOLDER` | `./output` | Output folder where the diff will be saved |
66-
| `--redirect-target-revisions <revs>` | `REDIRECT_TARGET_REVISIONS` | - | List of target revisions to redirect |
66+
| `--redirect-target-revisions <revs>` | `REDIRECT_TARGET_REVISIONS` | - | Comma-separated source targetRevision values to redirect to the target branch. Example: main,HEAD. By default, every targetRevision in matching repositories is redirected |
6767
| `--render-method <method>` | `RENDER_METHOD` | `server-api` | Manifest rendering method. Options: `cli`, `server-api`, `repo-server-api` |
68+
| `--repo-regex <regex>` | `REPO_REGEX` | - | Advanced repository matcher for templated Argo CD repoURL values. Mutually exclusive with `--repo` |
6869
| `--secrets-folder <folder>`, `-s` | `SECRETS_FOLDER` | `./secrets` | Secrets folder where the secrets are read from |
6970
| `--selector <selector>`, `-l` | `SELECTOR` | - | Label selector to filter on (e.g., `key1=value1,key2=value2`) |
7071
| `--timeout <seconds>` | `TIMEOUT` | `180` | Set timeout in seconds |

integration-test/integration_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ type TestCase struct {
6565
ArgocdConfigDir string // Custom argocd-config directory (relative to integration-test/); overrides auto-derived path
6666
ArgocdUIURL string // Argo CD URL for generating application links in diff output
6767
TraverseAppOfApps string // If "true", enables recursive child app discovery (--traverse-app-of-apps)
68+
RepoRegex string // If set, use --repo-regex instead of --repo
6869
ExpectFailure bool // If true, the test is expected to fail
6970
}
7071

@@ -234,6 +235,7 @@ var testCases = []TestCase{
234235
BaseBranch: "integration-test/branch-9/base",
235236
Suffix: "-3",
236237
MaxDiffLength: "400",
238+
RepoRegex: "go.*diff-pre",
237239
},
238240
{
239241
Name: "branch-10/target-1",
@@ -272,6 +274,7 @@ var testCases = []TestCase{
272274
TargetBranch: "integration-test/branch-13/target",
273275
BaseBranch: "integration-test/branch-13/base",
274276
Suffix: "-1",
277+
RepoRegex: "-diff-",
275278
},
276279
{
277280
Name: "branch-13/target-2",
@@ -872,7 +875,11 @@ func runWithDocker(tc TestCase, createCluster bool, runDirs RunDirs) error {
872875
// Add environment variables
873876
args = append(args, "-e", fmt.Sprintf("BASE_BRANCH=%s", tc.BaseBranch))
874877
args = append(args, "-e", fmt.Sprintf("TARGET_BRANCH=%s", tc.TargetBranch))
875-
args = append(args, "-e", fmt.Sprintf("REPO=%s/%s", defaultGitHubOrg, defaultGitOpsRepo))
878+
if tc.RepoRegex != "" {
879+
args = append(args, "-e", fmt.Sprintf("REPO_REGEX=%s", tc.RepoRegex))
880+
} else {
881+
args = append(args, "-e", fmt.Sprintf("REPO=%s/%s", defaultGitHubOrg, defaultGitOpsRepo))
882+
}
876883
args = append(args, "-e", fmt.Sprintf("TIMEOUT=%s", defaultTimeout))
877884
args = append(args, "-e", fmt.Sprintf("LINE_COUNT=%s", getLineCount(tc)))
878885
args = append(args, "-e", fmt.Sprintf("MAX_DIFF_LENGTH=%s", getMaxDiffLength(tc)))
@@ -964,7 +971,6 @@ func buildArgs(tc TestCase, createCluster bool, runDirs RunDirs, repoRoot string
964971
args := []string{
965972
"--base-branch", tc.BaseBranch,
966973
"--target-branch", tc.TargetBranch,
967-
"--repo", fmt.Sprintf("%s/%s", defaultGitHubOrg, defaultGitOpsRepo),
968974
"--argocd-namespace", argocdNamespace,
969975
"--timeout", defaultTimeout,
970976
"--line-count", getLineCount(tc),
@@ -973,6 +979,11 @@ func buildArgs(tc TestCase, createCluster bool, runDirs RunDirs, repoRoot string
973979
"--keep-cluster-alive",
974980
"--disable-client-throttling",
975981
}
982+
if tc.RepoRegex != "" {
983+
args = append(args, "--repo-regex", tc.RepoRegex)
984+
} else {
985+
args = append(args, "--repo", fmt.Sprintf("%s/%s", defaultGitHubOrg, defaultGitOpsRepo))
986+
}
976987

977988
// Don't keep cluster alive for tests that expect failure (cluster may be in broken state)
978989
if !tc.ExpectFailure {

pkg/argoapplication/app_status.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ package argoapplication
33
import (
44
"errors"
55
"fmt"
6+
"strings"
67

78
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
89
"github.com/dag-andersen/argocd-diff-preview/pkg/argocd"
910
)
1011

1112
func isErrorCondition(condType string) bool {
12-
return condType != "" && containsIgnoreCase(condType, "error")
13+
return condType != "" && strings.Contains(strings.ToLower(condType), "error")
1314
}
1415

1516
// GetApplicationStatus returns the error status of an application

pkg/argoapplication/application_sets.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/dag-andersen/argocd-diff-preview/pkg/argocd"
1313
"github.com/dag-andersen/argocd-diff-preview/pkg/git"
14+
"github.com/dag-andersen/argocd-diff-preview/pkg/repository"
1415
"github.com/dag-andersen/argocd-diff-preview/pkg/utils"
1516
)
1617

@@ -20,7 +21,7 @@ func ConvertAppSetsToAppsInBothBranches(
2021
targetApps *ArgoSelection,
2122
baseBranch *git.Branch,
2223
targetBranch *git.Branch,
23-
repo string,
24+
repoSelector repository.Selector,
2425
tempFolder string,
2526
redirectRevisions []string,
2627
debug bool,
@@ -40,7 +41,7 @@ func ConvertAppSetsToAppsInBothBranches(
4041
debug,
4142
failOnDuplicateGeneratedApplications,
4243
appSelectionOptions,
43-
repo,
44+
repoSelector,
4445
redirectRevisions,
4546
)
4647

@@ -58,7 +59,7 @@ func ConvertAppSetsToAppsInBothBranches(
5859
debug,
5960
failOnDuplicateGeneratedApplications,
6061
appSelectionOptions,
61-
repo,
62+
repoSelector,
6263
redirectRevisions,
6364
)
6465
if err != nil {
@@ -79,7 +80,7 @@ func processAppSets(
7980
debug bool,
8081
failOnDuplicateGeneratedApplications bool,
8182
appSelectionOptions ApplicationSelectionOptions,
82-
repo string,
83+
repoSelector repository.Selector,
8384
redirectRevisions []string,
8485
) (*ArgoSelection, error) {
8586

@@ -150,7 +151,7 @@ func processAppSets(
150151
argocd.Namespace,
151152
selection.SelectedApps,
152153
branch,
153-
repo,
154+
repoSelector,
154155
redirectRevisions,
155156
)
156157
if err != nil {

pkg/argoapplication/applications.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/dag-andersen/argocd-diff-preview/pkg/fileparsing"
1111
"github.com/dag-andersen/argocd-diff-preview/pkg/git"
12+
"github.com/dag-andersen/argocd-diff-preview/pkg/repository"
1213
"github.com/dag-andersen/argocd-diff-preview/pkg/utils"
1314
"sigs.k8s.io/yaml"
1415
)
@@ -74,14 +75,14 @@ func GetApplicationsForBranches(
7475
baseBranch *git.Branch,
7576
targetBranch *git.Branch,
7677
appSelectionOptions ApplicationSelectionOptions,
77-
repo string,
78+
repoSelector repository.Selector,
7879
redirectRevisions []string,
7980
) (*ArgoSelection, *ArgoSelection, error) {
8081
baseApps, err := getApplications(
8182
argocdNamespace,
8283
baseBranch,
8384
appSelectionOptions,
84-
repo,
85+
repoSelector,
8586
redirectRevisions,
8687
)
8788
if err != nil {
@@ -92,7 +93,7 @@ func GetApplicationsForBranches(
9293
argocdNamespace,
9394
targetBranch,
9495
appSelectionOptions,
95-
repo,
96+
repoSelector,
9697
redirectRevisions,
9798
)
9899
if err != nil {
@@ -107,7 +108,7 @@ func getApplications(
107108
argocdNamespace string,
108109
branch *git.Branch,
109110
appSelectionOptions ApplicationSelectionOptions,
110-
repo string,
111+
repoSelector repository.Selector,
111112
redirectRevisions []string,
112113
) (*ArgoSelection, error) {
113114
log.Info().Str("branch", branch.Name).Msg("🤖 Fetching all files for branch")
@@ -156,7 +157,7 @@ func getApplications(
156157
argocdNamespace,
157158
selection.SelectedApps,
158159
branch,
159-
repo,
160+
repoSelector,
160161
redirectRevisions,
161162
)
162163
if err != nil {

0 commit comments

Comments
 (0)