diff --git a/flux_local/tool/selector.py b/flux_local/tool/selector.py index 5a8f496d..a15bbc74 100644 --- a/flux_local/tool/selector.py +++ b/flux_local/tool/selector.py @@ -44,6 +44,28 @@ def __call__( setattr(namespace, self.dest, result) +class SelectorAppendAction(Action): + """Append a key=value pair to the argument dict.""" + + def __call__( + self, + parser: ArgumentParser, + namespace: Namespace, + values: Any, + option_string: str | None = None, + ) -> None: + values = values.split(",") + if not values[0]: + return + result = getattr(namespace, self.dest) or {} + for value in values: + if "=" not in value: + raise ValueError(f"Expected key=value format but got '{value}'") + k, v = value.split("=") + result[k] = v + setattr(namespace, self.dest, result) + + def add_selector_flags(args: ArgumentParser) -> None: """Add common selector flags to the arguments object.""" args.add_argument( @@ -75,6 +97,12 @@ def add_selector_flags(args: ArgumentParser) -> None: default=DEFAULT_NAMESPACE, help="If present, the namespace scope for this request", ) + args.add_argument( + "--label-selector", + "-l", + action=SelectorAppendAction, + help="Filter objects by label selector by name=value", + ) add_common_flags(args) @@ -135,6 +163,7 @@ def build_ks_selector( # type: ignore[no-untyped-def] selector.kustomization.namespace = kwargs["namespace"] if kwargs["all_namespaces"]: selector.kustomization.namespace = None + selector.kustomization.label_selector = kwargs["label_selector"] selector.kustomization.skip_crds = kwargs["skip_crds"] selector.kustomization.skip_secrets = kwargs["skip_secrets"] return selector @@ -165,6 +194,7 @@ def build_hr_selector( # type: ignore[no-untyped-def] selector.helm_release.namespace = kwargs["namespace"] if kwargs["all_namespaces"]: selector.helm_release.namespace = None + selector.helm_release.label_selector = kwargs["label_selector"] selector.helm_release.skip_crds = kwargs["skip_crds"] selector.helm_release.skip_secrets = kwargs["skip_secrets"] selector.kustomization.name = None @@ -222,6 +252,7 @@ def build_cluster_selector( # type: ignore[no-untyped-def] if kwargs.get("all_namespaces"): selector.cluster.namespace = None selector.kustomization.namespace = None + selector.kustomization.label_selector = kwargs["label_selector"] selector.kustomization.skip_crds = kwargs["skip_crds"] selector.kustomization.skip_secrets = kwargs["skip_secrets"] return selector diff --git a/tests/tool/__snapshots__/test_get_hr.ambr b/tests/tool/__snapshots__/test_get_hr.ambr index c6ef8e28..0e53d3c2 100644 --- a/tests/tool/__snapshots__/test_get_hr.ambr +++ b/tests/tool/__snapshots__/test_get_hr.ambr @@ -74,6 +74,19 @@ ''' # --- +# name: test_get_hr[label-selector-match] + ''' + NAMESPACE NAME REVISION CHART SOURCE + podinfo podinfo 6.3.2 podinfo-podinfo podinfo + + ''' +# --- +# name: test_get_hr[label-selector-no-match] + ''' + no HelmRelease objects found in cluster + + ''' +# --- # name: test_get_hr[name] ''' NAME REVISION CHART SOURCE diff --git a/tests/tool/test_get_hr.py b/tests/tool/test_get_hr.py index bfdbe8ca..ed7e10e1 100644 --- a/tests/tool/test_get_hr.py +++ b/tests/tool/test_get_hr.py @@ -29,6 +29,24 @@ (["metallb", "-A", "--path", "tests/testdata/cluster"]), (["-n", "metallb", "--path", "tests/testdata/cluster"]), (["-A", "--path", "tests/testdata/cluster9/clusters/dev"]), + ( + [ + "-A", + "--path", + "tests/testdata/cluster", + "-l", + "app.kubernetes.io/name=podinfo", + ] + ), + ( + [ + "-A", + "--path", + "tests/testdata/cluster", + "-l", + "app.kubernetes.io/name=kubernetes-dashboard", + ] + ), ], ids=[ "cluster", @@ -42,6 +60,8 @@ "all_namespace", "name", "cluster9", + "label-selector-match", + "label-selector-no-match", ], ) async def test_get_hr(args: list[str], snapshot: SnapshotAssertion) -> None: