From d8a012676eebe11cce4db8a7bc23793a02272e68 Mon Sep 17 00:00:00 2001 From: "Chris (ChrisJr404)" <11917633+ChrisJr404@users.noreply.github.com> Date: Mon, 17 Aug 2026 22:46:55 -0400 Subject: [PATCH 1/3] feat: add --name filter to store list The ListStores API already accepts a name filter, so wire it up on the CLI. Adds a --name flag to fga store list and passes it through as Name on ClientListStoresOptions. Only set when non-empty so existing behavior is unchanged. Closes #552 Signed-off-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com> --- README.md | 1 + cmd/store/list.go | 13 +++++++++++-- cmd/store/list_test.go | 42 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9dd7f4fd..ab202bb8 100644 --- a/README.md +++ b/README.md @@ -364,6 +364,7 @@ fga store **list** ###### Parameters * `--max-pages`: Max number of pages to retrieve (default: 20) +* `--name`: Filter stores by name ###### Example `fga store list` diff --git a/cmd/store/list.go b/cmd/store/list.go index 8d7a92b4..0df14f67 100644 --- a/cmd/store/list.go +++ b/cmd/store/list.go @@ -31,7 +31,7 @@ import ( // MaxStoresPagesLength Limit the pages of stores so that we are not paginating indefinitely. var MaxStoresPagesLength = 20 // up to 1000 records -func listStores(ctx context.Context, fgaClient client.SdkClient, maxPages int) (*openfga.ListStoresResponse, error) { +func listStores(ctx context.Context, fgaClient client.SdkClient, maxPages int, name string) (*openfga.ListStoresResponse, error) { stores := []openfga.Store{} continuationToken := "" pageIndex := 0 @@ -40,6 +40,9 @@ func listStores(ctx context.Context, fgaClient client.SdkClient, maxPages int) ( options := client.ClientListStoresOptions{ ContinuationToken: &continuationToken, } + if name != "" { + options.Name = &name + } response, err := fgaClient.ListStores(ctx).Options(options).Execute() if err != nil { @@ -78,7 +81,12 @@ var listCmd = &cobra.Command{ return fmt.Errorf("failed to parse max pages due to %w", err) } - response, err := listStores(cmd.Context(), fgaClient, maxPages) + name, err := cmd.Flags().GetString("name") + if err != nil { + return fmt.Errorf("failed to parse name due to %w", err) + } + + response, err := listStores(cmd.Context(), fgaClient, maxPages, name) if err != nil { return err } @@ -89,4 +97,5 @@ var listCmd = &cobra.Command{ func init() { listCmd.Flags().Int("max-pages", MaxStoresPagesLength, "Max number of pages to get.") + listCmd.Flags().String("name", "", "Filter stores by name.") } diff --git a/cmd/store/list_test.go b/cmd/store/list_test.go index a697a9ea..540946fc 100644 --- a/cmd/store/list_test.go +++ b/cmd/store/list_test.go @@ -36,7 +36,7 @@ func TestListStoresError(t *testing.T) { mockRequest.EXPECT().Options(options).Return(mockExecute) mockFgaClient.EXPECT().ListStores(t.Context()).Return(mockRequest) - _, err := listStores(t.Context(), mockFgaClient, 5) + _, err := listStores(t.Context(), mockFgaClient, 5, "") if err == nil { t.Error("Expect error but there is none") } @@ -67,7 +67,7 @@ func TestListStoresEmpty(t *testing.T) { mockRequest.EXPECT().Options(options).Return(mockExecute) mockFgaClient.EXPECT().ListStores(t.Context()).Return(mockRequest) - output, err := listStores(t.Context(), mockFgaClient, 5) + output, err := listStores(t.Context(), mockFgaClient, 5, "") if err != nil { t.Error(err) } @@ -118,7 +118,7 @@ func TestListStoresSinglePage(t *testing.T) { mockRequest.EXPECT().Options(options).Return(mockExecute) mockFgaClient.EXPECT().ListStores(t.Context()).Return(mockRequest) - output, err := listStores(t.Context(), mockFgaClient, 5) + output, err := listStores(t.Context(), mockFgaClient, 5, "") if err != nil { t.Error(err) } @@ -202,7 +202,7 @@ func TestListStoresMultiPage(t *testing.T) { mockFgaClient.EXPECT().ListStores(t.Context()).Return(mockRequest2), ) - output, err := listStores(t.Context(), mockFgaClient, 5) + output, err := listStores(t.Context(), mockFgaClient, 5, "") if err != nil { t.Error(err) } @@ -256,7 +256,7 @@ func TestListStoresMultiPageMaxPage(t *testing.T) { mockRequest1.EXPECT().Options(options1).Return(mockExecute1) mockFgaClient.EXPECT().ListStores(t.Context()).Return(mockRequest1) - output, err := listStores(t.Context(), mockFgaClient, 1) + output, err := listStores(t.Context(), mockFgaClient, 1, "") if err != nil { t.Error(err) } @@ -272,3 +272,35 @@ func TestListStoresMultiPageMaxPage(t *testing.T) { t.Errorf("Expected output %v actual %v", expectedOutput, string(outputTxt)) } } + +func TestListStoresWithName(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + const storeName = "my-store" + + mockFgaClient := mockclient.NewMockSdkClient(mockCtrl) + + mockExecute := mockclient.NewMockSdkClientListStoresRequestInterface(mockCtrl) + + response := openfga.ListStoresResponse{ + Stores: []openfga.Store{}, + ContinuationToken: "", + } + mockExecute.EXPECT().Execute().Return(&response, nil) + + mockRequest := mockclient.NewMockSdkClientListStoresRequestInterface(mockCtrl) + options := client.ClientListStoresOptions{ + ContinuationToken: openfga.PtrString(""), + Name: openfga.PtrString(storeName), + } + mockRequest.EXPECT().Options(options).Return(mockExecute) + mockFgaClient.EXPECT().ListStores(t.Context()).Return(mockRequest) + + _, err := listStores(t.Context(), mockFgaClient, 5, storeName) + if err != nil { + t.Error(err) + } +} From f293ebec8b4247dfc4c756db210030c58eaf07bc Mon Sep 17 00:00:00 2001 From: "Chris (ChrisJr404)" <11917633+ChrisJr404@users.noreply.github.com> Date: Tue, 18 Aug 2026 13:36:07 -0400 Subject: [PATCH 2/3] cmd/store: wrap listStores signature under the 120-col line limit Signed-off-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com> --- cmd/store/list.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/store/list.go b/cmd/store/list.go index 0df14f67..36e37a16 100644 --- a/cmd/store/list.go +++ b/cmd/store/list.go @@ -31,7 +31,12 @@ import ( // MaxStoresPagesLength Limit the pages of stores so that we are not paginating indefinitely. var MaxStoresPagesLength = 20 // up to 1000 records -func listStores(ctx context.Context, fgaClient client.SdkClient, maxPages int, name string) (*openfga.ListStoresResponse, error) { +func listStores( + ctx context.Context, + fgaClient client.SdkClient, + maxPages int, + name string, +) (*openfga.ListStoresResponse, error) { stores := []openfga.Store{} continuationToken := "" pageIndex := 0 From 157e5336baa0dbae80b8be0afaaf91864f5feeee Mon Sep 17 00:00:00 2001 From: "Chris (ChrisJr404)" <11917633+ChrisJr404@users.noreply.github.com> Date: Thu, 20 Aug 2026 10:03:25 -0400 Subject: [PATCH 3/3] clarify --name filters by exact store name and document it --- README.md | 6 ++++-- cmd/store/list.go | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ab202bb8..f792eecf 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ custom-headers: | [Create a Store](#create-store) | `create` | `--name` | `fga store create --name="FGA Demo Store"` | | [Import a Store](#import-store) | `import` | `--file` | `fga store import --file store.fga.yaml` | | [Export a Store](#export-store) | `export` | `--store-id` | `fga store export --store-id=01H0H015178Y2V4CX10C2KGHF4` | -| [List Stores](#list-stores) | `list` | | `fga store list` | +| [List Stores](#list-stores) | `list` | `--name` | `fga store list --name="FGA Demo Store"` | | [Get a Store](#get-store) | `get` | `--store-id` | `fga store get --store-id=01H0H015178Y2V4CX10C2KGHF4` | | [Delete a Store](#delete-store) | `delete` | `--store-id` | `fga store delete --store-id=01H0H015178Y2V4CX10C2KGHF4` | @@ -364,11 +364,13 @@ fga store **list** ###### Parameters * `--max-pages`: Max number of pages to retrieve (default: 20) -* `--name`: Filter stores by name +* `--name`: Filter stores by exact name (substrings and regexes are not supported) ###### Example `fga store list` +`fga store list --name="FGA Demo Store"` + ###### Response ```json { diff --git a/cmd/store/list.go b/cmd/store/list.go index 36e37a16..40e87d75 100644 --- a/cmd/store/list.go +++ b/cmd/store/list.go @@ -102,5 +102,5 @@ var listCmd = &cobra.Command{ func init() { listCmd.Flags().Int("max-pages", MaxStoresPagesLength, "Max number of pages to get.") - listCmd.Flags().String("name", "", "Filter stores by name.") + listCmd.Flags().String("name", "", "Filter stores by exact name. Substrings and regexes are not supported.") }