Skip to content

Commit 714af62

Browse files
committed
refactor: read the instance version through api.ServerVersion
The merge brought in `api.ServerVersion`, added by #86 for the same purpose, so the version lookup added here was a second one in the same package. Uses the shared function instead, which also stops going through the 301 that `/version` (no trailing slash) answers with. Adopts its rule about the tag, too: an instance reporting "latest" or a commit sha now has its tag left out of the message rather than quoted back as though it were a version. Nothing here rests on the tag — the 404 already established the endpoint is absent — so it only decides whether the version can be named, where `login` has to stay silent entirely because it is inferring age. Dropped the `package_versions` fallback with it: it would be a change to what `login` gates on, which wants deciding on its own terms.
1 parent ceb54b2 commit 714af62

3 files changed

Lines changed: 43 additions & 24 deletions

File tree

internal/api/client.go

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import (
1313
"strconv"
1414
"strings"
1515

16-
"github.com/Flagsmith/flagsmith-cli/v2/internal/bug"
16+
"github.com/blang/semver/v4"
1717

18+
"github.com/Flagsmith/flagsmith-cli/v2/internal/bug"
1819
"github.com/Flagsmith/flagsmith-cli/v2/internal/httpx"
1920
"github.com/Flagsmith/flagsmith-cli/v2/internal/version"
2021
)
@@ -990,36 +991,28 @@ func (c *Client) classifyFlagWrite(ctx context.Context, err error) error {
990991

991992
// unsupportedFlagWrite names the instance's version in the error when it can be
992993
// read, since "upgrade" is easier to act on knowing what you're upgrading from.
993-
// The lookup only happens on this failure path, and its own failure just leaves
994-
// the version out.
994+
// The lookup only happens on this failure path.
995+
//
996+
// A tag that is not a version ("latest", a commit sha) is left out rather than
997+
// quoted back: unlike the inference in `login`, nothing here rests on it — the
998+
// 404 already established the endpoint is absent — so it only decides whether
999+
// the version can be named.
9951000
func (c *Client) unsupportedFlagWrite(ctx context.Context) error {
996-
if version, err := c.ServerVersion(ctx); err == nil && version != "" {
997-
return fmt.Errorf("%w: this instance runs %s", ErrFlagWritesUnsupported, version)
1001+
tag, err := ServerVersion(ctx, c.httpClient, c.baseURL)
1002+
if err != nil {
1003+
return ErrFlagWritesUnsupported
1004+
}
1005+
if _, err := semver.ParseTolerant(tag); err != nil {
1006+
return ErrFlagWritesUnsupported
9981007
}
999-
return ErrFlagWritesUnsupported
1008+
return fmt.Errorf("%w: this instance runs %s", ErrFlagWritesUnsupported, tag)
10001009
}
10011010

10021011
// ErrFlagWritesUnsupported marks an instance without the update-flag endpoints,
10031012
// which every flag mutation needs. Reads are unaffected: they use endpoints that
10041013
// have been there all along.
10051014
var ErrFlagWritesUnsupported = fmt.Errorf("changing flags needs Flagsmith %s or newer", MinFlagWriteVersion)
10061015

1007-
// ServerVersion reports the instance's version, as /version advertises it. The
1008-
// endpoint is unauthenticated and predates everything the CLI uses.
1009-
func (c *Client) ServerVersion(ctx context.Context) (string, error) {
1010-
var info struct {
1011-
ImageTag string `json:"image_tag"`
1012-
PackageVersions map[string]string `json:"package_versions"`
1013-
}
1014-
if err := c.get(ctx, "/version", &info); err != nil {
1015-
return "", err
1016-
}
1017-
if info.ImageTag != "" {
1018-
return info.ImageTag, nil
1019-
}
1020-
return info.PackageVersions["."], nil
1021-
}
1022-
10231016
// ErrWorkflowGated is returned when update-flag refuses because the environment
10241017
// has change-request workflows enabled.
10251018
var ErrWorkflowGated = fmt.Errorf("this environment uses change-request workflows; direct updates are disabled")

internal/api/client_test.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ func TestUpdateFlag(t *testing.T) {
583583
t.Run("a 404 with no detail is an instance too old, and names its version", func(t *testing.T) {
584584
// Given
585585
mux := http.NewServeMux()
586-
mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
586+
mux.HandleFunc("/version/", func(w http.ResponseWriter, r *http.Request) {
587587
fmt.Fprint(w, `{"image_tag": "2.262.0", "package_versions": {".": "2.262.0"}}`)
588588
})
589589
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -609,6 +609,32 @@ func TestUpdateFlag(t *testing.T) {
609609
}
610610
})
611611

612+
t.Run("a tag that is not a version is left out rather than quoted back", func(t *testing.T) {
613+
// Given: what a self-hosted instance tracking a branch reports.
614+
mux := http.NewServeMux()
615+
mux.HandleFunc("/version/", func(w http.ResponseWriter, r *http.Request) {
616+
fmt.Fprint(w, `{"image_tag": "latest"}`)
617+
})
618+
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
619+
w.WriteHeader(http.StatusNotFound)
620+
fmt.Fprint(w, "<h1>Not Found</h1>")
621+
})
622+
srv := httptest.NewServer(mux)
623+
defer srv.Close()
624+
625+
// When
626+
_, err := testClient(srv.URL, APIKey("k.s"), srv).UpdateFlag(context.Background(), "envkey", 42,
627+
UpdateFlagRequest{EnvironmentDefault: &FlagStateUpdate{Enabled: &enabled}})
628+
629+
// Then
630+
if !errors.Is(err, ErrFlagWritesUnsupported) {
631+
t.Fatalf("err = %v, want ErrFlagWritesUnsupported", err)
632+
}
633+
if strings.Contains(err.Error(), "latest") {
634+
t.Errorf("err = %v, want the unparseable tag left out", err)
635+
}
636+
})
637+
612638
t.Run("an unreadable version still reports the requirement", func(t *testing.T) {
613639
// Given: no /version to read, as a proxy in front of an old instance
614640
// might leave it.

internal/cmd/cmd_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ func newFakeInstance(t *testing.T) *fakeInstance {
591591
w.WriteHeader(http.StatusCreated)
592592
json.NewEncoder(w).Encode(clone)
593593
})
594-
mux.HandleFunc("GET /version", func(w http.ResponseWriter, r *http.Request) {
594+
mux.HandleFunc("GET /version/", func(w http.ResponseWriter, r *http.Request) {
595595
json.NewEncoder(w).Encode(map[string]any{
596596
"image_tag": "2.262.0", "package_versions": map[string]string{".": "2.262.0"},
597597
})

0 commit comments

Comments
 (0)