Skip to content

Commit 3919d6b

Browse files
authored
feat(cosmosgen): fetch fallback buf token (#4805)
* feat(cosmosgen): fetch fallback buf token * package refactor * fix `CaptureException called with nil error` * cl * updates * updates * feedback
1 parent 55d8b58 commit 3919d6b

File tree

18 files changed

+165
-47
lines changed

18 files changed

+165
-47
lines changed

changelog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
## Unreleased
44

5-
### Features
5+
### Changes
66

77
- [#4807](https://github.com/ignite/cli/pull/4807) Improve unconfigured path message when building a chain.
8+
- [#4805](https://github.com/ignite/cli/pull/4805) Fetch fallback buf token.
89

910
## [`v29.4.0`](https://github.com/ignite/cli/releases/tag/v29.4.0)
1011

ignite/cmd/bubblemodel/chain_serve.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77

88
tea "github.com/charmbracelet/bubbletea"
99

10-
"github.com/ignite/cli/v29/ignite/pkg/announcements"
10+
"github.com/ignite/cli/v29/ignite/internal/announcements"
1111
"github.com/ignite/cli/v29/ignite/pkg/cliui/colors"
1212
"github.com/ignite/cli/v29/ignite/pkg/cliui/icons"
1313
cliuimodel "github.com/ignite/cli/v29/ignite/pkg/cliui/model"

ignite/cmd/cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
"github.com/ignite/cli/v29/ignite/config"
1616
chainconfig "github.com/ignite/cli/v29/ignite/config/chain"
17-
"github.com/ignite/cli/v29/ignite/pkg/announcements"
17+
"github.com/ignite/cli/v29/ignite/internal/announcements"
1818
"github.com/ignite/cli/v29/ignite/pkg/cache"
1919
"github.com/ignite/cli/v29/ignite/pkg/cliui"
2020
uilog "github.com/ignite/cli/v29/ignite/pkg/cliui/log"

ignite/internal/analytics/analytics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import (
1212
"github.com/spf13/cobra"
1313

1414
"github.com/ignite/cli/v29/ignite/config"
15+
"github.com/ignite/cli/v29/ignite/internal/sentry"
1516
"github.com/ignite/cli/v29/ignite/pkg/cliui"
1617
"github.com/ignite/cli/v29/ignite/pkg/errors"
1718
"github.com/ignite/cli/v29/ignite/pkg/matomo"
1819
"github.com/ignite/cli/v29/ignite/pkg/randstr"
19-
"github.com/ignite/cli/v29/ignite/pkg/sentry"
2020
"github.com/ignite/cli/v29/ignite/version"
2121
)
2222

ignite/pkg/announcements/announcement.go renamed to ignite/internal/announcements/announcement.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,10 @@ import (
1111
)
1212

1313
var (
14-
SurveyLink = "https://bit.ly/3WZS2uS"
15-
APIURL = "http://announcements.ignite.com/v1/announcements"
14+
SurveyLink = "https://bit.ly/3WZS2uS"
15+
AnnouncementURL = "https://api.ignite.com/v1/announcements"
1616
)
1717

18-
type api struct {
19-
Announcements []announcement `json:"announcements"`
20-
}
21-
2218
type announcement struct {
2319
ID string `json:"id"`
2420
Text string `json:"text"`
@@ -28,13 +24,16 @@ type announcement struct {
2824

2925
// Fetch fetches the latest announcements from the API.
3026
func Fetch() string {
31-
resp, err := http.Get(APIURL) //nolint:gosec
27+
resp, err := http.Get(AnnouncementURL) //nolint:gosec
3228
if err != nil || resp.StatusCode != 200 {
3329
return fallbackData()
3430
}
3531
defer resp.Body.Close()
3632

37-
var data api
33+
type response struct {
34+
Announcements []announcement `json:"announcements"`
35+
}
36+
var data response
3837
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
3938
return fallbackData()
4039
}

ignite/pkg/announcements/announcement_test.go renamed to ignite/internal/announcements/announcement_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"net/http/httptest"
77
"testing"
88

9-
"github.com/ignite/cli/v29/ignite/pkg/announcements"
9+
"github.com/ignite/cli/v29/ignite/internal/announcements"
1010
)
1111

1212
func TestFetchAnnouncements(t *testing.T) {
@@ -52,9 +52,9 @@ func TestFetchAnnouncements(t *testing.T) {
5252
}))
5353
defer server.Close()
5454

55-
originalAPI := announcements.APIURL
56-
announcements.APIURL = server.URL
57-
defer func() { announcements.APIURL = originalAPI }()
55+
originalAPI := announcements.AnnouncementURL
56+
announcements.AnnouncementURL = server.URL
57+
defer func() { announcements.AnnouncementURL = originalAPI }()
5858

5959
result := announcements.Fetch()
6060
if result != tt.expected {

ignite/internal/buf/buf.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package buf
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"time"
7+
8+
"github.com/ignite/cli/v29/ignite/pkg/errors"
9+
)
10+
11+
var BufTokenURL = "https://buf.ignite.com" //nolint:gosec // URL is hardcoded and not user-provided
12+
13+
// FetchToken fetches the buf token from the Ignite API.
14+
func FetchToken() (string, error) {
15+
client := &http.Client{
16+
Timeout: 5 * time.Second,
17+
}
18+
19+
resp, err := client.Get(BufTokenURL)
20+
if err != nil {
21+
return "", err
22+
}
23+
defer resp.Body.Close()
24+
25+
if resp.StatusCode != http.StatusOK {
26+
return "", errors.Errorf("HTTP request failed with status code: %d", resp.StatusCode)
27+
}
28+
29+
type tokenResponse struct {
30+
Token string `json:"token"`
31+
}
32+
var tokenResp tokenResponse
33+
34+
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
35+
return "", err
36+
}
37+
38+
return tokenResp.Token, nil
39+
}

ignite/internal/buf/buf_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package buf_test
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/ignite/cli/v29/ignite/internal/buf"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestFetchToken(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
serverResponse string
16+
statusCode int
17+
expectedToken string
18+
expectError bool
19+
}{
20+
{
21+
name: "successful token fetch",
22+
serverResponse: `{"token":"test_token_123"}`,
23+
statusCode: http.StatusOK,
24+
expectedToken: "test_token_123",
25+
expectError: false,
26+
},
27+
{
28+
name: "server error",
29+
serverResponse: `{"error":"internal server error"}`,
30+
statusCode: http.StatusInternalServerError,
31+
expectedToken: "",
32+
expectError: true,
33+
},
34+
{
35+
name: "invalid json response",
36+
serverResponse: `invalid json`,
37+
statusCode: http.StatusOK,
38+
expectedToken: "",
39+
expectError: true,
40+
},
41+
}
42+
43+
for _, tt := range tests {
44+
t.Run(tt.name, func(t *testing.T) {
45+
// Create mock server
46+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
47+
w.WriteHeader(tt.statusCode)
48+
w.Write([]byte(tt.serverResponse))
49+
}))
50+
defer server.Close()
51+
52+
// Temporarily override the endpoint
53+
originalEndpoint := buf.BufTokenURL
54+
buf.BufTokenURL = server.URL
55+
defer func() {
56+
buf.BufTokenURL = originalEndpoint
57+
}()
58+
59+
token, err := buf.FetchToken()
60+
if tt.expectError {
61+
require.Error(t, err)
62+
require.Empty(t, token)
63+
} else {
64+
require.NoError(t, err)
65+
require.Equal(t, tt.expectedToken, token)
66+
}
67+
})
68+
}
69+
}

ignite/pkg/cosmosgen/generate_typescript.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"golang.org/x/sync/errgroup"
1313

14+
"github.com/ignite/cli/v29/ignite/internal/buf"
1415
"github.com/ignite/cli/v29/ignite/pkg/cache"
1516
"github.com/ignite/cli/v29/ignite/pkg/cosmosanalysis/module"
1617
"github.com/ignite/cli/v29/ignite/pkg/cosmosbuf"
@@ -19,6 +20,8 @@ import (
1920
)
2021

2122
var (
23+
bufTokenEnvName = "BUF_TOKEN"
24+
2225
dirchangeCacheNamespace = "generate.typescript.dirchange"
2326

2427
protocGenTSProtoBin = "protoc-gen-ts_proto"
@@ -31,15 +34,21 @@ plugins:
3134
- plugin: ts_proto
3235
out: .
3336
opt:
34-
- "esModuleInterop=true"
35-
- "forceLong=long"
36-
- "useOptionals=true"
37+
- logtostderr=true
38+
- allow_merge=true
39+
- json_names_for_fields=false
40+
- ts_proto_opt=snakeToCamel=true
41+
- ts_proto_opt=esModuleInterop=true
42+
- ts_proto_out=.
3743
`
3844

3945
type tsGenerator struct {
4046
g *generator
4147
tsTemplateFile string
4248
isLocalProto bool
49+
50+
// hasLocalBufToken indicates whether the user had already a local Buf token.
51+
hasLocalBufToken bool
4352
}
4453

4554
type generatePayload struct {
@@ -54,7 +63,16 @@ func newTSGenerator(g *generator) *tsGenerator {
5463
}
5564

5665
if !tsg.isLocalProto {
57-
log.Printf("No '%s' binary found in PATH, using remote buf plugin for Typescript generation. %s\n", protocGenTSProtoBin, msgBufAuth)
66+
if os.Getenv(bufTokenEnvName) == "" {
67+
token, err := buf.FetchToken()
68+
if err != nil {
69+
log.Printf("No '%s' binary found in PATH, using remote buf plugin for Typescript generation. %s\n", protocGenTSProtoBin, msgBufAuth)
70+
} else {
71+
os.Setenv(bufTokenEnvName, token)
72+
}
73+
} else {
74+
tsg.hasLocalBufToken = true
75+
}
5876
}
5977

6078
return tsg
@@ -83,6 +101,11 @@ func (g *tsGenerator) cleanup() {
83101
if g.tsTemplateFile != "" {
84102
os.Remove(g.tsTemplateFile)
85103
}
104+
105+
// unset ignite buf token from env
106+
if !g.hasLocalBufToken {
107+
os.Unsetenv(bufTokenEnvName)
108+
}
86109
}
87110

88111
func (g *generator) tsTemplate() string {

0 commit comments

Comments
 (0)