Skip to content

Commit

Permalink
feat(cli): add support for multiple sources to app diff|manifests com…
Browse files Browse the repository at this point in the history
…mand with `revisions` flag (argoproj#17650)

* Add support for multiple source to manifests --revision command

Signed-off-by: ishitasequeira <[email protected]>

* Update GetManifests to support multiple sources

Signed-off-by: ishitasequeira <[email protected]>

* remove testing logs

Signed-off-by: ishitasequeira <[email protected]>

* update cli docs

Signed-off-by: ishitasequeira <[email protected]>

* add extra validation for diff command

Signed-off-by: ishitasequeira <[email protected]>

* fix lint

Signed-off-by: ishitasequeira <[email protected]>

* Empty-Commit

Signed-off-by: ishitasequeira <[email protected]>

* revert apimachinery version

Signed-off-by: ishitasequeira <[email protected]>

* Update docs based on comments

Signed-off-by: ishitasequeira <[email protected]>

---------

Signed-off-by: ishitasequeira <[email protected]>
  • Loading branch information
ishitasequeira authored and Hariharasuthan99 committed Jun 16, 2024
1 parent 8f1cc50 commit 3b689ea
Show file tree
Hide file tree
Showing 6 changed files with 548 additions and 249 deletions.
90 changes: 82 additions & 8 deletions cmd/argocd/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,8 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
serverSideGenerate bool
localIncludes []string
appNamespace string
revisions []string
sourceIndexes []int64
)
shortDesc := "Perform a diff against the target and live state."
var command = &cobra.Command{
Expand All @@ -1138,6 +1140,11 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
c.HelpFunc()(c, args)
os.Exit(2)
}

if len(revisions) != len(sourceIndexes) {
errors.CheckError(fmt.Errorf("While using revisions and source-indexes, length of values for both flags should be same."))
}

clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)
Expand All @@ -1156,7 +1163,27 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
argoSettings, err := settingsIf.Get(ctx, &settings.SettingsQuery{})
errors.CheckError(err)
diffOption := &DifferenceOption{}
if revision != "" {
if app.Spec.HasMultipleSources() && len(revisions) > 0 && len(sourceIndexes) > 0 {

revisionSourceMappings := make(map[int64]string, 0)
for i, index := range sourceIndexes {
if index <= 0 {
errors.CheckError(fmt.Errorf("source-index cannot be less than or equal to 0. Index starts at 1."))
}
revisionSourceMappings[index] = revisions[i]
}

q := application.ApplicationManifestQuery{
Name: &appName,
AppNamespace: &appNs,
RevisionSourceMappings: revisionSourceMappings,
}
res, err := appIf.GetManifests(ctx, &q)
errors.CheckError(err)

diffOption.res = res
diffOption.revisionSourceMappings = &revisionSourceMappings
} else if revision != "" {
q := application.ApplicationManifestQuery{
Name: &appName,
Revision: &revision,
Expand Down Expand Up @@ -1206,17 +1233,20 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
command.Flags().BoolVar(&serverSideGenerate, "server-side-generate", false, "Used with --local, this will send your manifests to the server for diffing")
command.Flags().StringArrayVar(&localIncludes, "local-include", []string{"*.yaml", "*.yml", "*.json"}, "Used with --server-side-generate, specify patterns of filenames to send. Matching is based on filename and not path.")
command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only render the difference in namespace")
command.Flags().StringArrayVar(&revisions, "revisions", []string{}, "Show manifests at specific revisions for the index of sources in source-indexes")
command.Flags().Int64SliceVar(&sourceIndexes, "source-indexes", []int64{}, "List of source indexes. Default is empty array. Indexes start at 1.")
return command
}

// DifferenceOption struct to store diff options
type DifferenceOption struct {
local string
localRepoRoot string
revision string
cluster *argoappv1.Cluster
res *repoapiclient.ManifestResponse
serversideRes *repoapiclient.ManifestResponse
local string
localRepoRoot string
revision string
cluster *argoappv1.Cluster
res *repoapiclient.ManifestResponse
serversideRes *repoapiclient.ManifestResponse
revisionSourceMappings *map[int64]string
}

// findandPrintDiff ... Prints difference between application current state and state stored in git or locally, returns boolean as true if difference is found else returns false
Expand All @@ -1228,7 +1258,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, proj *arg
if diffOptions.local != "" {
localObjs := groupObjsByKey(getLocalObjects(ctx, app, proj, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace)
items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace)
} else if diffOptions.revision != "" {
} else if diffOptions.revision != "" || (diffOptions.revisionSourceMappings != nil) {
var unstructureds []*unstructured.Unstructured
for _, mfst := range diffOptions.res.Manifests {
obj, err := argoappv1.UnmarshalToUnstructured(mfst)
Expand Down Expand Up @@ -2708,23 +2738,41 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
var (
source string
revision string
revisions []string
sourceIndexes []int64
local string
localRepoRoot string
)
var command = &cobra.Command{
Use: "manifests APPNAME",
Short: "Print manifests of an application",
Example: templates.Examples(`
# Get manifests for an application
argocd app manifests my-app
# Get manifests for an application at a specific revision
argocd app manifests my-app --revision 0.0.1
# Get manifests for a multi-source application at specific revisions for specific sources
argocd app manifests my-app --revisions 0.0.1 --source-indexes 1 --revisions 0.0.2 --source-indexes 2
`),
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()

if len(args) != 1 {
c.HelpFunc()(c, args)
os.Exit(1)
}

if len(revisions) != len(sourceIndexes) {
errors.CheckError(fmt.Errorf("While using revisions and source-indexes, length of values for both flags should be same."))
}

appName, appNs := argo.ParseFromQualifiedName(args[0], "")
clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)

resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{
ApplicationName: &appName,
AppNamespace: &appNs,
Expand All @@ -2750,6 +2798,30 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob

proj := getProject(c, clientOpts, ctx, app.Spec.Project)
unstructureds = getLocalObjects(context.Background(), app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod)
} else if len(revisions) > 0 && len(sourceIndexes) > 0 {

revisionSourceMappings := make(map[int64]string, 0)
for i, index := range sourceIndexes {
if index <= 0 {
errors.CheckError(fmt.Errorf("source-index cannot be less than or equal to 0, Index starts at 1"))
}
revisionSourceMappings[index] = revisions[i]
}

q := application.ApplicationManifestQuery{
Name: &appName,
AppNamespace: &appNs,
Revision: pointer.String(revision),
RevisionSourceMappings: revisionSourceMappings,
}
res, err := appIf.GetManifests(ctx, &q)
errors.CheckError(err)

for _, mfst := range res.Manifests {
obj, err := argoappv1.UnmarshalToUnstructured(mfst)
errors.CheckError(err)
unstructureds = append(unstructureds, obj)
}
} else if revision != "" {
q := application.ApplicationManifestQuery{
Name: &appName,
Expand Down Expand Up @@ -2787,6 +2859,8 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
}
command.Flags().StringVar(&source, "source", "git", "Source of manifests. One of: live|git")
command.Flags().StringVar(&revision, "revision", "", "Show manifests at a specific revision")
command.Flags().StringArrayVar(&revisions, "revisions", []string{}, "Show manifests at specific revisions for the index of sources in source-indexes")
command.Flags().Int64SliceVar(&sourceIndexes, "source-indexes", []int64{}, "List of source indexes. Default is empty array. Indexes start at 1.")
command.Flags().StringVar(&local, "local", "", "If set, show locally-generated manifests. Value is the absolute path to app manifests within the manifest repo. Example: '/home/username/apps/env/app-1'.")
command.Flags().StringVar(&localRepoRoot, "local-repo-root", ".", "Path to the local repository root. Used together with --local allows setting the repository root. Example: '/home/username/apps'.")
return command
Expand Down
2 changes: 2 additions & 0 deletions docs/user-guide/commands/argocd_app_diff.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ argocd app diff APPNAME [flags]
--local-repo-root string Path to the repository root. Used together with --local allows setting the repository root (default "/")
--refresh Refresh application data when retrieving
--revision string Compare live app to a particular revision
--revisions stringArray Show manifests at specific revisions for the index of sources in source-indexes
--server-side-generate Used with --local, this will send your manifests to the server for diffing
--source-indexes int64Slice List of source indexes. Default is empty array. Indexes start at 1. (default [])
```

### Options inherited from parent commands
Expand Down
25 changes: 20 additions & 5 deletions docs/user-guide/commands/argocd_app_manifests.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,29 @@ Print manifests of an application
argocd app manifests APPNAME [flags]
```

### Examples

```
# Get manifests for an application
argocd app manifests my-app
# Get manifests for an application at a specific revision
argocd app manifests my-app --revision 0.0.1
# Get manifests for a multi-source application at specific revisions for specific sources
argocd app manifests my-app --revisions 0.0.1 --source-indexes 1 --revisions 0.0.2 --source-indexes 2
```

### Options

```
-h, --help help for manifests
--local string If set, show locally-generated manifests. Value is the absolute path to app manifests within the manifest repo. Example: '/home/username/apps/env/app-1'.
--local-repo-root string Path to the local repository root. Used together with --local allows setting the repository root. Example: '/home/username/apps'. (default ".")
--revision string Show manifests at a specific revision
--source string Source of manifests. One of: live|git (default "git")
-h, --help help for manifests
--local string If set, show locally-generated manifests. Value is the absolute path to app manifests within the manifest repo. Example: '/home/username/apps/env/app-1'.
--local-repo-root string Path to the local repository root. Used together with --local allows setting the repository root. Example: '/home/username/apps'. (default ".")
--revision string Show manifests at a specific revision
--revisions stringArray Show manifests at specific revisions for the index of sources in source-indexes
--source string Source of manifests. One of: live|git (default "git")
--source-indexes int64Slice List of source indexes. Default is empty array. Indexes start at 1. (default [])
```

### Options inherited from parent commands
Expand Down
Loading

0 comments on commit 3b689ea

Please sign in to comment.