From 05499be34cc62c8da82419ae2cfc379380d2bc56 Mon Sep 17 00:00:00 2001 From: Josh Komoroske Date: Mon, 16 Feb 2026 16:55:07 -0500 Subject: [PATCH] feat: argocd application matcher flag --- cmd/command.go | 10 +++++ matcher/matcher-argocd.go | 51 +++++++++++++++++++++++++ matcher/matcher-argocd_test.go | 49 ++++++++++++++++++++++++ matcher/testdata/resources.txt | 2 + matcher/testdata/service.yaml | 2 + matcher/testdata/subdir/deployment.yaml | 1 + 6 files changed, 115 insertions(+) create mode 100644 matcher/matcher-argocd.go create mode 100644 matcher/matcher-argocd_test.go diff --git a/cmd/command.go b/cmd/command.go index 33e082a..afc0c31 100644 --- a/cmd/command.go +++ b/cmd/command.go @@ -69,6 +69,16 @@ func Command() *cobra.Command { //nolint:funlen,maintidx "not-apiversion", "exclude resources by api version") + // Define --argocd flag. + mf.StringSliceMatcher(matcher.NewArgoCDMatcher, + "argocd", + "include resources by ArgoCD application") + + // Define --not-argocd flag. + mf.StringSliceMatcher(matcher.NewArgoCDMatcher, + "not-argocd", + "exclude resources by ArgoCD application") + // Define --cel flag. mf.StringMatcher(matcher.NewCELMatcher, "cel", diff --git a/matcher/matcher-argocd.go b/matcher/matcher-argocd.go new file mode 100644 index 0000000..518ec91 --- /dev/null +++ b/matcher/matcher-argocd.go @@ -0,0 +1,51 @@ +// Copyright Josh Komoroske. All rights reserved. +// Use of this source code is governed by the MIT license, +// a copy of which can be found in the LICENSE.txt file. +// SPDX-License-Identifier: MIT + +package matcher + +import ( + "strings" + + "github.com/gobwas/glob" + + "github.com/joshdk/krf/resources" +) + +// NewArgoCDMatcher matches resources.Resource instances based on the ArgoCD +// Application that the resource is being tracked by. +func NewArgoCDMatcher(selector string) (Matcher, error) { + appGlob, err := glob.Compile(selector) + if err != nil { + return nil, err + } + + m := argocdMatcher{appGlob: appGlob} + + return m, nil +} + +type argocdMatcher struct { + appGlob glob.Glob +} + +func (m argocdMatcher) Matches(item resources.Resource) bool { + value, found := item.GetAnnotations()["argocd.argoproj.io/tracking-id"] + if !found { + return false + } + + // The format of the tracking annotation looks like this: + // :/:/ + // We are interested in the application name, so we look for the location + // of the first ':' character and slice the string up to that point. + index := strings.IndexByte(value, ':') + if index == -1 { + return false + } + + app := value[:index] + + return m.appGlob.Match(app) +} diff --git a/matcher/matcher-argocd_test.go b/matcher/matcher-argocd_test.go new file mode 100644 index 0000000..f838cd6 --- /dev/null +++ b/matcher/matcher-argocd_test.go @@ -0,0 +1,49 @@ +// Copyright Josh Komoroske. All rights reserved. +// Use of this source code is governed by the MIT license, +// a copy of which can be found in the LICENSE.txt file. +// SPDX-License-Identifier: MIT + +package matcher_test + +import ( + "testing" + + "github.com/joshdk/krf/matcher" +) + +func TestArgoCDMatcher(t *testing.T) { + t.Parallel() + + testMatcher(t, []spec{ + { + title: "literal app name", + matcher: must(matcher.NewArgoCDMatcher("app")), + matches: []string{ + "Service/my-service", + }, + }, + { + title: "app name with wildcard suffix", + matcher: must(matcher.NewArgoCDMatcher("app*")), + matches: []string{ + "Deployment/nginx-deployment", + "Service/my-service", + }, + }, + { + title: "wildcard", + matcher: must(matcher.NewArgoCDMatcher("*")), + matches: []string{ + "Deployment/nginx-deployment", + "Service/my-service", + }, + }, + { + title: "wildcard with suffix", + matcher: must(matcher.NewArgoCDMatcher("*-dev")), + matches: []string{ + "Deployment/nginx-deployment", + }, + }, + }) +} diff --git a/matcher/testdata/resources.txt b/matcher/testdata/resources.txt index ea3bd21..5613cdb 100644 --- a/matcher/testdata/resources.txt +++ b/matcher/testdata/resources.txt @@ -31,6 +31,8 @@ metadata: component: api name: my-service namespace: custom-app + annotations: + argocd.argoproj.io/tracking-id: app:/Service:custom-app/my-service spec: ports: - port: 80 diff --git a/matcher/testdata/service.yaml b/matcher/testdata/service.yaml index 3e31bb3..38da042 100644 --- a/matcher/testdata/service.yaml +++ b/matcher/testdata/service.yaml @@ -6,6 +6,8 @@ metadata: labels: app: myapp component: api + annotations: + argocd.argoproj.io/tracking-id: app:/Service:custom-app/my-service spec: selector: app.kubernetes.io/name: myapp diff --git a/matcher/testdata/subdir/deployment.yaml b/matcher/testdata/subdir/deployment.yaml index 2eb447b..a90e3ed 100644 --- a/matcher/testdata/subdir/deployment.yaml +++ b/matcher/testdata/subdir/deployment.yaml @@ -8,6 +8,7 @@ metadata: component: proxy annotations: kubernetes.io/description: proxy + argocd.argoproj.io/tracking-id: app-dev:apps/Deployment:default/nginx-deployment spec: replicas: 3 selector: