From 8b4747c338cfaca408a3569dd3aa00077eda6078 Mon Sep 17 00:00:00 2001 From: Justin Watkinson Date: Mon, 8 Aug 2022 16:19:42 -0500 Subject: [PATCH] feat: add projects filter to app sync command (#8320) (#10133) * feat: add projects filter to app sync command Signed-off-by: Chetan Banavikalmutt * test: add e2e sync by project Signed-off-by: Justin Watkinson * Retrigger CI pipeline Signed-off-by: Justin Watkinson Co-authored-by: Chetan Banavikalmutt --- cmd/argocd/commands/app.go | 22 ++++++++++++++++----- docs/user-guide/commands/argocd_app_sync.md | 3 ++- test/e2e/app_management_test.go | 20 ++++++++++++++++++- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index ce14642ee0523..9bbcd6ba0705a 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -1389,9 +1389,10 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co infos []string diffChanges bool diffChangesConfirm bool + projects []string ) var command = &cobra.Command{ - Use: "sync [APPNAME... | -l selector]", + Use: "sync [APPNAME... | -l selector | --project project-name]", Short: "Sync an application to its target state", Example: ` # Sync an app argocd app sync my-app @@ -1411,7 +1412,8 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co Run: func(c *cobra.Command, args []string) { ctx := c.Context() - if len(args) == 0 && selector == "" { + if len(args) == 0 && selector == "" && len(projects) == 0 { + c.HelpFunc()(c, args) os.Exit(1) } @@ -1423,13 +1425,22 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co errors.CheckError(err) appNames := args - if selector != "" { - list, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{Selector: pointer.String(selector)}) + if selector != "" || len(projects) > 0 { + list, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{Selector: pointer.String(selector), Projects: projects}) errors.CheckError(err) + // unlike list, we'd want to fail if nothing was found if len(list.Items) == 0 { - log.Fatalf("no apps match selector %v", selector) + errMsg := "No matching apps found for filter:" + if selector != "" { + errMsg += fmt.Sprintf(" selector %s", selector) + } + if len(projects) != 0 { + errMsg += fmt.Sprintf(" projects %v", projects) + } + log.Fatalf(errMsg) } + for _, i := range list.Items { appNames = append(appNames, i.Name) } @@ -1612,6 +1623,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().StringArrayVar(&infos, "info", []string{}, "A list of key-value pairs during sync process. These infos will be persisted in app.") command.Flags().BoolVar(&diffChangesConfirm, "assumeYes", false, "Assume yes as answer for all user queries or prompts") command.Flags().BoolVar(&diffChanges, "preview-changes", false, "Preview difference against the target and live state before syncing app and wait for user confirmation") + command.Flags().StringArrayVar(&projects, "project", []string{}, "Sync apps that belong to the specified projects. This option may be specified repeatedly.") return command } diff --git a/docs/user-guide/commands/argocd_app_sync.md b/docs/user-guide/commands/argocd_app_sync.md index 09556335616cb..753f2ffe7a71f 100644 --- a/docs/user-guide/commands/argocd_app_sync.md +++ b/docs/user-guide/commands/argocd_app_sync.md @@ -3,7 +3,7 @@ Sync an application to its target state ``` -argocd app sync [APPNAME... | -l selector] [flags] +argocd app sync [APPNAME... | -l selector | --project project-name] [flags] ``` ### Examples @@ -39,6 +39,7 @@ argocd app sync [APPNAME... | -l selector] [flags] --local string Path to a local directory. When this flag is present no git queries will be made --local-repo-root string Path to the repository root. Used together with --local allows setting the repository root (default "/") --preview-changes Preview difference against the target and live state before syncing app and wait for user confirmation + --project stringArray Sync apps that belong to the specified projects. This option may be specified repeatedly. --prune Allow deleting unexpected resources --replace Use a kubectl create/replace instead apply --resource stringArray Sync only specific resources as GROUP:KIND:NAME. Fields may be blank. This option may be specified repeatedly diff --git a/test/e2e/app_management_test.go b/test/e2e/app_management_test.go index 4ab2c5baa54cd..1a85020b514b9 100644 --- a/test/e2e/app_management_test.go +++ b/test/e2e/app_management_test.go @@ -462,7 +462,7 @@ func TestAppLabels(t *testing.T) { Sync("-l", "foo=rubbish"). DoNotIgnoreErrors(). Then(). - Expect(Error("", "no apps match selector foo=rubbish")). + Expect(Error("", "No matching apps found for filter: selector foo=rubbish")). // check we can update the app and it is then sync'd Given(). When(). @@ -938,6 +938,24 @@ func TestSyncResourceByLabel(t *testing.T) { }) } +func TestSyncResourceByProject(t *testing.T) { + Given(t). + Path(guestbookPath). + When(). + CreateApp(). + Sync(). + Then(). + And(func(app *Application) { + _, _ = RunCli("app", "sync", app.Name, "--project", app.Spec.Project) + }). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + And(func(app *Application) { + _, err := RunCli("app", "sync", app.Name, "--project", "this-project-does-not-exist") + assert.Error(t, err) + assert.Contains(t, err.Error(), "level=fatal") + }) +} + func TestLocalManifestSync(t *testing.T) { Given(t). Path(guestbookPath).