From 3e62d6d0b3b78723c695a220b138ab605524f3e5 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 16 Sep 2025 21:59:13 +0200 Subject: [PATCH 1/7] feat(cosmosgen): fetch fallback buf token --- ignite/pkg/cosmosgen/generate_typescript.go | 46 ++++- .../pkg/cosmosgen/generate_typescript_test.go | 178 ++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) diff --git a/ignite/pkg/cosmosgen/generate_typescript.go b/ignite/pkg/cosmosgen/generate_typescript.go index c6919d805a..f731a09027 100644 --- a/ignite/pkg/cosmosgen/generate_typescript.go +++ b/ignite/pkg/cosmosgen/generate_typescript.go @@ -2,12 +2,16 @@ package cosmosgen import ( "context" + "encoding/json" + "fmt" "log" + "net/http" "os" "os/exec" "path/filepath" "sort" "strings" + "time" "golang.org/x/sync/errgroup" @@ -19,11 +23,15 @@ import ( ) var ( + bufTokenEnvName = "BUF_TOKEN" + dirchangeCacheNamespace = "generate.typescript.dirchange" protocGenTSProtoBin = "protoc-gen-ts_proto" msgBufAuth = "Note: Buf is limits remote plugin requests from unauthenticated users on 'buf.build'. Intensively using this function will get you rate limited. Authenticate with 'buf registry login' to avoid this (https://buf.build/docs/generate/auth-required)." + + bufTokenEndpoint = "https://api.ignite.com/v1/buf/token" ) const localTSProtoTmpl = `version: v1 @@ -54,7 +62,15 @@ func newTSGenerator(g *generator) *tsGenerator { } if !tsg.isLocalProto { - log.Printf("No '%s' binary found in PATH, using remote buf plugin for Typescript generation. %s\n", protocGenTSProtoBin, msgBufAuth) + if os.Getenv(bufTokenEnvName) == "" { + // fetch ignite buf.build token + token, err := fetchBufToken() + if err != nil { + log.Printf("No '%s' binary found in PATH, using remote buf plugin for Typescript generation. %s\n", protocGenTSProtoBin, msgBufAuth) + } else { + os.Setenv(bufTokenEnvName, token) + } + } } return tsg @@ -250,3 +266,31 @@ func (g *tsGenerator) generateRootTemplates(p generatePayload) error { return templateTSClientRoot.Write(outDir, "", p) } + +// fetchBufToken fetches the buf token from the ignite API +func fetchBufToken() (string, error) { + client := &http.Client{ + Timeout: 10 * time.Second, + } + + resp, err := client.Get(bufTokenEndpoint) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("HTTP request failed with status code: %d", resp.StatusCode) + } + + type tokenResponse struct { + Token string `json:"token"` + } + var tokenResp tokenResponse + + if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { + return "", err + } + + return tokenResp.Token, nil +} diff --git a/ignite/pkg/cosmosgen/generate_typescript_test.go b/ignite/pkg/cosmosgen/generate_typescript_test.go index ad806ce201..307eecdfb9 100644 --- a/ignite/pkg/cosmosgen/generate_typescript_test.go +++ b/ignite/pkg/cosmosgen/generate_typescript_test.go @@ -2,6 +2,8 @@ package cosmosgen import ( "fmt" + "net/http" + "net/http/httptest" "os" "path/filepath" "strings" @@ -75,3 +77,179 @@ func TestGenerateTypeScript(t *testing.T) { return nil }) } + +func TestFetchBufToken(t *testing.T) { + tests := []struct { + name string + serverResponse string + statusCode int + expectedToken string + expectError bool + }{ + { + name: "successful token fetch", + serverResponse: `{"token":"test_token_123"}`, + statusCode: http.StatusOK, + expectedToken: "test_token_123", + expectError: false, + }, + { + name: "server error", + serverResponse: `{"error":"internal server error"}`, + statusCode: http.StatusInternalServerError, + expectedToken: "", + expectError: true, + }, + { + name: "invalid json response", + serverResponse: `invalid json`, + statusCode: http.StatusOK, + expectedToken: "", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mock server + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(tt.statusCode) + w.Write([]byte(tt.serverResponse)) + })) + defer server.Close() + + // Temporarily override the endpoint + originalEndpoint := bufTokenEndpoint + bufTokenEndpoint = server.URL + defer func() { + bufTokenEndpoint = originalEndpoint + }() + + token, err := fetchBufToken() + + if tt.expectError { + require.Error(t, err) + require.Empty(t, token) + } else { + require.NoError(t, err) + require.Equal(t, tt.expectedToken, token) + } + }) + } +} + +func TestNewTSGeneratorBufTokenLogic(t *testing.T) { + tests := []struct { + name string + isLocalProto bool + existingEnvToken string + mockServerResponse string + mockStatusCode int + expectEnvSet bool + expectLogMessage bool + }{ + { + name: "local proto available - no token fetch", + isLocalProto: true, + existingEnvToken: "", + mockServerResponse: "", + mockStatusCode: 0, + expectEnvSet: false, + expectLogMessage: false, + }, + { + name: "env token already set - no fetch", + isLocalProto: false, + existingEnvToken: "existing_token", + mockServerResponse: "", + mockStatusCode: 0, + expectEnvSet: false, + expectLogMessage: false, + }, + { + name: "successful token fetch", + isLocalProto: false, + existingEnvToken: "", + mockServerResponse: `{"token":"fetched_token"}`, + mockStatusCode: http.StatusOK, + expectEnvSet: true, + expectLogMessage: false, + }, + { + name: "failed token fetch - log message", + isLocalProto: false, + existingEnvToken: "", + mockServerResponse: `{"error":"server error"}`, + mockStatusCode: http.StatusInternalServerError, + expectEnvSet: false, + expectLogMessage: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Save original environment + originalToken := os.Getenv(bufTokenEnvName) + originalEndpoint := bufTokenEndpoint + defer func() { + if originalToken != "" { + os.Setenv(bufTokenEnvName, originalToken) + } else { + os.Unsetenv(bufTokenEnvName) + } + bufTokenEndpoint = originalEndpoint + }() + + // Set up test environment + if tt.existingEnvToken != "" { + os.Setenv(bufTokenEnvName, tt.existingEnvToken) + } else { + os.Unsetenv(bufTokenEnvName) + } + + // Set up mock server if needed + if !tt.isLocalProto && tt.existingEnvToken == "" { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(tt.mockStatusCode) + w.Write([]byte(tt.mockServerResponse)) + })) + defer server.Close() + bufTokenEndpoint = server.URL + } + + // Create mock generator + g := &generator{} + + // Create TSGenerator with mocked isLocalProto + tsg := &tsGenerator{ + g: g, + isLocalProto: tt.isLocalProto, + } + + // Simulate the logic from newTSGenerator + if !tsg.isLocalProto { + if os.Getenv(bufTokenEnvName) == "" { + token, err := fetchBufToken() + if err != nil { + // This would normally log the message + if tt.expectLogMessage { + require.Error(t, err) + } + } else { + os.Setenv(bufTokenEnvName, token) + } + } + } + + // Verify expectations + if tt.expectEnvSet { + token := os.Getenv(bufTokenEnvName) + require.NotEmpty(t, token) + require.Equal(t, "fetched_token", token) + } else if tt.existingEnvToken != "" { + token := os.Getenv(bufTokenEnvName) + require.Equal(t, tt.existingEnvToken, token) + } + }) + } +} From 55c6a7b15ccfe82820b4f56967292370cebd082e Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 17 Sep 2025 10:36:39 +0200 Subject: [PATCH 2/7] package refactor --- ignite/cmd/bubblemodel/chain_serve.go | 2 +- ignite/cmd/cmd.go | 2 +- ignite/internal/analytics/analytics.go | 2 +- .../announcements/announcement.go | 15 +- .../announcements/announcement_test.go | 8 +- ignite/internal/buf/buf.go | 38 ++++ ignite/internal/buf/buf_test.go | 69 +++++++ ignite/{pkg => internal}/sentry/sentry.go | 0 ignite/pkg/cosmosgen/generate_typescript.go | 47 +---- .../pkg/cosmosgen/generate_typescript_test.go | 178 ------------------ .../testchain/proto/buf.gen.swagger.yaml | 2 +- ignite/pkg/errors/xerrors.go | 6 +- .../app/files/{{protoDir}}/buf.gen.gogo.yaml | 2 +- .../app/files/{{protoDir}}/buf.gen.sta.yaml | 2 +- .../files/{{protoDir}}/buf.gen.swagger.yaml | 2 +- .../app/files/{{protoDir}}/buf.gen.ts.yaml | 2 +- 16 files changed, 137 insertions(+), 240 deletions(-) rename ignite/{pkg => internal}/announcements/announcement.go (78%) rename ignite/{pkg => internal}/announcements/announcement_test.go (87%) create mode 100644 ignite/internal/buf/buf.go create mode 100644 ignite/internal/buf/buf_test.go rename ignite/{pkg => internal}/sentry/sentry.go (100%) diff --git a/ignite/cmd/bubblemodel/chain_serve.go b/ignite/cmd/bubblemodel/chain_serve.go index 08cfa298f5..088c81c091 100644 --- a/ignite/cmd/bubblemodel/chain_serve.go +++ b/ignite/cmd/bubblemodel/chain_serve.go @@ -7,7 +7,7 @@ import ( tea "github.com/charmbracelet/bubbletea" - "github.com/ignite/cli/v29/ignite/pkg/announcements" + "github.com/ignite/cli/v29/ignite/internal/announcements" "github.com/ignite/cli/v29/ignite/pkg/cliui/colors" "github.com/ignite/cli/v29/ignite/pkg/cliui/icons" cliuimodel "github.com/ignite/cli/v29/ignite/pkg/cliui/model" diff --git a/ignite/cmd/cmd.go b/ignite/cmd/cmd.go index e5b937be35..19979a3cfd 100644 --- a/ignite/cmd/cmd.go +++ b/ignite/cmd/cmd.go @@ -14,7 +14,7 @@ import ( "github.com/ignite/cli/v29/ignite/config" chainconfig "github.com/ignite/cli/v29/ignite/config/chain" - "github.com/ignite/cli/v29/ignite/pkg/announcements" + "github.com/ignite/cli/v29/ignite/internal/announcements" "github.com/ignite/cli/v29/ignite/pkg/cache" "github.com/ignite/cli/v29/ignite/pkg/cliui" uilog "github.com/ignite/cli/v29/ignite/pkg/cliui/log" diff --git a/ignite/internal/analytics/analytics.go b/ignite/internal/analytics/analytics.go index 5c55290d37..5a83512003 100644 --- a/ignite/internal/analytics/analytics.go +++ b/ignite/internal/analytics/analytics.go @@ -12,11 +12,11 @@ import ( "github.com/spf13/cobra" "github.com/ignite/cli/v29/ignite/config" + "github.com/ignite/cli/v29/ignite/internal/sentry" "github.com/ignite/cli/v29/ignite/pkg/cliui" "github.com/ignite/cli/v29/ignite/pkg/errors" "github.com/ignite/cli/v29/ignite/pkg/matomo" "github.com/ignite/cli/v29/ignite/pkg/randstr" - "github.com/ignite/cli/v29/ignite/pkg/sentry" "github.com/ignite/cli/v29/ignite/version" ) diff --git a/ignite/pkg/announcements/announcement.go b/ignite/internal/announcements/announcement.go similarity index 78% rename from ignite/pkg/announcements/announcement.go rename to ignite/internal/announcements/announcement.go index 7b1947f54a..0c3c5058ad 100644 --- a/ignite/pkg/announcements/announcement.go +++ b/ignite/internal/announcements/announcement.go @@ -11,14 +11,10 @@ import ( ) var ( - SurveyLink = "https://bit.ly/3WZS2uS" - APIURL = "http://announcements.ignite.com/v1/announcements" + SurveyLink = "https://bit.ly/3WZS2uS" + AnnouncementURL = "https://api.ignite.com/v1/announcements" ) -type api struct { - Announcements []announcement `json:"announcements"` -} - type announcement struct { ID string `json:"id"` Text string `json:"text"` @@ -28,13 +24,16 @@ type announcement struct { // Fetch fetches the latest announcements from the API. func Fetch() string { - resp, err := http.Get(APIURL) //nolint:gosec + resp, err := http.Get(AnnouncementURL) //nolint:gosec if err != nil || resp.StatusCode != 200 { return fallbackData() } defer resp.Body.Close() - var data api + type response struct { + Announcements []announcement `json:"announcements"` + } + var data response if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return fallbackData() } diff --git a/ignite/pkg/announcements/announcement_test.go b/ignite/internal/announcements/announcement_test.go similarity index 87% rename from ignite/pkg/announcements/announcement_test.go rename to ignite/internal/announcements/announcement_test.go index eb1796c881..23a8e5b3c9 100644 --- a/ignite/pkg/announcements/announcement_test.go +++ b/ignite/internal/announcements/announcement_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/ignite/cli/v29/ignite/pkg/announcements" + "github.com/ignite/cli/v29/ignite/internal/announcements" ) func TestFetchAnnouncements(t *testing.T) { @@ -52,9 +52,9 @@ func TestFetchAnnouncements(t *testing.T) { })) defer server.Close() - originalAPI := announcements.APIURL - announcements.APIURL = server.URL - defer func() { announcements.APIURL = originalAPI }() + originalAPI := announcements.AnnouncementURL + announcements.AnnouncementURL = server.URL + defer func() { announcements.AnnouncementURL = originalAPI }() result := announcements.Fetch() if result != tt.expected { diff --git a/ignite/internal/buf/buf.go b/ignite/internal/buf/buf.go new file mode 100644 index 0000000000..fbbe73e5e4 --- /dev/null +++ b/ignite/internal/buf/buf.go @@ -0,0 +1,38 @@ +package buf + +import ( + "encoding/json" + "fmt" + "net/http" + "time" +) + +var BufTokenURL = "https://api.ignite.com/v1/buf/token" + +// FetchToken fetches the buf token from the Ignite API. +func FetchToken() (string, error) { + client := &http.Client{ + Timeout: 5 * time.Second, + } + + resp, err := client.Get(BufTokenURL) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("HTTP request failed with status code: %d", resp.StatusCode) + } + + type tokenResponse struct { + Token string `json:"token"` + } + var tokenResp tokenResponse + + if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { + return "", err + } + + return tokenResp.Token, nil +} diff --git a/ignite/internal/buf/buf_test.go b/ignite/internal/buf/buf_test.go new file mode 100644 index 0000000000..a2f167cd6e --- /dev/null +++ b/ignite/internal/buf/buf_test.go @@ -0,0 +1,69 @@ +package buf_test + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/ignite/cli/v29/ignite/internal/buf" + "github.com/stretchr/testify/require" +) + +func TestFetchToken(t *testing.T) { + tests := []struct { + name string + serverResponse string + statusCode int + expectedToken string + expectError bool + }{ + { + name: "successful token fetch", + serverResponse: `{"token":"test_token_123"}`, + statusCode: http.StatusOK, + expectedToken: "test_token_123", + expectError: false, + }, + { + name: "server error", + serverResponse: `{"error":"internal server error"}`, + statusCode: http.StatusInternalServerError, + expectedToken: "", + expectError: true, + }, + { + name: "invalid json response", + serverResponse: `invalid json`, + statusCode: http.StatusOK, + expectedToken: "", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mock server + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(tt.statusCode) + w.Write([]byte(tt.serverResponse)) + })) + defer server.Close() + + // Temporarily override the endpoint + originalEndpoint := buf.BufTokenURL + buf.BufTokenURL = server.URL + defer func() { + buf.BufTokenURL = originalEndpoint + }() + + token, err := buf.FetchToken() + if tt.expectError { + require.Error(t, err) + require.Empty(t, token) + } else { + require.NoError(t, err) + require.Equal(t, tt.expectedToken, token) + } + }) + } +} diff --git a/ignite/pkg/sentry/sentry.go b/ignite/internal/sentry/sentry.go similarity index 100% rename from ignite/pkg/sentry/sentry.go rename to ignite/internal/sentry/sentry.go diff --git a/ignite/pkg/cosmosgen/generate_typescript.go b/ignite/pkg/cosmosgen/generate_typescript.go index f731a09027..0b5706ee49 100644 --- a/ignite/pkg/cosmosgen/generate_typescript.go +++ b/ignite/pkg/cosmosgen/generate_typescript.go @@ -2,19 +2,16 @@ package cosmosgen import ( "context" - "encoding/json" - "fmt" "log" - "net/http" "os" "os/exec" "path/filepath" "sort" "strings" - "time" "golang.org/x/sync/errgroup" + "github.com/ignite/cli/v29/ignite/internal/buf" "github.com/ignite/cli/v29/ignite/pkg/cache" "github.com/ignite/cli/v29/ignite/pkg/cosmosanalysis/module" "github.com/ignite/cli/v29/ignite/pkg/cosmosbuf" @@ -30,8 +27,6 @@ var ( protocGenTSProtoBin = "protoc-gen-ts_proto" msgBufAuth = "Note: Buf is limits remote plugin requests from unauthenticated users on 'buf.build'. Intensively using this function will get you rate limited. Authenticate with 'buf registry login' to avoid this (https://buf.build/docs/generate/auth-required)." - - bufTokenEndpoint = "https://api.ignite.com/v1/buf/token" ) const localTSProtoTmpl = `version: v1 @@ -39,9 +34,12 @@ plugins: - plugin: ts_proto out: . opt: - - "esModuleInterop=true" - - "forceLong=long" - - "useOptionals=true" + - logtostderr=true + - allow_merge=true + - json_names_for_fields=false + - ts_proto_opt=snakeToCamel=true + - ts_proto_opt=esModuleInterop=true + - ts_proto_out=. ` type tsGenerator struct { @@ -63,8 +61,7 @@ func newTSGenerator(g *generator) *tsGenerator { if !tsg.isLocalProto { if os.Getenv(bufTokenEnvName) == "" { - // fetch ignite buf.build token - token, err := fetchBufToken() + token, err := buf.FetchToken() if err != nil { log.Printf("No '%s' binary found in PATH, using remote buf plugin for Typescript generation. %s\n", protocGenTSProtoBin, msgBufAuth) } else { @@ -266,31 +263,3 @@ func (g *tsGenerator) generateRootTemplates(p generatePayload) error { return templateTSClientRoot.Write(outDir, "", p) } - -// fetchBufToken fetches the buf token from the ignite API -func fetchBufToken() (string, error) { - client := &http.Client{ - Timeout: 10 * time.Second, - } - - resp, err := client.Get(bufTokenEndpoint) - if err != nil { - return "", err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("HTTP request failed with status code: %d", resp.StatusCode) - } - - type tokenResponse struct { - Token string `json:"token"` - } - var tokenResp tokenResponse - - if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { - return "", err - } - - return tokenResp.Token, nil -} diff --git a/ignite/pkg/cosmosgen/generate_typescript_test.go b/ignite/pkg/cosmosgen/generate_typescript_test.go index 307eecdfb9..ad806ce201 100644 --- a/ignite/pkg/cosmosgen/generate_typescript_test.go +++ b/ignite/pkg/cosmosgen/generate_typescript_test.go @@ -2,8 +2,6 @@ package cosmosgen import ( "fmt" - "net/http" - "net/http/httptest" "os" "path/filepath" "strings" @@ -77,179 +75,3 @@ func TestGenerateTypeScript(t *testing.T) { return nil }) } - -func TestFetchBufToken(t *testing.T) { - tests := []struct { - name string - serverResponse string - statusCode int - expectedToken string - expectError bool - }{ - { - name: "successful token fetch", - serverResponse: `{"token":"test_token_123"}`, - statusCode: http.StatusOK, - expectedToken: "test_token_123", - expectError: false, - }, - { - name: "server error", - serverResponse: `{"error":"internal server error"}`, - statusCode: http.StatusInternalServerError, - expectedToken: "", - expectError: true, - }, - { - name: "invalid json response", - serverResponse: `invalid json`, - statusCode: http.StatusOK, - expectedToken: "", - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create mock server - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(tt.statusCode) - w.Write([]byte(tt.serverResponse)) - })) - defer server.Close() - - // Temporarily override the endpoint - originalEndpoint := bufTokenEndpoint - bufTokenEndpoint = server.URL - defer func() { - bufTokenEndpoint = originalEndpoint - }() - - token, err := fetchBufToken() - - if tt.expectError { - require.Error(t, err) - require.Empty(t, token) - } else { - require.NoError(t, err) - require.Equal(t, tt.expectedToken, token) - } - }) - } -} - -func TestNewTSGeneratorBufTokenLogic(t *testing.T) { - tests := []struct { - name string - isLocalProto bool - existingEnvToken string - mockServerResponse string - mockStatusCode int - expectEnvSet bool - expectLogMessage bool - }{ - { - name: "local proto available - no token fetch", - isLocalProto: true, - existingEnvToken: "", - mockServerResponse: "", - mockStatusCode: 0, - expectEnvSet: false, - expectLogMessage: false, - }, - { - name: "env token already set - no fetch", - isLocalProto: false, - existingEnvToken: "existing_token", - mockServerResponse: "", - mockStatusCode: 0, - expectEnvSet: false, - expectLogMessage: false, - }, - { - name: "successful token fetch", - isLocalProto: false, - existingEnvToken: "", - mockServerResponse: `{"token":"fetched_token"}`, - mockStatusCode: http.StatusOK, - expectEnvSet: true, - expectLogMessage: false, - }, - { - name: "failed token fetch - log message", - isLocalProto: false, - existingEnvToken: "", - mockServerResponse: `{"error":"server error"}`, - mockStatusCode: http.StatusInternalServerError, - expectEnvSet: false, - expectLogMessage: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Save original environment - originalToken := os.Getenv(bufTokenEnvName) - originalEndpoint := bufTokenEndpoint - defer func() { - if originalToken != "" { - os.Setenv(bufTokenEnvName, originalToken) - } else { - os.Unsetenv(bufTokenEnvName) - } - bufTokenEndpoint = originalEndpoint - }() - - // Set up test environment - if tt.existingEnvToken != "" { - os.Setenv(bufTokenEnvName, tt.existingEnvToken) - } else { - os.Unsetenv(bufTokenEnvName) - } - - // Set up mock server if needed - if !tt.isLocalProto && tt.existingEnvToken == "" { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(tt.mockStatusCode) - w.Write([]byte(tt.mockServerResponse)) - })) - defer server.Close() - bufTokenEndpoint = server.URL - } - - // Create mock generator - g := &generator{} - - // Create TSGenerator with mocked isLocalProto - tsg := &tsGenerator{ - g: g, - isLocalProto: tt.isLocalProto, - } - - // Simulate the logic from newTSGenerator - if !tsg.isLocalProto { - if os.Getenv(bufTokenEnvName) == "" { - token, err := fetchBufToken() - if err != nil { - // This would normally log the message - if tt.expectLogMessage { - require.Error(t, err) - } - } else { - os.Setenv(bufTokenEnvName, token) - } - } - } - - // Verify expectations - if tt.expectEnvSet { - token := os.Getenv(bufTokenEnvName) - require.NotEmpty(t, token) - require.Equal(t, "fetched_token", token) - } else if tt.existingEnvToken != "" { - token := os.Getenv(bufTokenEnvName) - require.Equal(t, tt.existingEnvToken, token) - } - }) - } -} diff --git a/ignite/pkg/cosmosgen/testdata/testchain/proto/buf.gen.swagger.yaml b/ignite/pkg/cosmosgen/testdata/testchain/proto/buf.gen.swagger.yaml index 0061ef290e..d81685c33d 100644 --- a/ignite/pkg/cosmosgen/testdata/testchain/proto/buf.gen.swagger.yaml +++ b/ignite/pkg/cosmosgen/testdata/testchain/proto/buf.gen.swagger.yaml @@ -1,4 +1,4 @@ -# This file is auto-generated from Ignite. You can edit +# This file is auto-generated by Ignite. You can edit # the file content but do not change the file name or path. # # buf.gen.swagger.yaml diff --git a/ignite/pkg/errors/xerrors.go b/ignite/pkg/errors/xerrors.go index 66ba2c074e..587714b61e 100644 --- a/ignite/pkg/errors/xerrors.go +++ b/ignite/pkg/errors/xerrors.go @@ -26,7 +26,7 @@ func New(msg string) error { } // Errorf aliases Newf(). -func Errorf(format string, args ...interface{}) error { +func Errorf(format string, args ...any) error { err := errors.Errorf(format, args...) sentry.CaptureException(err) return err @@ -49,7 +49,7 @@ func Wrap(err error, msg string) error { // Wrapf wraps an error with a formatted message prefix. A stack // trace is also retained. If the format is empty, no prefix is added, // but the extra arguments are still processed for reportable strings. -func Wrapf(err error, format string, args ...interface{}) error { +func Wrapf(err error, format string, args ...any) error { errWrap := errors.Wrapf(err, format, args...) sentry.CaptureException(errWrap) return errWrap @@ -73,4 +73,4 @@ func Is(err, reference error) bool { return errors.Is(err, reference) } // matches a type if it is assignable to the target type, or if it has a method // As(interface{}) bool such that As(target) returns true. As will panic if target // is not a non-nil pointer to a type which implements error or is of interface type. -func As(err error, target interface{}) bool { return errors.As(err, target) } +func As(err error, target any) bool { return errors.As(err, target) } diff --git a/ignite/templates/app/files/{{protoDir}}/buf.gen.gogo.yaml b/ignite/templates/app/files/{{protoDir}}/buf.gen.gogo.yaml index 1f6ecfe5e0..a3b72cc944 100644 --- a/ignite/templates/app/files/{{protoDir}}/buf.gen.gogo.yaml +++ b/ignite/templates/app/files/{{protoDir}}/buf.gen.gogo.yaml @@ -1,4 +1,4 @@ -# This file is auto-generated from Ignite. You can edit +# This file is auto-generated by Ignite. You can edit # the file content but do not change the file name or path. # # buf.gen.gogo.yaml diff --git a/ignite/templates/app/files/{{protoDir}}/buf.gen.sta.yaml b/ignite/templates/app/files/{{protoDir}}/buf.gen.sta.yaml index 215d950d94..7e69ed5d2e 100644 --- a/ignite/templates/app/files/{{protoDir}}/buf.gen.sta.yaml +++ b/ignite/templates/app/files/{{protoDir}}/buf.gen.sta.yaml @@ -1,4 +1,4 @@ -# This file is auto-generated from Ignite. You can edit +# This file is auto-generated by Ignite. You can edit # the file content but do not change the file name or path. # # buf.gen.sta.yaml diff --git a/ignite/templates/app/files/{{protoDir}}/buf.gen.swagger.yaml b/ignite/templates/app/files/{{protoDir}}/buf.gen.swagger.yaml index 0061ef290e..d81685c33d 100644 --- a/ignite/templates/app/files/{{protoDir}}/buf.gen.swagger.yaml +++ b/ignite/templates/app/files/{{protoDir}}/buf.gen.swagger.yaml @@ -1,4 +1,4 @@ -# This file is auto-generated from Ignite. You can edit +# This file is auto-generated by Ignite. You can edit # the file content but do not change the file name or path. # # buf.gen.swagger.yaml diff --git a/ignite/templates/app/files/{{protoDir}}/buf.gen.ts.yaml b/ignite/templates/app/files/{{protoDir}}/buf.gen.ts.yaml index bc2f01b93c..9bd0f601e7 100644 --- a/ignite/templates/app/files/{{protoDir}}/buf.gen.ts.yaml +++ b/ignite/templates/app/files/{{protoDir}}/buf.gen.ts.yaml @@ -1,4 +1,4 @@ -# This file is auto-generated from Ignite. You can edit +# This file is auto-generated by Ignite. You can edit # the file content but do not change the file name or path. # # buf.gen.ts.yaml From 293a213936bd362a89f1142199e51e6538a8b12f Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 17 Sep 2025 18:01:12 +0200 Subject: [PATCH 3/7] fix `CaptureException called with nil error` --- ignite/pkg/errors/xerrors.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ignite/pkg/errors/xerrors.go b/ignite/pkg/errors/xerrors.go index 587714b61e..8261f898e6 100644 --- a/ignite/pkg/errors/xerrors.go +++ b/ignite/pkg/errors/xerrors.go @@ -42,7 +42,9 @@ func WithStack(err error) error { // Wrap wraps an error with a message prefix. A stack trace is retained. func Wrap(err error, msg string) error { errWrap := errors.Wrap(err, msg) - sentry.CaptureException(errWrap) + if err != nil { + sentry.CaptureException(errWrap) + } return errWrap } @@ -51,7 +53,9 @@ func Wrap(err error, msg string) error { // but the extra arguments are still processed for reportable strings. func Wrapf(err error, format string, args ...any) error { errWrap := errors.Wrapf(err, format, args...) - sentry.CaptureException(errWrap) + if err != nil { + sentry.CaptureException(errWrap) + } return errWrap } From d29589db294494394dd5b6c9ead38573434f8728 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 19 Sep 2025 23:30:27 +0200 Subject: [PATCH 4/7] cl --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index bab189ffec..3dd0947dc3 100644 --- a/changelog.md +++ b/changelog.md @@ -2,7 +2,7 @@ ## Unreleased -### Features +### Changes - [#4807](https://github.com/ignite/cli/pull/4807) Improve unconfigured path message when building a chain. From 4088343b988d2cae23cf799c00cbbb1a2e6dd33b Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 25 Sep 2025 20:52:58 +0200 Subject: [PATCH 5/7] updates --- changelog.md | 1 + ignite/internal/buf/buf.go | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 3dd0947dc3..a66b2d4a4a 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,7 @@ ### Changes - [#4807](https://github.com/ignite/cli/pull/4807) Improve unconfigured path message when building a chain. +- [#4805](https://github.com/ignite/cli/pull/4805) Fetch fallback buf token. ## [`v29.4.0`](https://github.com/ignite/cli/releases/tag/v29.4.0) diff --git a/ignite/internal/buf/buf.go b/ignite/internal/buf/buf.go index fbbe73e5e4..268ee2af27 100644 --- a/ignite/internal/buf/buf.go +++ b/ignite/internal/buf/buf.go @@ -2,12 +2,13 @@ package buf import ( "encoding/json" - "fmt" "net/http" "time" + + "github.com/ignite/cli/v29/ignite/pkg/errors" ) -var BufTokenURL = "https://api.ignite.com/v1/buf/token" +var BufTokenURL = "https://buf.ignite.com" //nolint:gosec // URL is hardcoded and not user-provided // FetchToken fetches the buf token from the Ignite API. func FetchToken() (string, error) { @@ -22,7 +23,7 @@ func FetchToken() (string, error) { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("HTTP request failed with status code: %d", resp.StatusCode) + return "", errors.Errorf("HTTP request failed with status code: %d", resp.StatusCode) } type tokenResponse struct { From e1f5cc8ca931eb39eafffa51afb1d7f423619012 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 25 Sep 2025 22:02:17 +0200 Subject: [PATCH 6/7] updates --- ignite/pkg/gocmd/gocmd.go | 8 -------- ignite/pkg/gocmd/gocmd_test.go | 9 --------- 2 files changed, 17 deletions(-) diff --git a/ignite/pkg/gocmd/gocmd.go b/ignite/pkg/gocmd/gocmd.go index c5216df876..db3aedb1e1 100644 --- a/ignite/pkg/gocmd/gocmd.go +++ b/ignite/pkg/gocmd/gocmd.go @@ -168,14 +168,6 @@ func Install(ctx context.Context, path string, pkgs []string, options ...exec.Op return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } -// IsInstallError returns true if err is interpreted as a go install error. -func IsInstallError(err error) bool { - if err == nil { - return false - } - return strings.Contains(err.Error(), "no required module provides package") -} - // Get runs go get pkgs on path with options. func Get(ctx context.Context, path string, pkgs []string, options ...exec.Option) error { command := []string{ diff --git a/ignite/pkg/gocmd/gocmd_test.go b/ignite/pkg/gocmd/gocmd_test.go index fc33beb654..bf3a3e69dd 100644 --- a/ignite/pkg/gocmd/gocmd_test.go +++ b/ignite/pkg/gocmd/gocmd_test.go @@ -7,18 +7,9 @@ import ( "github.com/stretchr/testify/assert" - "github.com/ignite/cli/v29/ignite/pkg/errors" "github.com/ignite/cli/v29/ignite/pkg/gocmd" ) -func TestIsInstallError(t *testing.T) { - assert.False(t, gocmd.IsInstallError(errors.New("oups"))) - - err := errors.New(`error while running command go install github.com/cosmos/gogoproto/protoc-gen-gocosmos google.golang.org/protobuf/cmd/protoc-gen-go github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2: no required module provides package github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2; to add it: - go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2`) - assert.True(t, gocmd.IsInstallError(err)) -} - func TestList(t *testing.T) { wd, err := os.Getwd() assert.NoError(t, err) From 149a8421713c0640d7fa00f70604e5cf0c633014 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 30 Sep 2025 23:26:31 +0200 Subject: [PATCH 7/7] feedback --- ignite/pkg/cosmosgen/generate_typescript.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ignite/pkg/cosmosgen/generate_typescript.go b/ignite/pkg/cosmosgen/generate_typescript.go index 0b5706ee49..10e8c5a440 100644 --- a/ignite/pkg/cosmosgen/generate_typescript.go +++ b/ignite/pkg/cosmosgen/generate_typescript.go @@ -46,6 +46,9 @@ type tsGenerator struct { g *generator tsTemplateFile string isLocalProto bool + + // hasLocalBufToken indicates whether the user had already a local Buf token. + hasLocalBufToken bool } type generatePayload struct { @@ -67,6 +70,8 @@ func newTSGenerator(g *generator) *tsGenerator { } else { os.Setenv(bufTokenEnvName, token) } + } else { + tsg.hasLocalBufToken = true } } @@ -96,6 +101,11 @@ func (g *tsGenerator) cleanup() { if g.tsTemplateFile != "" { os.Remove(g.tsTemplateFile) } + + // unset ignite buf token from env + if !g.hasLocalBufToken { + os.Unsetenv(bufTokenEnvName) + } } func (g *generator) tsTemplate() string {