From ed0218f98e1c0ecfbe3851cc3d0b71af5275320f Mon Sep 17 00:00:00 2001 From: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:15:08 -0400 Subject: [PATCH] feat: add cli commands to create/set/unset/edit sources for multi-source application (#17425) * "feat:add cli commands to create/set/unset/edit sources for multi-source app" Signed-off-by: ishitasequeira * fixed the ci failure Signed-off-by: ishitasequeira * update commands Signed-off-by: ishitasequeira * error out if source-index not specified for multi-source applications Signed-off-by: ishitasequeira * fixed the ci failure Signed-off-by: ishitasequeira * fix tests Signed-off-by: ishitasequeira * set 0 as default source index for app create Signed-off-by: ishitasequeira * add index to ParameterOverrides function Signed-off-by: ishitasequeira * do not allow overrides for applications with multiple sources Signed-off-by: ishitasequeira * update tests Signed-off-by: ishitasequeira * remove create with override example Signed-off-by: ishitasequeira * address comments Signed-off-by: ishitasequeira * update tests Signed-off-by: ishitasequeira * update examples in docs Signed-off-by: ishitasequeira * update logs Signed-off-by: ishitasequeira * Add test and update docs Signed-off-by: ishitasequeira --------- Signed-off-by: ishitasequeira --- cmd/argocd/commands/app.go | 103 ++++++++++++++---- cmd/util/app.go | 32 ++++-- cmd/util/app_test.go | 59 +++++++++- docs/user-guide/commands/argocd_app.md | 2 +- docs/user-guide/commands/argocd_app_create.md | 3 + .../commands/argocd_app_remove-source.md | 6 +- docs/user-guide/commands/argocd_app_set.md | 4 + docs/user-guide/commands/argocd_app_unset.md | 7 +- pkg/apis/application/v1alpha1/types.go | 5 +- server/repository/repository_test.go | 4 +- util/notification/expression/repo/repo.go | 2 +- 11 files changed, 185 insertions(+), 42 deletions(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 7ad3d7646fa29..fe42633f47e93 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -137,13 +137,15 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra. # Create a Kustomize app argocd app create kustomize-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path kustomize-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --kustomize-image gcr.io/heptio-images/ks-guestbook-demo:0.1 + # Create a MultiSource app while yaml file contains an application with multiple sources + argocd app create guestbook --file + # Create a app using a custom tool: argocd app create kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() argocdClient := headless.NewClientOrDie(clientOpts, c) - apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags()) errors.CheckError(err) @@ -730,6 +732,7 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com var ( appOpts cmdutil.AppOptions appNamespace string + sourceIndex int ) var command = &cobra.Command{ Use: "set APPNAME", @@ -747,6 +750,9 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com # Set and override application parameters with a parameter file argocd app set my-app --parameter-file path/to/parameter-file.yaml + # Set and override application parameters for a source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app set my-app --source-index 1 --repo https://github.com/argoproj/argocd-example-apps.git + # Set application parameters and specify the namespace argocd app set my-app --parameter key1=value1 --parameter key2=value2 --namespace my-namespace `), @@ -765,14 +771,25 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: &appName, AppNamespace: &appNs}) errors.CheckError(err) - visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) + if app.Spec.HasMultipleSources() { + if sourceIndex <= 0 { + errors.CheckError(fmt.Errorf("Source index should be specified and greater than 0 for applications with multiple sources")) + } + if len(app.Spec.GetSources()) < sourceIndex { + errors.CheckError(fmt.Errorf("Source index should be less than the number of sources in the application")) + } + } + + // sourceIndex startes with 1, thus, it needs to be decreased by 1 to find the correct index in the list of sources + sourceIndex = sourceIndex - 1 + visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, sourceIndex) if visited == 0 { log.Error("Please set at least one option to update") c.HelpFunc()(c, args) os.Exit(1) } - setParameterOverrides(app, appOpts.Parameters) + setParameterOverrides(app, appOpts.Parameters, sourceIndex) _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &app.Name, Spec: &app.Spec, @@ -782,6 +799,7 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com errors.CheckError(err) }, } + command.Flags().IntVar(&sourceIndex, "source-index", -1, "Index of the source from the list of sources of the app. Index starts at 1.") cmdutil.AddAppFlags(command, &appOpts) command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Set application parameters in namespace") return command @@ -801,6 +819,7 @@ type unsetOpts struct { ignoreMissingValueFiles bool pluginEnvs []string passCredentials bool + ref bool } // IsZero returns true when the Application options for kustomize are considered empty @@ -816,6 +835,9 @@ func (o *unsetOpts) KustomizeIsZero() bool { // NewApplicationUnsetCommand returns a new instance of an `argocd app unset` command func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + sourceIndex int + ) appOpts := cmdutil.AppOptions{} opts := unsetOpts{} var appNamespace string @@ -825,9 +847,12 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C Example: ` # Unset kustomize override kustomize image argocd app unset my-app --kustomize-image=alpine - # Unset kustomize override prefix + # Unset kustomize override suffix argocd app unset my-app --namesuffix + # Unset kustomize override suffix for source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app unset my-app --source-index 1 --namesuffix + # Unset parameter override argocd app unset my-app -p COMPONENT=PARAM`, @@ -838,14 +863,25 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C c.HelpFunc()(c, args) os.Exit(1) } + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: &appName, AppNamespace: &appNs}) errors.CheckError(err) - source := app.Spec.GetSource() - updated, nothingToUnset := unset(&source, opts) + if app.Spec.HasMultipleSources() { + if sourceIndex <= 0 { + errors.CheckError(fmt.Errorf("Source index should be specified and greater than 0 for applications with multiple sources")) + } + if len(app.Spec.GetSources()) < sourceIndex { + errors.CheckError(fmt.Errorf("Source index should be less than the number of sources in the application")) + } + } + + source := app.Spec.GetSourcePtr(sourceIndex) + + updated, nothingToUnset := unset(source, opts) if nothingToUnset { c.HelpFunc()(c, args) os.Exit(1) @@ -854,7 +890,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C return } - cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) + cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, sourceIndex) _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &app.Name, Spec: &app.Spec, @@ -877,13 +913,22 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C command.Flags().StringArrayVar(&opts.kustomizeReplicas, "kustomize-replica", []string{}, "Kustomize replicas name (e.g. --kustomize-replica my-deployment --kustomize-replica my-statefulset)") command.Flags().StringArrayVar(&opts.pluginEnvs, "plugin-env", []string{}, "Unset plugin env variables (e.g --plugin-env name)") command.Flags().BoolVar(&opts.passCredentials, "pass-credentials", false, "Unset passCredentials") + command.Flags().BoolVar(&opts.ref, "ref", false, "Unset ref on the source") + command.Flags().IntVar(&sourceIndex, "source-index", -1, "Index of the source from the list of sources of the app. Index starts at 1.") return command } func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, nothingToUnset bool) { + needToUnsetRef := false + if opts.ref && source.Ref != "" { + source.Ref = "" + updated = true + needToUnsetRef = true + } + if source.Kustomize != nil { if opts.KustomizeIsZero() { - return false, true + return updated, !needToUnsetRef } if opts.namePrefix && source.Kustomize.NamePrefix != "" { @@ -933,7 +978,7 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n } if source.Helm != nil { if len(opts.parameters) == 0 && len(opts.valuesFiles) == 0 && !opts.valuesLiteral && !opts.ignoreMissingValueFiles && !opts.passCredentials { - return false, true + return updated, !needToUnsetRef } for _, paramStr := range opts.parameters { helmParams := source.Helm.Parameters @@ -970,9 +1015,10 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n updated = true } } + if source.Plugin != nil { if len(opts.pluginEnvs) == 0 { - return false, true + return false, !needToUnsetRef } for _, env := range opts.pluginEnvs { err := source.Plugin.RemoveEnvEntry(env) @@ -2419,11 +2465,11 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, // setParameterOverrides updates an existing or appends a new parameter override in the application // the app is assumed to be a helm app and is expected to be in the form: // param=value -func setParameterOverrides(app *argoappv1.Application, parameters []string) { +func setParameterOverrides(app *argoappv1.Application, parameters []string, index int) { if len(parameters) == 0 { return } - source := app.Spec.GetSource() + source := app.Spec.GetSourcePtr(index) var sourceType argoappv1.ApplicationSourceType if st, _ := source.ExplicitType(); st != nil { sourceType = *st @@ -2731,7 +2777,9 @@ func NewApplicationTerminateOpCommand(clientOpts *argocdclient.ClientOptions) *c } func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { - var appNamespace string + var ( + appNamespace string + ) var command = &cobra.Command{ Use: "edit APPNAME", Short: "Edit application", @@ -2742,6 +2790,7 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co c.HelpFunc()(c, args) os.Exit(1) } + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) @@ -2768,7 +2817,11 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } var appOpts cmdutil.AppOptions - cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) + + // do not allow overrides for applications with multiple sources + if !app.Spec.HasMultipleSources() { + cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, 0) + } _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &appName, Spec: &updatedSpec, @@ -2871,8 +2924,12 @@ func NewApplicationAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cob if len(app.Spec.Sources) > 0 { appSource, _ := cmdutil.ConstructSource(&argoappv1.ApplicationSource{}, appOpts, c.Flags()) + // sourceIndex is the index at which new source will be appended to spec.Sources + sourceIndex := len(app.Spec.GetSources()) app.Spec.Sources = append(app.Spec.Sources, *appSource) + setParameterOverrides(app, appOpts.Parameters, sourceIndex) + _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &app.Name, Spec: &app.Spec, @@ -2895,13 +2952,13 @@ func NewApplicationAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cob // NewApplicationRemoveSourceCommand returns a new instance of an `argocd app remove-source` command func NewApplicationRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - source_index int + sourceIndex int appNamespace string ) command := &cobra.Command{ Use: "remove-source APPNAME", - Short: "Remove a source from multiple sources application. Index starts with 0.", - Example: ` # Remove the source at index 1 from application's sources + Short: "Remove a source from multiple sources application. Index starts with 1. Default value is -1.", + Example: ` # Remove the source at index 1 from application's sources. Index starts at 1. argocd app remove-source myapplication --source-index 1`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -2911,8 +2968,8 @@ func NewApplicationRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) * os.Exit(1) } - if source_index < 0 { - errors.CheckError(fmt.Errorf("Index value of source cannot be less than 0")) + if sourceIndex <= 0 { + errors.CheckError(fmt.Errorf("Index value of source must be greater than 0")) } argocdClient := headless.NewClientOrDie(clientOpts, c) @@ -2936,11 +2993,11 @@ func NewApplicationRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) * errors.CheckError(fmt.Errorf("Cannot remove the only source remaining in the app")) } - if len(app.Spec.GetSources()) <= source_index { - errors.CheckError(fmt.Errorf("Application does not have source at %d\n", source_index)) + if len(app.Spec.GetSources()) < sourceIndex { + errors.CheckError(fmt.Errorf("Application does not have source at %d\n", sourceIndex)) } - app.Spec.Sources = append(app.Spec.Sources[:source_index], app.Spec.Sources[source_index+1:]...) + app.Spec.Sources = append(app.Spec.Sources[:sourceIndex-1], app.Spec.Sources[sourceIndex:]...) _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &app.Name, @@ -2953,6 +3010,6 @@ func NewApplicationRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) * }, } command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Namespace of the target application where the source will be appended") - command.Flags().IntVar(&source_index, "source-index", -1, "Index of the source from the list of sources of the app. Index starts from 0.") + command.Flags().IntVar(&sourceIndex, "source-index", -1, "Index of the source from the list of sources of the app. Index starts from 1.") return command } diff --git a/cmd/util/app.go b/cmd/util/app.go index 9a284b56ce38b..b1693689004c4 100644 --- a/cmd/util/app.go +++ b/cmd/util/app.go @@ -139,16 +139,27 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) { command.Flags().StringVar(&opts.ref, "ref", "", "Ref is reference to another source within sources field") } -func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions) int { +func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions, index int) int { visited := 0 if flags == nil { return visited } - source := spec.GetSourcePtr() + source := spec.GetSourcePtr(index) if source == nil { source = &argoappv1.ApplicationSource{} } source, visited = ConstructSource(source, *appOpts, flags) + if spec.HasMultipleSources() { + if index == 0 { + spec.Sources[index] = *source + } else if index > 0 { + spec.Sources[index-1] = *source + } else { + spec.Sources = append(spec.Sources, *source) + } + } else { + spec.Source = source + } flags.Visit(func(f *pflag.Flag) { visited++ @@ -220,7 +231,6 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap log.Fatalf("Invalid sync-retry-limit [%d]", appOpts.retryLimit) } } - spec.Source = source }) if flags.Changed("auto-prune") { if spec.SyncPolicy == nil || spec.SyncPolicy.Automated == nil { @@ -414,11 +424,11 @@ func setJsonnetOptLibs(src *argoappv1.ApplicationSource, libs []string) { // SetParameterOverrides updates an existing or appends a new parameter override in the application // The app is assumed to be a helm app and is expected to be in the form: // param=value -func SetParameterOverrides(app *argoappv1.Application, parameters []string) { +func SetParameterOverrides(app *argoappv1.Application, parameters []string, index int) { if len(parameters) == 0 { return } - source := app.Spec.GetSource() + source := app.Spec.GetSourcePtr(index) var sourceType argoappv1.ApplicationSourceType if st, _ := source.ExplicitType(); st != nil { sourceType = *st @@ -530,8 +540,8 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string, Source: &argoappv1.ApplicationSource{}, }, } - SetAppSpecOptions(flags, &app.Spec, &appOpts) - SetParameterOverrides(app, appOpts.Parameters) + SetAppSpecOptions(flags, &app.Spec, &appOpts, 0) + SetParameterOverrides(app, appOpts.Parameters, 0) mergeLabels(app, labels) setAnnotations(app, annotations) return []*argoappv1.Application{ @@ -557,10 +567,14 @@ func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args return nil, fmt.Errorf("app.Name is empty. --name argument can be used to provide app.Name") } - SetAppSpecOptions(flags, &app.Spec, &appOpts) - SetParameterOverrides(app, appOpts.Parameters) mergeLabels(app, labels) setAnnotations(app, annotations) + + // do not allow overrides for applications with multiple sources + if !app.Spec.HasMultipleSources() { + SetAppSpecOptions(flags, &app.Spec, &appOpts, 0) + SetParameterOverrides(app, appOpts.Parameters, 0) + } } return apps, nil } diff --git a/cmd/util/app_test.go b/cmd/util/app_test.go index b5fce9c1e663e..5e95eeb388634 100644 --- a/cmd/util/app_test.go +++ b/cmd/util/app_test.go @@ -170,7 +170,16 @@ func (f *appOptionsFixture) SetFlag(key, value string) error { if err != nil { return err } - _ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options) + _ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options, 0) + return err +} + +func (f *appOptionsFixture) SetFlagWithSourceIndex(key, value string, index int) error { + err := f.command.Flags().Set(key, value) + if err != nil { + return err + } + _ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options, index) return err } @@ -225,6 +234,54 @@ func Test_setAppSpecOptions(t *testing.T) { }) } +func newMultiSourceAppOptionsFixture() *appOptionsFixture { + fixture := &appOptionsFixture{ + spec: &v1alpha1.ApplicationSpec{ + Sources: v1alpha1.ApplicationSources{ + v1alpha1.ApplicationSource{}, + v1alpha1.ApplicationSource{}, + }, + }, + command: &cobra.Command{}, + options: &AppOptions{}, + } + AddAppFlags(fixture.command, fixture.options) + return fixture +} + +func Test_setAppSpecOptionsMultiSourceApp(t *testing.T) { + f := newMultiSourceAppOptionsFixture() + index := 0 + index1 := 1 + index2 := 2 + t.Run("SyncPolicy", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("sync-policy", "automated", index1)) + assert.NotNil(t, f.spec.SyncPolicy.Automated) + + f.spec.SyncPolicy = nil + assert.NoError(t, f.SetFlagWithSourceIndex("sync-policy", "automatic", index1)) + assert.NotNil(t, f.spec.SyncPolicy.Automated) + }) + t.Run("Helm - Index 0", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("helm-version", "v2", index)) + assert.Equal(t, len(f.spec.GetSources()), 2) + assert.Equal(t, f.spec.GetSources()[index].Helm.Version, "v2") + }) + t.Run("Kustomize", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("kustomize-replica", "my-deployment=2", index1)) + assert.Equal(t, f.spec.Sources[index1-1].Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(2)}}) + assert.NoError(t, f.SetFlagWithSourceIndex("kustomize-replica", "my-deployment=4", index2)) + assert.Equal(t, f.spec.Sources[index2-1].Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(4)}}) + }) + t.Run("Helm", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("helm-version", "v2", index1)) + assert.NoError(t, f.SetFlagWithSourceIndex("helm-version", "v3", index2)) + assert.Equal(t, len(f.spec.GetSources()), 2) + assert.Equal(t, f.spec.GetSources()[index1-1].Helm.Version, "v2") + assert.Equal(t, f.spec.GetSources()[index2-1].Helm.Version, "v3") + }) +} + func Test_setAnnotations(t *testing.T) { t.Run("Annotations", func(t *testing.T) { app := v1alpha1.Application{} diff --git a/docs/user-guide/commands/argocd_app.md b/docs/user-guide/commands/argocd_app.md index ff8fe0d4a01b6..a5878502ce5c7 100644 --- a/docs/user-guide/commands/argocd_app.md +++ b/docs/user-guide/commands/argocd_app.md @@ -91,7 +91,7 @@ argocd app [flags] * [argocd app manifests](argocd_app_manifests.md) - Print manifests of an application * [argocd app patch](argocd_app_patch.md) - Patch application * [argocd app patch-resource](argocd_app_patch-resource.md) - Patch resource in an application -* [argocd app remove-source](argocd_app_remove-source.md) - Remove a source from multiple sources application. Index starts with 0. +* [argocd app remove-source](argocd_app_remove-source.md) - Remove a source from multiple sources application. Index starts with 1. Default value is -1. * [argocd app resources](argocd_app_resources.md) - List resource of application * [argocd app rollback](argocd_app_rollback.md) - Rollback application to a previous deployed version by History ID, omitted will Rollback to the previous version * [argocd app set](argocd_app_set.md) - Set application parameters diff --git a/docs/user-guide/commands/argocd_app_create.md b/docs/user-guide/commands/argocd_app_create.md index 00b4949f7993b..fb147b8e4aa9f 100644 --- a/docs/user-guide/commands/argocd_app_create.md +++ b/docs/user-guide/commands/argocd_app_create.md @@ -26,6 +26,9 @@ argocd app create APPNAME [flags] # Create a Kustomize app argocd app create kustomize-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path kustomize-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --kustomize-image gcr.io/heptio-images/ks-guestbook-demo:0.1 + # Create a MultiSource app while yaml file contains an application with multiple sources + argocd app create guestbook --file + # Create a app using a custom tool: argocd app create kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane ``` diff --git a/docs/user-guide/commands/argocd_app_remove-source.md b/docs/user-guide/commands/argocd_app_remove-source.md index b7bd0df09823d..b9f29d8c6eb45 100644 --- a/docs/user-guide/commands/argocd_app_remove-source.md +++ b/docs/user-guide/commands/argocd_app_remove-source.md @@ -2,7 +2,7 @@ ## argocd app remove-source -Remove a source from multiple sources application. Index starts with 0. +Remove a source from multiple sources application. Index starts with 1. Default value is -1. ``` argocd app remove-source APPNAME [flags] @@ -11,7 +11,7 @@ argocd app remove-source APPNAME [flags] ### Examples ``` - # Remove the source at index 1 from application's sources + # Remove the source at index 1 from application's sources. Index starts at 1. argocd app remove-source myapplication --source-index 1 ``` @@ -20,7 +20,7 @@ argocd app remove-source APPNAME [flags] ``` -N, --app-namespace string Namespace of the target application where the source will be appended -h, --help help for remove-source - --source-index int Index of the source from the list of sources of the app. Index starts from 0. (default -1) + --source-index int Index of the source from the list of sources of the app. Index starts from 1. (default -1) ``` ### Options inherited from parent commands diff --git a/docs/user-guide/commands/argocd_app_set.md b/docs/user-guide/commands/argocd_app_set.md index 1c6cc40bd5c27..97288ad775345 100644 --- a/docs/user-guide/commands/argocd_app_set.md +++ b/docs/user-guide/commands/argocd_app_set.md @@ -23,6 +23,9 @@ argocd app set APPNAME [flags] # Set and override application parameters with a parameter file argocd app set my-app --parameter-file path/to/parameter-file.yaml + # Set and override application parameters for a source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app set my-app --source-index 1 --repo https://github.com/argoproj/argocd-example-apps.git + # Set application parameters and specify the namespace argocd app set my-app --parameter key1=value1 --parameter key2=value2 --namespace my-namespace ``` @@ -76,6 +79,7 @@ argocd app set APPNAME [flags] --revision string The tracking source branch, tag, commit or Helm chart version the application will sync to --revision-history-limit int How many items to keep in revision history (default 10) --self-heal Set self healing when sync is automated + --source-index int Index of the source from the list of sources of the app. Index starts at 1. (default -1) --sync-option Prune=false Add or remove a sync option, e.g add Prune=false. Remove using `!` prefix, e.g. `!Prune=false` --sync-policy string Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic)) --sync-retry-backoff-duration duration Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h) (default 5s) diff --git a/docs/user-guide/commands/argocd_app_unset.md b/docs/user-guide/commands/argocd_app_unset.md index 34194b02d447c..0c3bf25d7fa91 100644 --- a/docs/user-guide/commands/argocd_app_unset.md +++ b/docs/user-guide/commands/argocd_app_unset.md @@ -14,9 +14,12 @@ argocd app unset APPNAME parameters [flags] # Unset kustomize override kustomize image argocd app unset my-app --kustomize-image=alpine - # Unset kustomize override prefix + # Unset kustomize override suffix argocd app unset my-app --namesuffix + # Unset kustomize override suffix for source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app unset my-app --source-index 1 --namesuffix + # Unset parameter override argocd app unset my-app -p COMPONENT=PARAM ``` @@ -36,6 +39,8 @@ argocd app unset APPNAME parameters [flags] -p, --parameter stringArray Unset a parameter override (e.g. -p guestbook=image) --pass-credentials Unset passCredentials --plugin-env stringArray Unset plugin env variables (e.g --plugin-env name) + --ref Unset ref on the source + --source-index int Index of the source from the list of sources of the app. Index starts at 1. (default -1) --values stringArray Unset one or more Helm values files --values-literal Unset literal Helm values block ``` diff --git a/pkg/apis/application/v1alpha1/types.go b/pkg/apis/application/v1alpha1/types.go index fc2908c4643dc..abd2735710e72 100644 --- a/pkg/apis/application/v1alpha1/types.go +++ b/pkg/apis/application/v1alpha1/types.go @@ -230,9 +230,12 @@ func (a *ApplicationSpec) HasMultipleSources() bool { return a.Sources != nil && len(a.Sources) > 0 } -func (a *ApplicationSpec) GetSourcePtr() *ApplicationSource { +func (a *ApplicationSpec) GetSourcePtr(index int) *ApplicationSource { // if Application has multiple sources, return the first source in sources if a.HasMultipleSources() { + if index > 0 { + return &a.Sources[index-1] + } return &a.Sources[0] } return a.Source diff --git a/server/repository/repository_test.go b/server/repository/repository_test.go index 9c294b5a332b9..55bf7ab7220ac 100644 --- a/server/repository/repository_test.go +++ b/server/repository/repository_test.go @@ -654,7 +654,7 @@ func TestRepositoryServerGetAppDetails(t *testing.T) { s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ - Source: guestbookApp.Spec.GetSourcePtr(), + Source: guestbookApp.Spec.GetSourcePtr(0), AppName: "guestbook", AppProject: "default", }) @@ -752,7 +752,7 @@ func TestRepositoryServerGetAppDetails(t *testing.T) { s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ - Source: guestbookApp.Spec.GetSourcePtr(), + Source: guestbookApp.Spec.GetSourcePtr(0), AppName: "guestbook", AppProject: "mismatch", }) diff --git a/util/notification/expression/repo/repo.go b/util/notification/expression/repo/repo.go index a782c0b7c1725..8456774f0869a 100644 --- a/util/notification/expression/repo/repo.go +++ b/util/notification/expression/repo/repo.go @@ -33,7 +33,7 @@ func getApplicationSourceAndName(obj *unstructured.Unstructured) (*v1alpha1.Appl if err != nil { return nil, "", err } - return application.Spec.GetSourcePtr(), application.GetName(), nil + return application.Spec.GetSourcePtr(0), application.GetName(), nil } func getAppDetails(app *unstructured.Unstructured, argocdService service.Service) (*shared.AppDetail, error) {