diff --git a/go.mod b/go.mod index c794657..3881ebf 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.24.0 require github.com/urfave/cli/v3 v3.0.0-alpha9.2 // direct require ( - buf.build/gen/go/openstatus/api/connectrpc/gosimple v1.19.1-20260202165838-5bd92a1e5d53.2 - buf.build/gen/go/openstatus/api/protocolbuffers/go v1.36.11-20260202165838-5bd92a1e5d53.1 + buf.build/gen/go/openstatus/api/connectrpc/gosimple v1.19.1-20260323160652-4be687fa490b.2 + buf.build/gen/go/openstatus/api/protocolbuffers/go v1.36.11-20260323160652-4be687fa490b.1 connectrpc.com/connect v1.19.1 github.com/briandowns/spinner v1.23.2 github.com/fatih/color v1.18.0 @@ -26,6 +26,7 @@ require ( require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 // indirect + buf.build/gen/go/gnostic/gnostic/protocolbuffers/go v1.36.11-20230414000709-087bc8072ce4.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index 269cf5a..c80a9e2 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,11 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 h1:j9yeqTWEFrtimt8Nng2MIeRrpoCvQzM9/g25XTvqUGg= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= -buf.build/gen/go/openstatus/api/connectrpc/gosimple v1.19.1-20260202165838-5bd92a1e5d53.2 h1:MeP+r7GwYHWKSMa1ltvtRNwzT+gCyHIYCEpNxWeNwS4= -buf.build/gen/go/openstatus/api/connectrpc/gosimple v1.19.1-20260202165838-5bd92a1e5d53.2/go.mod h1:W/PtF1QguqXdSkOHAD0VAOTMNfuESeNOdR2cF/CWeOQ= -buf.build/gen/go/openstatus/api/protocolbuffers/go v1.36.11-20260202165838-5bd92a1e5d53.1 h1:vw4PznfU8x7XrFtc/HHPjWfxNnFExtaSwrPS8cEKq+w= -buf.build/gen/go/openstatus/api/protocolbuffers/go v1.36.11-20260202165838-5bd92a1e5d53.1/go.mod h1:pZsKB5l3aT2mKtGkAZTC8pXhTptdfyYwFGCyH+KVfOM= +buf.build/gen/go/gnostic/gnostic/protocolbuffers/go v1.36.11-20230414000709-087bc8072ce4.1 h1:t8f+WWZ5WNrZaP5zrpWD8f1tKU7eelJMbIAT9FRX558= +buf.build/gen/go/gnostic/gnostic/protocolbuffers/go v1.36.11-20230414000709-087bc8072ce4.1/go.mod h1:/t9AeRQQp2iNkiGHDLfHLW3SzNpYpNPGRZ+Ih8+SOUs= +buf.build/gen/go/openstatus/api/connectrpc/gosimple v1.19.1-20260323160652-4be687fa490b.2 h1:AHDJQUgykCBDBE8qx4ewHxk4q29BYin4I5k2VZBJoSI= +buf.build/gen/go/openstatus/api/connectrpc/gosimple v1.19.1-20260323160652-4be687fa490b.2/go.mod h1:M+ceX35kH8wh3cgoFD8o2fNVedIx8NB9LWV7Z0ObO6Y= +buf.build/gen/go/openstatus/api/protocolbuffers/go v1.36.11-20260323160652-4be687fa490b.1 h1:sTK/97BsCzbBtqydnKAyRduWLbm1U7LbOk+hAzOikhs= +buf.build/gen/go/openstatus/api/protocolbuffers/go v1.36.11-20260323160652-4be687fa490b.1/go.mod h1:GRsD/In1AV3/RC92zWVAjBpj57hJIQm7Rph0rLOYYPg= connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w= diff --git a/internal/statuspage/statuspage.go b/internal/statuspage/statuspage.go index c11b949..35c9e47 100644 --- a/internal/statuspage/statuspage.go +++ b/internal/statuspage/statuspage.go @@ -65,6 +65,27 @@ func componentTypeToString(t status_pagev1.PageComponentType) string { } } +func localeToString(l status_pagev1.Locale) string { + switch l { + case status_pagev1.Locale_LOCALE_EN: + return "en" + case status_pagev1.Locale_LOCALE_FR: + return "fr" + case status_pagev1.Locale_LOCALE_DE: + return "de" + default: + return "unknown" + } +} + +func localesToStrings(locales []status_pagev1.Locale) []string { + result := make([]string, 0, len(locales)) + for _, l := range locales { + result = append(result, localeToString(l)) + } + return result +} + func StatusPageCmd() *cli.Command { return &cli.Command{ Name: "status-page", diff --git a/internal/statuspage/statuspage_info.go b/internal/statuspage/statuspage_info.go index 30dfed7..f14dbb9 100644 --- a/internal/statuspage/statuspage_info.go +++ b/internal/statuspage/statuspage_info.go @@ -23,16 +23,18 @@ import ( ) type statusPageDetail struct { - ID string `json:"id"` - Title string `json:"title"` - Description string `json:"description,omitempty"` - URL string `json:"url"` - Published bool `json:"published"` - AccessType string `json:"access_type"` - Theme string `json:"theme"` - HomepageURL string `json:"homepage_url,omitempty"` - ContactURL string `json:"contact_url,omitempty"` - Components []statusPageComponent `json:"components,omitempty"` + ID string `json:"id"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + URL string `json:"url"` + Published bool `json:"published"` + AccessType string `json:"access_type"` + Theme string `json:"theme"` + DefaultLocale string `json:"default_locale"` + Locales []string `json:"locales,omitempty"` + HomepageURL string `json:"homepage_url,omitempty"` + ContactURL string `json:"contact_url,omitempty"` + Components []statusPageComponent `json:"components,omitempty"` } type statusPageComponent struct { @@ -109,16 +111,18 @@ func GetStatusPageInfo(ctx context.Context, client status_pagev1connect.StatusPa if output.IsJSONOutput() { detail := statusPageDetail{ - ID: page.GetId(), - Title: page.GetTitle(), - Description: page.GetDescription(), - URL: pageURL, - Published: page.GetPublished(), - AccessType: accessTypeToString(page.GetAccessType()), - Theme: themeToString(page.GetTheme()), - HomepageURL: page.GetHomepageUrl(), - ContactURL: page.GetContactUrl(), - Components: comps, + ID: page.GetId(), + Title: page.GetTitle(), + Description: page.GetDescription(), + URL: pageURL, + Published: page.GetPublished(), + AccessType: accessTypeToString(page.GetAccessType()), + Theme: themeToString(page.GetTheme()), + DefaultLocale: localeToString(page.GetDefaultLocale()), + Locales: localesToStrings(page.GetLocales()), + HomepageURL: page.GetHomepageUrl(), + ContactURL: page.GetContactUrl(), + Components: comps, } return output.PrintJSON(detail) } @@ -162,6 +166,10 @@ func GetStatusPageInfo(ctx context.Context, client status_pagev1connect.StatusPa data = append(data, []string{"Access Type", accessTypeToString(page.GetAccessType())}) data = append(data, []string{"Theme", themeToString(page.GetTheme())}) + data = append(data, []string{"Default Locale", localeToString(page.GetDefaultLocale())}) + if locales := page.GetLocales(); len(locales) > 0 { + data = append(data, []string{"Locales", strings.Join(localesToStrings(locales), ", ")}) + } if page.GetHomepageUrl() != "" { data = append(data, []string{"Homepage URL", page.GetHomepageUrl()}) diff --git a/internal/statuspage/statuspage_list.go b/internal/statuspage/statuspage_list.go index 6497a4c..45805d8 100644 --- a/internal/statuspage/statuspage_list.go +++ b/internal/statuspage/statuspage_list.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "strings" status_pagev1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/status_page/v1" "buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/status_page/v1/status_pagev1connect" @@ -42,7 +43,7 @@ func ListStatusPages(ctx context.Context, client status_pagev1connect.StatusPage entries = append(entries, statusPageListEntry{ ID: p.GetId(), Title: p.GetTitle(), - URL: "https://" + p.GetSlug() + ".openstatus.dev", + URL: statusPageURL(p), }) } return output.PrintJSON(entries) @@ -65,7 +66,7 @@ func ListStatusPages(ctx context.Context, client status_pagev1connect.StatusPage tbl.AddRow( p.GetId(), p.GetTitle(), - "https://"+p.GetSlug()+".openstatus.dev", + statusPageURL(p), ) } @@ -73,6 +74,14 @@ func ListStatusPages(ctx context.Context, client status_pagev1connect.StatusPage return nil } +func statusPageURL(p *status_pagev1.StatusPageSummary) string { + if d := p.GetCustomDomain(); d != "" { + d = strings.TrimPrefix(strings.TrimPrefix(d, "https://"), "http://") + return "https://" + d + } + return "https://" + p.GetSlug() + ".openstatus.dev" +} + func ListStatusPagesWithHTTPClient(ctx context.Context, httpClient *http.Client, apiKey string, limit int) error { client := NewStatusPageClientWithHTTPClient(httpClient, apiKey) return ListStatusPages(ctx, client, limit, nil) diff --git a/internal/statuspage/statuspage_list_test.go b/internal/statuspage/statuspage_list_test.go index 9cdf9d2..056190f 100644 --- a/internal/statuspage/statuspage_list_test.go +++ b/internal/statuspage/statuspage_list_test.go @@ -42,6 +42,33 @@ func Test_ListStatusPages(t *testing.T) { } }) + t.Run("Displays custom domain when set", func(t *testing.T) { + body := `{"statusPages":[{"id":"1","title":"My Status Page","slug":"my-page","customDomain":"status.example.com","published":true,"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}],"totalSize":1}` + r := io.NopCloser(bytes.NewReader([]byte(body))) + + interceptor := &interceptorHTTPClient{ + f: func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusOK, + Body: r, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, nil + }, + } + + var bf bytes.Buffer + log.SetOutput(&bf) + t.Cleanup(func() { + log.SetOutput(os.Stderr) + }) + err := statuspage.ListStatusPagesWithHTTPClient(context.Background(), interceptor.GetHTTPClient(), "test-token", 0) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + }) + t.Run("Returns empty list", func(t *testing.T) { body := `{"statusPages":[],"totalSize":0}` r := io.NopCloser(bytes.NewReader([]byte(body)))