From 4133aa93bbccdf5d7f012eae7b8b376f491a738e Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Tue, 28 Jul 2026 13:47:39 +1200 Subject: [PATCH 1/7] fix: paginate ListChannelReleases to find versions beyond first page --- pkg/kotsclient/channel.go | 18 +++++++- pkg/kotsclient/channel_test.go | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 pkg/kotsclient/channel_test.go diff --git a/pkg/kotsclient/channel.go b/pkg/kotsclient/channel.go index b2162f525..37e2b2dc3 100644 --- a/pkg/kotsclient/channel.go +++ b/pkg/kotsclient/channel.go @@ -155,7 +155,23 @@ func (c *VendorV3Client) UnDemoteChannelRelease(appID string, channelID string, } func (c *VendorV3Client) ListChannelReleases(appID string, channelID string, includeInstallerImages string) ([]*types.ChannelRelease, error) { - return c.ListChannelReleasesPaged(appID, channelID, includeInstallerImages, 0, 0) + allReleases := []*types.ChannelRelease{} + page := 0 + pageSize := 20 + + for { + releases, err := c.ListChannelReleasesPaged(appID, channelID, includeInstallerImages, page, pageSize) + if err != nil { + return nil, err + } + allReleases = append(allReleases, releases...) + if len(releases) < pageSize { + break + } + page += 1 + } + + return allReleases, nil } func (c *VendorV3Client) ListChannelReleasesPaged(appID string, channelID string, includeInstallerImages string, page int, pageSize int) ([]*types.ChannelRelease, error) { diff --git a/pkg/kotsclient/channel_test.go b/pkg/kotsclient/channel_test.go new file mode 100644 index 000000000..6ebf72b27 --- /dev/null +++ b/pkg/kotsclient/channel_test.go @@ -0,0 +1,84 @@ +package kotsclient + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/replicatedhq/replicated/pkg/platformclient" + "github.com/replicatedhq/replicated/pkg/types" + "github.com/stretchr/testify/require" +) + +func TestListChannelReleases_Pagination(t *testing.T) { + pageCount := 0 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/v3/app/app-id/channel/channel-id/releases", r.URL.Path) + require.Equal(t, "test-token", r.Header.Get("Authorization")) + + page := r.URL.Query().Get("currentPage") + pageSize := r.URL.Query().Get("pageSize") + require.Equal(t, "20", pageSize) + pageCount += 1 + + releases := []types.ChannelRelease{} + switch page { + case "0": + for i := 0; i < 20; i++ { + releases = append(releases, types.ChannelRelease{Semver: "1.0.0"}) + } + case "1": + releases = append(releases, types.ChannelRelease{Semver: "2.17.12"}) + default: + // Empty page signals end of results + } + + _ = json.NewEncoder(w).Encode(map[string]interface{}{ + "releases": releases, + }) + })) + defer server.Close() + + api := platformclient.NewHTTPClient(server.URL, "test-token") + client := VendorV3Client{HTTPClient: *api} + + releases, err := client.ListChannelReleases("app-id", "channel-id", "") + require.NoError(t, err) + require.Len(t, releases, 21) + require.Equal(t, "2.17.12", releases[20].Semver) + require.Equal(t, 2, pageCount) +} + +func TestListChannelReleases_Pagination_ExactPageSize(t *testing.T) { + pageCount := 0 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/v3/app/app-id/channel/channel-id/releases", r.URL.Path) + + page := r.URL.Query().Get("currentPage") + pageCount += 1 + + releases := []types.ChannelRelease{} + switch page { + case "0", "1": + for i := 0; i < 20; i++ { + releases = append(releases, types.ChannelRelease{Semver: "1.0.0"}) + } + default: + // Empty page signals end of results + } + + _ = json.NewEncoder(w).Encode(map[string]interface{}{ + "releases": releases, + }) + })) + defer server.Close() + + api := platformclient.NewHTTPClient(server.URL, "test-token") + client := VendorV3Client{HTTPClient: *api} + + releases, err := client.ListChannelReleases("app-id", "channel-id", "") + require.NoError(t, err) + require.Len(t, releases, 40) + require.Equal(t, 3, pageCount) +} From e993f5981b2413a8bcae184f590b28c5df8171e4 Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Tue, 28 Jul 2026 13:57:59 +1200 Subject: [PATCH 2/7] fix: use versionLabel API filter for release image ls --version --- cli/cmd/release_image_ls.go | 18 +++++++++++++++--- client/channel.go | 9 +++++++++ pkg/kotsclient/channel.go | 28 ++++++++++++++++++++++++++++ pkg/kotsclient/channel_test.go | 24 ++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/cli/cmd/release_image_ls.go b/cli/cmd/release_image_ls.go index 6513a1e1a..f8a3cb673 100644 --- a/cli/cmd/release_image_ls.go +++ b/cli/cmd/release_image_ls.go @@ -64,15 +64,27 @@ func (r *runners) releaseImageLS(cmd *cobra.Command, args []string) error { var proxyDomain string if r.args.releaseImageLSVersion != "" { - // For specific versions, we need to get all releases - channelReleases, err := r.api.ListChannelReleases(r.appID, r.appType, channel.ID, r.args.releaseImageLSIncludeInstallerImages) + // For specific versions, try the server-side versionLabel filter first. + // This avoids downloading every page of a large channel history. + channelReleases, err := r.api.ListChannelReleasesByVersion(r.appID, r.appType, channel.ID, r.args.releaseImageLSVersion, r.args.releaseImageLSIncludeInstallerImages) if err != nil { return fmt.Errorf("failed to list channel releases: %w", err) } targetRelease, err = findTargetRelease(channelReleases, r.args.releaseImageLSVersion) if err != nil { - return err + // The versionLabel filter may not match when the version label differs + // from the semver. Fall back to listing all releases and searching by + // semver to preserve the previous behavior in those edge cases. + channelReleases, err = r.api.ListChannelReleases(r.appID, r.appType, channel.ID, r.args.releaseImageLSIncludeInstallerImages) + if err != nil { + return fmt.Errorf("failed to list channel releases: %w", err) + } + + targetRelease, err = findTargetRelease(channelReleases, r.args.releaseImageLSVersion) + if err != nil { + return err + } } // Get proxy domain for version-specific releases diff --git a/client/channel.go b/client/channel.go index bb929cba6..9d8889894 100644 --- a/client/channel.go +++ b/client/channel.go @@ -206,6 +206,15 @@ func (c *Client) ListChannelReleasesPaged(appID string, appType string, channelI return nil, errors.Errorf("unknown app type %q", appType) } +func (c *Client) ListChannelReleasesByVersion(appID string, appType string, channelID string, versionLabel string, includeInstallerImages string) ([]*types.ChannelRelease, error) { + if appType == "platform" { + return nil, errors.New("This feature is not currently supported for Platform applications.") + } else if appType == "kots" { + return c.KotsClient.ListChannelReleasesByVersion(appID, channelID, versionLabel, includeInstallerImages) + } + return nil, errors.Errorf("unknown app type %q", appType) +} + func (c *Client) GetCustomHostnames(appID string, appType string, channelID string) (*types.CustomHostNameOverrides, error) { if appType == "platform" { return nil, errors.New("This feature is not currently supported for Platform applications.") diff --git a/pkg/kotsclient/channel.go b/pkg/kotsclient/channel.go index 37e2b2dc3..2b7e109fd 100644 --- a/pkg/kotsclient/channel.go +++ b/pkg/kotsclient/channel.go @@ -174,6 +174,34 @@ func (c *VendorV3Client) ListChannelReleases(appID string, channelID string, inc return allReleases, nil } +func (c *VendorV3Client) ListChannelReleasesByVersion(appID string, channelID string, versionLabel string, includeInstallerImages string) ([]*types.ChannelRelease, error) { + type listChannelReleasesResponse struct { + Releases []*types.ChannelRelease `json:"releases"` + } + + response := listChannelReleasesResponse{} + v := url.Values{} + v.Set("versionLabel", versionLabel) + if includeInstallerImages != "" { + v.Set("includeInstallerImages", includeInstallerImages) + } + // A versionLabel filter should return a small number of releases, so a + // single page is sufficient. This avoids the cost of paginating through a + // large channel history when looking for a specific version. + v.Set("pageSize", "20") + + reqURL := fmt.Sprintf("/v3/app/%s/channel/%s/releases", appID, url.QueryEscape(channelID)) + if encoded := v.Encode(); encoded != "" { + reqURL = fmt.Sprintf("%s?%s", reqURL, encoded) + } + err := c.DoJSON(context.TODO(), "GET", reqURL, http.StatusOK, nil, &response) + if err != nil { + return nil, errors.Wrap(err, "list channel releases by version") + } + + return response.Releases, nil +} + func (c *VendorV3Client) ListChannelReleasesPaged(appID string, channelID string, includeInstallerImages string, page int, pageSize int) ([]*types.ChannelRelease, error) { type listChannelReleasesResponse struct { Releases []*types.ChannelRelease `json:"releases"` diff --git a/pkg/kotsclient/channel_test.go b/pkg/kotsclient/channel_test.go index 6ebf72b27..729f12758 100644 --- a/pkg/kotsclient/channel_test.go +++ b/pkg/kotsclient/channel_test.go @@ -82,3 +82,27 @@ func TestListChannelReleases_Pagination_ExactPageSize(t *testing.T) { require.Len(t, releases, 40) require.Equal(t, 3, pageCount) } + +func TestListChannelReleasesByVersion(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/v3/app/app-id/channel/channel-id/releases", r.URL.Path) + require.Equal(t, "test-token", r.Header.Get("Authorization")) + require.Equal(t, "2.17.12", r.URL.Query().Get("versionLabel")) + require.Equal(t, "20", r.URL.Query().Get("pageSize")) + + _ = json.NewEncoder(w).Encode(map[string]interface{}{ + "releases": []types.ChannelRelease{ + {Semver: "2.17.12"}, + }, + }) + })) + defer server.Close() + + api := platformclient.NewHTTPClient(server.URL, "test-token") + client := VendorV3Client{HTTPClient: *api} + + releases, err := client.ListChannelReleasesByVersion("app-id", "channel-id", "2.17.12", "") + require.NoError(t, err) + require.Len(t, releases, 1) + require.Equal(t, "2.17.12", releases[0].Semver) +} From ccca4a10a2222132cb90135fa53c4fa7ccb3cb09 Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Tue, 28 Jul 2026 14:17:31 +1200 Subject: [PATCH 3/7] fix: address review feedback on release image ls pagination --- cli/cmd/release_image_ls.go | 38 ++++++++++++++++++---------------- pkg/kotsclient/channel.go | 16 ++++++-------- pkg/kotsclient/channel_test.go | 2 +- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/cli/cmd/release_image_ls.go b/cli/cmd/release_image_ls.go index f8a3cb673..20c356a56 100644 --- a/cli/cmd/release_image_ls.go +++ b/cli/cmd/release_image_ls.go @@ -66,25 +66,9 @@ func (r *runners) releaseImageLS(cmd *cobra.Command, args []string) error { if r.args.releaseImageLSVersion != "" { // For specific versions, try the server-side versionLabel filter first. // This avoids downloading every page of a large channel history. - channelReleases, err := r.api.ListChannelReleasesByVersion(r.appID, r.appType, channel.ID, r.args.releaseImageLSVersion, r.args.releaseImageLSIncludeInstallerImages) + targetRelease, err = r.findReleaseByVersion(channel.ID, r.args.releaseImageLSVersion) if err != nil { - return fmt.Errorf("failed to list channel releases: %w", err) - } - - targetRelease, err = findTargetRelease(channelReleases, r.args.releaseImageLSVersion) - if err != nil { - // The versionLabel filter may not match when the version label differs - // from the semver. Fall back to listing all releases and searching by - // semver to preserve the previous behavior in those edge cases. - channelReleases, err = r.api.ListChannelReleases(r.appID, r.appType, channel.ID, r.args.releaseImageLSIncludeInstallerImages) - if err != nil { - return fmt.Errorf("failed to list channel releases: %w", err) - } - - targetRelease, err = findTargetRelease(channelReleases, r.args.releaseImageLSVersion) - if err != nil { - return err - } + return err } // Get proxy domain for version-specific releases @@ -185,6 +169,24 @@ func cleanImageName(image string, proxyRegistryDomain string) string { return cleaned } +// findReleaseByVersion tries the API's versionLabel filter first, and falls back +// to listing all releases when the filter errors or returns no semver match. +func (r *runners) findReleaseByVersion(channelID string, version string) (*types.ChannelRelease, error) { + filteredReleases, err := r.api.ListChannelReleasesByVersion(r.appID, r.appType, channelID, version, r.args.releaseImageLSIncludeInstallerImages) + if err == nil { + if release, err := findTargetRelease(filteredReleases, version); err == nil { + return release, nil + } + } + + // Fallback: list all releases and search by semver. + allReleases, err := r.api.ListChannelReleases(r.appID, r.appType, channelID, r.args.releaseImageLSIncludeInstallerImages) + if err != nil { + return nil, fmt.Errorf("failed to list channel releases: %w", err) + } + return findTargetRelease(allReleases, version) +} + // findTargetRelease finds the target release from a list of releases // If requestedVersion is empty, returns the current release (highest channel sequence) // If requestedVersion is specified, returns the release with matching semver diff --git a/pkg/kotsclient/channel.go b/pkg/kotsclient/channel.go index 2b7e109fd..e0f4c8fc6 100644 --- a/pkg/kotsclient/channel.go +++ b/pkg/kotsclient/channel.go @@ -15,6 +15,10 @@ type ListChannelsResponse struct { Channels []*types.KotsChannel `json:"channels"` } +type listChannelReleasesResponse struct { + Releases []*types.ChannelRelease `json:"releases"` +} + func (c *VendorV3Client) ListKotsChannels(appID string, channelName string, excludeDetails bool) ([]*types.KotsChannel, error) { var response = ListChannelsResponse{} v := url.Values{} @@ -164,10 +168,10 @@ func (c *VendorV3Client) ListChannelReleases(appID string, channelID string, inc if err != nil { return nil, err } - allReleases = append(allReleases, releases...) - if len(releases) < pageSize { + if len(releases) == 0 { break } + allReleases = append(allReleases, releases...) page += 1 } @@ -175,10 +179,6 @@ func (c *VendorV3Client) ListChannelReleases(appID string, channelID string, inc } func (c *VendorV3Client) ListChannelReleasesByVersion(appID string, channelID string, versionLabel string, includeInstallerImages string) ([]*types.ChannelRelease, error) { - type listChannelReleasesResponse struct { - Releases []*types.ChannelRelease `json:"releases"` - } - response := listChannelReleasesResponse{} v := url.Values{} v.Set("versionLabel", versionLabel) @@ -203,10 +203,6 @@ func (c *VendorV3Client) ListChannelReleasesByVersion(appID string, channelID st } func (c *VendorV3Client) ListChannelReleasesPaged(appID string, channelID string, includeInstallerImages string, page int, pageSize int) ([]*types.ChannelRelease, error) { - type listChannelReleasesResponse struct { - Releases []*types.ChannelRelease `json:"releases"` - } - response := listChannelReleasesResponse{} v := url.Values{} if includeInstallerImages != "" { diff --git a/pkg/kotsclient/channel_test.go b/pkg/kotsclient/channel_test.go index 729f12758..1a1d4b6a8 100644 --- a/pkg/kotsclient/channel_test.go +++ b/pkg/kotsclient/channel_test.go @@ -47,7 +47,7 @@ func TestListChannelReleases_Pagination(t *testing.T) { require.NoError(t, err) require.Len(t, releases, 21) require.Equal(t, "2.17.12", releases[20].Semver) - require.Equal(t, 2, pageCount) + require.Equal(t, 3, pageCount) } func TestListChannelReleases_Pagination_ExactPageSize(t *testing.T) { From 801312ae1513921fea8c88fc4b6d20940b4de4c9 Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Wed, 29 Jul 2026 17:50:43 +1200 Subject: [PATCH 4/7] fix: remove fallback release search and findTargetRelease helper --- cli/cmd/release_image_ls.go | 52 +++----------------------- cli/cmd/release_image_ls_test.go | 64 -------------------------------- 2 files changed, 6 insertions(+), 110 deletions(-) diff --git a/cli/cmd/release_image_ls.go b/cli/cmd/release_image_ls.go index 20c356a56..2558e234a 100644 --- a/cli/cmd/release_image_ls.go +++ b/cli/cmd/release_image_ls.go @@ -169,56 +169,16 @@ func cleanImageName(image string, proxyRegistryDomain string) string { return cleaned } -// findReleaseByVersion tries the API's versionLabel filter first, and falls back -// to listing all releases when the filter errors or returns no semver match. +// findReleaseByVersion returns the channel release matching the requested version. +// ListChannelReleasesByVersion uses a server-side versionLabel filter and returns +// matching releases sorted by channel sequence, so the first result is the target. func (r *runners) findReleaseByVersion(channelID string, version string) (*types.ChannelRelease, error) { - filteredReleases, err := r.api.ListChannelReleasesByVersion(r.appID, r.appType, channelID, version, r.args.releaseImageLSIncludeInstallerImages) - if err == nil { - if release, err := findTargetRelease(filteredReleases, version); err == nil { - return release, nil - } - } - - // Fallback: list all releases and search by semver. - allReleases, err := r.api.ListChannelReleases(r.appID, r.appType, channelID, r.args.releaseImageLSIncludeInstallerImages) + releases, err := r.api.ListChannelReleasesByVersion(r.appID, r.appType, channelID, version, r.args.releaseImageLSIncludeInstallerImages) if err != nil { return nil, fmt.Errorf("failed to list channel releases: %w", err) } - return findTargetRelease(allReleases, version) -} - -// findTargetRelease finds the target release from a list of releases -// If requestedVersion is empty, returns the current release (highest channel sequence) -// If requestedVersion is specified, returns the release with matching semver -func findTargetRelease(releases []*types.ChannelRelease, requestedVersion string) (*types.ChannelRelease, error) { if len(releases) == 0 { - return nil, errors.New("no releases found in channel") + return nil, fmt.Errorf("no release found with version %q in channel", version) } - - var targetRelease *types.ChannelRelease - - if requestedVersion != "" { - // Find release by semver - for _, release := range releases { - if release.Semver == requestedVersion { - targetRelease = release - break - } - } - if targetRelease == nil { - return nil, fmt.Errorf("no release found with version %q in channel", requestedVersion) - } - } else { - // Find the current release (highest channel sequence) - for _, release := range releases { - if targetRelease == nil || release.ChannelSequence > targetRelease.ChannelSequence { - targetRelease = release - } - } - if targetRelease == nil { - return nil, errors.New("no current release found") - } - } - - return targetRelease, nil + return releases[0], nil } diff --git a/cli/cmd/release_image_ls_test.go b/cli/cmd/release_image_ls_test.go index 05454370c..6973648a9 100644 --- a/cli/cmd/release_image_ls_test.go +++ b/cli/cmd/release_image_ls_test.go @@ -3,7 +3,6 @@ package cmd import ( "testing" - "github.com/replicatedhq/replicated/pkg/types" "github.com/stretchr/testify/assert" ) @@ -78,67 +77,4 @@ func TestCleanImageName(t *testing.T) { } } -func TestFindTargetRelease(t *testing.T) { - tests := []struct { - name string - releases []*types.ChannelRelease - requestedVersion string - expectedSequence int32 - expectError bool - errorMsg string - }{ - { - name: "find current release (highest channel sequence)", - releases: []*types.ChannelRelease{ - {ChannelSequence: 5, Semver: "1.0.0"}, - {ChannelSequence: 10, Semver: "1.1.0"}, - {ChannelSequence: 8, Semver: "1.0.5"}, - }, - requestedVersion: "", - expectedSequence: 10, - }, - { - name: "find specific version", - releases: []*types.ChannelRelease{ - {ChannelSequence: 5, Semver: "1.0.0"}, - {ChannelSequence: 10, Semver: "1.1.0"}, - {ChannelSequence: 8, Semver: "1.0.5"}, - }, - requestedVersion: "1.0.5", - expectedSequence: 8, - }, - { - name: "version not found", - releases: []*types.ChannelRelease{ - {ChannelSequence: 5, Semver: "1.0.0"}, - {ChannelSequence: 10, Semver: "1.1.0"}, - }, - requestedVersion: "2.0.0", - expectError: true, - errorMsg: "no release found with version \"2.0.0\"", - }, - { - name: "no releases", - releases: []*types.ChannelRelease{}, - requestedVersion: "", - expectError: true, - errorMsg: "no releases found in channel", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - targetRelease, err := findTargetRelease(tt.releases, tt.requestedVersion) - if tt.expectError { - assert.Error(t, err) - assert.Contains(t, err.Error(), tt.errorMsg) - assert.Nil(t, targetRelease) - } else { - assert.NoError(t, err) - assert.NotNil(t, targetRelease) - assert.Equal(t, tt.expectedSequence, targetRelease.ChannelSequence) - } - }) - } -} From fce77d64687006e671ab609fafaf1cd48578d4b2 Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Thu, 30 Jul 2026 07:54:07 +1200 Subject: [PATCH 5/7] fix: remove redundant ListChannelReleases pagination unit tests --- pkg/kotsclient/channel_test.go | 72 ---------------------------------- 1 file changed, 72 deletions(-) diff --git a/pkg/kotsclient/channel_test.go b/pkg/kotsclient/channel_test.go index 1a1d4b6a8..d9599da5a 100644 --- a/pkg/kotsclient/channel_test.go +++ b/pkg/kotsclient/channel_test.go @@ -11,78 +11,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestListChannelReleases_Pagination(t *testing.T) { - pageCount := 0 - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/v3/app/app-id/channel/channel-id/releases", r.URL.Path) - require.Equal(t, "test-token", r.Header.Get("Authorization")) - - page := r.URL.Query().Get("currentPage") - pageSize := r.URL.Query().Get("pageSize") - require.Equal(t, "20", pageSize) - pageCount += 1 - - releases := []types.ChannelRelease{} - switch page { - case "0": - for i := 0; i < 20; i++ { - releases = append(releases, types.ChannelRelease{Semver: "1.0.0"}) - } - case "1": - releases = append(releases, types.ChannelRelease{Semver: "2.17.12"}) - default: - // Empty page signals end of results - } - - _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "releases": releases, - }) - })) - defer server.Close() - - api := platformclient.NewHTTPClient(server.URL, "test-token") - client := VendorV3Client{HTTPClient: *api} - - releases, err := client.ListChannelReleases("app-id", "channel-id", "") - require.NoError(t, err) - require.Len(t, releases, 21) - require.Equal(t, "2.17.12", releases[20].Semver) - require.Equal(t, 3, pageCount) -} - -func TestListChannelReleases_Pagination_ExactPageSize(t *testing.T) { - pageCount := 0 - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/v3/app/app-id/channel/channel-id/releases", r.URL.Path) - - page := r.URL.Query().Get("currentPage") - pageCount += 1 - - releases := []types.ChannelRelease{} - switch page { - case "0", "1": - for i := 0; i < 20; i++ { - releases = append(releases, types.ChannelRelease{Semver: "1.0.0"}) - } - default: - // Empty page signals end of results - } - - _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "releases": releases, - }) - })) - defer server.Close() - - api := platformclient.NewHTTPClient(server.URL, "test-token") - client := VendorV3Client{HTTPClient: *api} - - releases, err := client.ListChannelReleases("app-id", "channel-id", "") - require.NoError(t, err) - require.Len(t, releases, 40) - require.Equal(t, 3, pageCount) -} - func TestListChannelReleasesByVersion(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, "/v3/app/app-id/channel/channel-id/releases", r.URL.Path) From b2d1ded6fa264f929c886b942b71ced0f6f6559b Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Thu, 30 Jul 2026 08:02:36 +1200 Subject: [PATCH 6/7] fix: simplify prefix stripping to resolve staticcheck S1017 --- cli/cmd/release_image_ls.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/cmd/release_image_ls.go b/cli/cmd/release_image_ls.go index 2558e234a..1f70badd3 100644 --- a/cli/cmd/release_image_ls.go +++ b/cli/cmd/release_image_ls.go @@ -161,9 +161,7 @@ func cleanImageName(image string, proxyRegistryDomain string) string { } for _, prefix := range prefixes { - if strings.HasPrefix(cleaned, prefix) { - cleaned = strings.TrimPrefix(cleaned, prefix) - } + cleaned = strings.TrimPrefix(cleaned, prefix) } return cleaned From 0c944481fcf2654ec2aa2acfeab7eec02e5cdc10 Mon Sep 17 00:00:00 2001 From: Xav Pa Date: Thu, 30 Jul 2026 08:09:27 +1200 Subject: [PATCH 7/7] fix: gofmt cleanup trailing blank lines in release_image_ls_test.go --- cli/cmd/release_image_ls_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/cmd/release_image_ls_test.go b/cli/cmd/release_image_ls_test.go index 6973648a9..cb76f07f1 100644 --- a/cli/cmd/release_image_ls_test.go +++ b/cli/cmd/release_image_ls_test.go @@ -76,5 +76,3 @@ func TestCleanImageName(t *testing.T) { }) } } - -