From bd6d6078a909b7997f82794c70f3336dfc320802 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 8 Mar 2025 06:27:21 +0000 Subject: [PATCH 01/23] feat(client): allow custom baseurls without trailing slash (#69) --- option/requestoption.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/option/requestoption.go b/option/requestoption.go index 811c1cb..cb983fe 100644 --- a/option/requestoption.go +++ b/option/requestoption.go @@ -9,6 +9,7 @@ import ( "log" "net/http" "net/url" + "strings" "time" "github.com/OneBusAway/go-sdk/internal/requestconfig" @@ -29,6 +30,9 @@ func WithBaseURL(base string) RequestOption { log.Fatalf("failed to parse BaseURL: %s\n", err) } return func(r *requestconfig.RequestConfig) error { + if u.Path != "" && !strings.HasSuffix(u.Path, "/") { + u.Path += "/" + } r.BaseURL = u return nil } From 249be00c6f37b9927493404b8d15f25cfce2a09c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 08:11:23 +0000 Subject: [PATCH 02/23] feat: add SKIP_BREW env var to ./scripts/bootstrap (#71) --- scripts/bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bootstrap b/scripts/bootstrap index ed03e52..99810d3 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then brew bundle check >/dev/null 2>&1 || { echo "==> Installing Homebrew dependencies…" brew bundle From 8496c56f4eeef5023732a2df3c9520245273a693 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 08:31:14 +0000 Subject: [PATCH 03/23] feat(client): accept RFC6838 JSON content types (#72) --- internal/requestconfig/requestconfig.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index 1e75799..04cee33 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -10,6 +10,7 @@ import ( "io" "math" "math/rand" + "mime" "net/http" "net/url" "runtime" @@ -485,7 +486,8 @@ func (cfg *RequestConfig) Execute() (err error) { // If we are not json, return plaintext contentType := res.Header.Get("content-type") - isJSON := strings.Contains(contentType, "application/json") || strings.Contains(contentType, "application/vnd.api+json") + mediaType, _, _ := mime.ParseMediaType(contentType) + isJSON := strings.Contains(mediaType, "application/json") || strings.HasSuffix(mediaType, "+json") if !isJSON { switch dst := cfg.ResponseBodyInto.(type) { case *string: @@ -496,7 +498,7 @@ func (cfg *RequestConfig) Execute() (err error) { case *[]byte: *dst = contents default: - return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type that is not 'application/json'") + return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type '%s' that is not 'application/json'", contentType) } return nil } From d2fd02d6c29f38cffaef48b61e50b3e34101daae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 08:35:37 +0000 Subject: [PATCH 04/23] refactor: tidy up dependencies (#73) --- go.mod | 8 +++++--- go.sum | 2 -- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 49c8594..4c8f759 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,11 @@ module github.com/OneBusAway/go-sdk go 1.21 require ( - github.com/google/uuid v1.3.0 // indirect - github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/gjson v1.14.4 + github.com/tidwall/sjson v1.2.5 +) + +require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/tidwall/sjson v1.2.5 // indirect ) diff --git a/go.sum b/go.sum index 569e555..a70a5e0 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= From 703d7bce4e38e23971f26e64a99b335b2417785b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 06:02:52 +0000 Subject: [PATCH 05/23] feat(client): improve default client options support (#74) --- client.go | 16 ++++-- internal/requestconfig/requestconfig.go | 43 +++++++++++++-- option/requestoption.go | 70 ++++++++++++------------- 3 files changed, 84 insertions(+), 45 deletions(-) diff --git a/client.go b/client.go index eac19b9..6db3a5b 100644 --- a/client.go +++ b/client.go @@ -46,16 +46,22 @@ type Client struct { Shape *ShapeService } +// DefaultClientOptions read from the environment (ONEBUSAWAY_API_KEY). This should +// be used to initialize new clients. +func DefaultClientOptions() []option.RequestOption { + defaults := []option.RequestOption{option.WithEnvironmentProduction()} + if o, ok := os.LookupEnv("ONEBUSAWAY_API_KEY"); ok { + defaults = append(defaults, option.WithAPIKey(o)) + } + return defaults +} + // NewClient generates a new client with the default option read from the // environment (ONEBUSAWAY_API_KEY). The option passed in as arguments are applied // after these default arguments, and all option will be passed down to the // services and requests that this client makes. func NewClient(opts ...option.RequestOption) (r *Client) { - defaults := []option.RequestOption{option.WithEnvironmentProduction()} - if o, ok := os.LookupEnv("ONEBUSAWAY_API_KEY"); ok { - defaults = append(defaults, option.WithAPIKey(o)) - } - opts = append(defaults, opts...) + opts = append(DefaultClientOptions(), opts...) r = &Client{Options: opts} diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index 04cee33..579aaf2 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -22,6 +22,7 @@ import ( "github.com/OneBusAway/go-sdk/internal/apierror" "github.com/OneBusAway/go-sdk/internal/apiform" "github.com/OneBusAway/go-sdk/internal/apiquery" + "github.com/OneBusAway/go-sdk/internal/param" ) func getDefaultHeaders() map[string]string { @@ -77,7 +78,17 @@ func getPlatformProperties() map[string]string { } } -func NewRequestConfig(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...func(*RequestConfig) error) (*RequestConfig, error) { +type RequestOption interface { + Apply(*RequestConfig) error +} + +type RequestOptionFunc func(*RequestConfig) error +type PreRequestOptionFunc func(*RequestConfig) error + +func (s RequestOptionFunc) Apply(r *RequestConfig) error { return s(r) } +func (s PreRequestOptionFunc) Apply(r *RequestConfig) error { return s(r) } + +func NewRequestConfig(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...RequestOption) (*RequestConfig, error) { var reader io.Reader contentType := "application/json" @@ -174,10 +185,17 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa return &cfg, nil } +func UseDefaultParam[T any](dst *param.Field[T], src *T) { + if !dst.Present && src != nil { + dst.Value = *src + dst.Present = true + } +} + // RequestConfig represents all the state related to one request. // // Editing the variables inside RequestConfig directly is unstable api. Prefer -// composing func(\*RequestConfig) error instead if possible. +// composing the RequestOption instead if possible. type RequestConfig struct { MaxRetries int RequestTimeout time.Duration @@ -517,7 +535,7 @@ func (cfg *RequestConfig) Execute() (err error) { return nil } -func ExecuteNewRequest(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...func(*RequestConfig) error) error { +func ExecuteNewRequest(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...RequestOption) error { cfg, err := NewRequestConfig(ctx, method, u, body, dst, opts...) if err != nil { return err @@ -551,12 +569,27 @@ func (cfg *RequestConfig) Clone(ctx context.Context) *RequestConfig { return new } -func (cfg *RequestConfig) Apply(opts ...func(*RequestConfig) error) error { +func (cfg *RequestConfig) Apply(opts ...RequestOption) error { for _, opt := range opts { - err := opt(cfg) + err := opt.Apply(cfg) if err != nil { return err } } return nil } + +func PreRequestOptions(opts ...RequestOption) (RequestConfig, error) { + cfg := RequestConfig{} + for _, opt := range opts { + if _, ok := opt.(PreRequestOptionFunc); !ok { + continue + } + + err := opt.Apply(&cfg) + if err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/option/requestoption.go b/option/requestoption.go index cb983fe..5ca864c 100644 --- a/option/requestoption.go +++ b/option/requestoption.go @@ -21,7 +21,7 @@ import ( // options pattern in our [README]. // // [README]: https://pkg.go.dev/github.com/OneBusAway/go-sdk#readme-requestoptions -type RequestOption = func(*requestconfig.RequestConfig) error +type RequestOption = requestconfig.RequestOption // WithBaseURL returns a RequestOption that sets the BaseURL for the client. func WithBaseURL(base string) RequestOption { @@ -29,22 +29,22 @@ func WithBaseURL(base string) RequestOption { if err != nil { log.Fatalf("failed to parse BaseURL: %s\n", err) } - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { if u.Path != "" && !strings.HasSuffix(u.Path, "/") { u.Path += "/" } r.BaseURL = u return nil - } + }) } // WithHTTPClient returns a RequestOption that changes the underlying [http.Client] used to make this // request, which by default is [http.DefaultClient]. func WithHTTPClient(client *http.Client) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.HTTPClient = client return nil - } + }) } // MiddlewareNext is a function which is called by a middleware to pass an HTTP request @@ -59,10 +59,10 @@ type Middleware = func(*http.Request, MiddlewareNext) (*http.Response, error) // WithMiddleware returns a RequestOption that applies the given middleware // to the requests made. Each middleware will execute in the order they were given. func WithMiddleware(middlewares ...Middleware) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.Middlewares = append(r.Middlewares, middlewares...) return nil - } + }) } // WithMaxRetries returns a RequestOption that sets the maximum number of retries that the client @@ -74,68 +74,68 @@ func WithMaxRetries(retries int) RequestOption { if retries < 0 { panic("option: cannot have fewer than 0 retries") } - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.MaxRetries = retries return nil - } + }) } // WithHeader returns a RequestOption that sets the header value to the associated key. It overwrites // any value if there was one already present. func WithHeader(key, value string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.Request.Header.Set(key, value) return nil - } + }) } // WithHeaderAdd returns a RequestOption that adds the header value to the associated key. It appends // onto any existing values. func WithHeaderAdd(key, value string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.Request.Header.Add(key, value) return nil - } + }) } // WithHeaderDel returns a RequestOption that deletes the header value(s) associated with the given key. func WithHeaderDel(key string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.Request.Header.Del(key) return nil - } + }) } // WithQuery returns a RequestOption that sets the query value to the associated key. It overwrites // any value if there was one already present. func WithQuery(key, value string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { query := r.Request.URL.Query() query.Set(key, value) r.Request.URL.RawQuery = query.Encode() return nil - } + }) } // WithQueryAdd returns a RequestOption that adds the query value to the associated key. It appends // onto any existing values. func WithQueryAdd(key, value string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { query := r.Request.URL.Query() query.Add(key, value) r.Request.URL.RawQuery = query.Encode() return nil - } + }) } // WithQueryDel returns a RequestOption that deletes the query value(s) associated with the key. func WithQueryDel(key string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { query := r.Request.URL.Query() query.Del(key) r.Request.URL.RawQuery = query.Encode() return nil - } + }) } // WithJSONSet returns a RequestOption that sets the body's JSON value associated with the key. @@ -143,7 +143,7 @@ func WithQueryDel(key string) RequestOption { // // [sjson format]: https://github.com/tidwall/sjson func WithJSONSet(key string, value interface{}) RequestOption { - return func(r *requestconfig.RequestConfig) (err error) { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) { if buffer, ok := r.Body.(*bytes.Buffer); ok { b := buffer.Bytes() b, err = sjson.SetBytes(b, key, value) @@ -155,7 +155,7 @@ func WithJSONSet(key string, value interface{}) RequestOption { } return fmt.Errorf("cannot use WithJSONSet on a body that is not serialized as *bytes.Buffer") - } + }) } // WithJSONDel returns a RequestOption that deletes the body's JSON value associated with the key. @@ -163,7 +163,7 @@ func WithJSONSet(key string, value interface{}) RequestOption { // // [sjson format]: https://github.com/tidwall/sjson func WithJSONDel(key string) RequestOption { - return func(r *requestconfig.RequestConfig) (err error) { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) { if buffer, ok := r.Body.(*bytes.Buffer); ok { b := buffer.Bytes() b, err = sjson.DeleteBytes(b, key) @@ -175,24 +175,24 @@ func WithJSONDel(key string) RequestOption { } return fmt.Errorf("cannot use WithJSONDel on a body that is not serialized as *bytes.Buffer") - } + }) } // WithResponseBodyInto returns a RequestOption that overwrites the deserialization target with // the given destination. If provided, we don't deserialize into the default struct. func WithResponseBodyInto(dst any) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.ResponseBodyInto = dst return nil - } + }) } // WithResponseInto returns a RequestOption that copies the [*http.Response] into the given address. func WithResponseInto(dst **http.Response) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.ResponseInto = dst return nil - } + }) } // WithRequestBody returns a RequestOption that provides a custom serialized body with the given @@ -200,7 +200,7 @@ func WithResponseInto(dst **http.Response) RequestOption { // // body accepts an io.Reader or raw []bytes. func WithRequestBody(contentType string, body any) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { if reader, ok := body.(io.Reader); ok { r.Body = reader return r.Apply(WithHeader("Content-Type", contentType)) @@ -212,17 +212,17 @@ func WithRequestBody(contentType string, body any) RequestOption { } return fmt.Errorf("body must be a byte slice or implement io.Reader") - } + }) } // WithRequestTimeout returns a RequestOption that sets the timeout for // each request attempt. This should be smaller than the timeout defined in // the context, which spans all retries. func WithRequestTimeout(dur time.Duration) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.RequestTimeout = dur return nil - } + }) } // WithEnvironmentProduction returns a RequestOption that sets the current @@ -234,8 +234,8 @@ func WithEnvironmentProduction() RequestOption { // WithAPIKey returns a RequestOption that sets the client setting "api_key". func WithAPIKey(value string) RequestOption { - return func(r *requestconfig.RequestConfig) error { + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { r.APIKey = value return r.Apply(WithQuery("key", r.APIKey)) - } + }) } From b943debfa05d346f776ea79477e83d6d382d81f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 06:11:49 +0000 Subject: [PATCH 06/23] chore(internal): remove extra empty newlines (#75) --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 901e734..a52ec3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,4 +41,3 @@ jobs: - name: Run tests run: ./scripts/test - From 301ca94a7f6f7925d76ce9031fc9733ccda4dfce Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 04:04:49 +0000 Subject: [PATCH 07/23] chore(docs): improve security documentation (#76) --- option/requestoption.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/option/requestoption.go b/option/requestoption.go index 5ca864c..bf25f68 100644 --- a/option/requestoption.go +++ b/option/requestoption.go @@ -24,6 +24,8 @@ import ( type RequestOption = requestconfig.RequestOption // WithBaseURL returns a RequestOption that sets the BaseURL for the client. +// +// For security reasons, ensure that the base URL is trusted. func WithBaseURL(base string) RequestOption { u, err := url.Parse(base) if err != nil { From a1409d69548e61a745a2ccaf308657ee43f1bfcb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 03:36:58 +0000 Subject: [PATCH 08/23] chore: add request options to client tests (#77) --- client_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client_test.go b/client_test.go index 6de1021..e1ef627 100644 --- a/client_test.go +++ b/client_test.go @@ -26,6 +26,7 @@ func (t *closureTransport) RoundTrip(req *http.Request) (*http.Response, error) func TestUserAgentHeader(t *testing.T) { var userAgent string client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -46,6 +47,7 @@ func TestUserAgentHeader(t *testing.T) { func TestRetryAfter(t *testing.T) { retryCountHeaders := make([]string, 0) client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -79,6 +81,7 @@ func TestRetryAfter(t *testing.T) { func TestDeleteRetryCountHeader(t *testing.T) { retryCountHeaders := make([]string, 0) client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -108,6 +111,7 @@ func TestDeleteRetryCountHeader(t *testing.T) { func TestOverwriteRetryCountHeader(t *testing.T) { retryCountHeaders := make([]string, 0) client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -137,6 +141,7 @@ func TestOverwriteRetryCountHeader(t *testing.T) { func TestRetryAfterMs(t *testing.T) { attempts := 0 client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -162,6 +167,7 @@ func TestRetryAfterMs(t *testing.T) { func TestContextCancel(t *testing.T) { client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -181,6 +187,7 @@ func TestContextCancel(t *testing.T) { func TestContextCancelDelay(t *testing.T) { client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { @@ -208,6 +215,7 @@ func TestContextDeadline(t *testing.T) { go func() { client := onebusaway.NewClient( + option.WithAPIKey("My API Key"), option.WithHTTPClient(&http.Client{ Transport: &closureTransport{ fn: func(req *http.Request) (*http.Response, error) { From a3975d5cfc9c9323ae81c7be878459ce73eac1a0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 03:37:54 +0000 Subject: [PATCH 09/23] fix(test): return early after test failure (#78) --- usage_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/usage_test.go b/usage_test.go index 2ce5120..1d3108f 100644 --- a/usage_test.go +++ b/usage_test.go @@ -27,6 +27,7 @@ func TestUsage(t *testing.T) { currentTime, err := client.CurrentTime.Get(context.TODO()) if err != nil { t.Error(err) + return } t.Logf("%+v\n", currentTime) } From 1b71db2b5d785c5657c8e2efed3202f562a941c8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 04:05:24 +0000 Subject: [PATCH 10/23] chore: fix typos (#79) --- internal/requestconfig/requestconfig.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index 579aaf2..69d4498 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -241,7 +241,7 @@ func shouldRetry(req *http.Request, res *http.Response) bool { return true } - // If the header explictly wants a retry behavior, respect that over the + // If the header explicitly wants a retry behavior, respect that over the // http status code. if res.Header.Get("x-should-retry") == "true" { return true From 5a6d7abfb6b3dde4ea259d4b99f9a28a9e266757 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 04:06:14 +0000 Subject: [PATCH 11/23] codegen metadata --- .stats.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.stats.yml b/.stats.yml index d4b713b..2de8424 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,4 @@ configured_endpoints: 29 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/open-transit%2Fopen-transit-6f08502508c8ad25235971add3124a1cde4f1c3ec705d5df455d750e0adcb90b.yml +openapi_spec_hash: 84d082f35446d29c7db3cfcd259e9859 +config_hash: c7e112ec9853ad18fe92551ae0d97656 From 70a742db5646d7a6c7c5ded09029a1fe76c989b2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 09:33:36 +0000 Subject: [PATCH 12/23] fix(client): return error on bad custom url instead of panic (#80) --- option/requestoption.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/option/requestoption.go b/option/requestoption.go index bf25f68..66aff82 100644 --- a/option/requestoption.go +++ b/option/requestoption.go @@ -6,7 +6,6 @@ import ( "bytes" "fmt" "io" - "log" "net/http" "net/url" "strings" @@ -28,10 +27,11 @@ type RequestOption = requestconfig.RequestOption // For security reasons, ensure that the base URL is trusted. func WithBaseURL(base string) RequestOption { u, err := url.Parse(base) - if err != nil { - log.Fatalf("failed to parse BaseURL: %s\n", err) - } return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { + if err != nil { + return fmt.Errorf("requestoption: WithBaseURL failed to parse url %s\n", err) + } + if u.Path != "" && !strings.HasSuffix(u.Path, "/") { u.Path += "/" } From 19d138e89e3926508836ef3ff7cf6b7b95abef3f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 03:10:55 +0000 Subject: [PATCH 13/23] feat(client): support custom http clients (#81) --- internal/requestconfig/requestconfig.go | 10 +++++++++ option/requestoption.go | 29 ++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index 69d4498..ebc4289 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -192,6 +192,12 @@ func UseDefaultParam[T any](dst *param.Field[T], src *T) { } } +// This interface is primarily used to describe an [*http.Client], but also +// supports custom HTTP implementations. +type HTTPDoer interface { + Do(req *http.Request) (*http.Response, error) +} + // RequestConfig represents all the state related to one request. // // Editing the variables inside RequestConfig directly is unstable api. Prefer @@ -202,6 +208,7 @@ type RequestConfig struct { Context context.Context Request *http.Request BaseURL *url.URL + CustomHTTPDoer HTTPDoer HTTPClient *http.Client Middlewares []middleware APIKey string @@ -399,6 +406,9 @@ func (cfg *RequestConfig) Execute() (err error) { } handler := cfg.HTTPClient.Do + if cfg.CustomHTTPDoer != nil { + handler = cfg.CustomHTTPDoer.Do + } for i := len(cfg.Middlewares) - 1; i >= 0; i -= 1 { handler = applyMiddleware(cfg.Middlewares[i], handler) } diff --git a/option/requestoption.go b/option/requestoption.go index 66aff82..c26cfcf 100644 --- a/option/requestoption.go +++ b/option/requestoption.go @@ -40,11 +40,34 @@ func WithBaseURL(base string) RequestOption { }) } -// WithHTTPClient returns a RequestOption that changes the underlying [http.Client] used to make this +// HTTPClient is primarily used to describe an [*http.Client], but also +// supports custom implementations. +// +// For bespoke implementations, prefer using an [*http.Client] with a +// custom transport. See [http.RoundTripper] for further information. +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} + +// WithHTTPClient returns a RequestOption that changes the underlying http client used to make this // request, which by default is [http.DefaultClient]. -func WithHTTPClient(client *http.Client) RequestOption { +// +// For custom uses cases, it is recommended to provide an [*http.Client] with a custom +// [http.RoundTripper] as its transport, rather than directly implementing [HTTPClient]. +func WithHTTPClient(client HTTPClient) RequestOption { return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { - r.HTTPClient = client + if client == nil { + return fmt.Errorf("requestoption: custom http client cannot be nil") + } + + if c, ok := client.(*http.Client); ok { + // Prefer the native client if possible. + r.HTTPClient = c + r.CustomHTTPDoer = nil + } else { + r.CustomHTTPDoer = client + } + return nil }) } From 39a0bd532bd1884c5c0354cec004ec8be274732c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:02:01 +0000 Subject: [PATCH 14/23] chore(internal): expand CI branch coverage --- .github/workflows/ci.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a52ec3b..85bc971 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ name: CI on: push: - branches: - - main - pull_request: - branches: - - main - - next + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'preview-head/**' + - 'preview-base/**' + - 'preview/**' jobs: lint: name: lint runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 @@ -27,7 +27,6 @@ jobs: test: name: test runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 From dd831b8fa18ed73c2a8170cf428f63697cfbf675 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:04:24 +0000 Subject: [PATCH 15/23] chore(internal): reduce CI branch coverage --- .github/workflows/ci.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85bc971..917696b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,17 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'preview-head/**' - - 'preview-base/**' - - 'preview/**' + branches: + - main + pull_request: + branches: + - main + - next jobs: lint: name: lint runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 From 82d21422f00dfe21f1562ea49406bc3671a9686e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 03:15:30 +0000 Subject: [PATCH 16/23] docs: update documentation links to be more uniform --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87a4bc9..e0d805d 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ Go Reference -The Onebusaway SDK Go library provides convenient access to [the Onebusaway SDK REST -API](https://developer.onebusaway.org) from applications written in Go. The full API of this library can be found in [api.md](api.md). +The Onebusaway SDK Go library provides convenient access to the [Onebusaway SDK REST API](https://developer.onebusaway.org) +from applications written in Go. It is generated with [Stainless](https://www.stainless.com/). From 1d1d81c5d5b5fc251bcf6c23faaf17356a765e8c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 02:53:04 +0000 Subject: [PATCH 17/23] chore(docs): document pre-request options --- internal/requestconfig/requestconfig.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index ebc4289..2c7482f 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -589,16 +589,20 @@ func (cfg *RequestConfig) Apply(opts ...RequestOption) error { return nil } +// PreRequestOptions is used to collect all the options which need to be known before +// a call to [RequestConfig.ExecuteNewRequest], such as path parameters +// or global defaults. +// PreRequestOptions will return a [RequestConfig] with the options applied. +// +// Only request option functions of type [PreRequestOptionFunc] are applied. func PreRequestOptions(opts ...RequestOption) (RequestConfig, error) { cfg := RequestConfig{} for _, opt := range opts { - if _, ok := opt.(PreRequestOptionFunc); !ok { - continue - } - - err := opt.Apply(&cfg) - if err != nil { - return cfg, err + if opt, ok := opt.(PreRequestOptionFunc); ok { + err := opt.Apply(&cfg) + if err != nil { + return cfg, err + } } } return cfg, nil From aa9e078338065441f57bbd9da3e0ab5c8ca31ee7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 02:56:29 +0000 Subject: [PATCH 18/23] feat(client): add support for reading base URL from environment variable --- client.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/client.go b/client.go index 6db3a5b..dd1e051 100644 --- a/client.go +++ b/client.go @@ -46,10 +46,13 @@ type Client struct { Shape *ShapeService } -// DefaultClientOptions read from the environment (ONEBUSAWAY_API_KEY). This should -// be used to initialize new clients. +// DefaultClientOptions read from the environment (ONEBUSAWAY_API_KEY, +// ONEBUSAWAY_SDK_BASE_URL). This should be used to initialize new clients. func DefaultClientOptions() []option.RequestOption { defaults := []option.RequestOption{option.WithEnvironmentProduction()} + if o, ok := os.LookupEnv("ONEBUSAWAY_SDK_BASE_URL"); ok { + defaults = append(defaults, option.WithBaseURL(o)) + } if o, ok := os.LookupEnv("ONEBUSAWAY_API_KEY"); ok { defaults = append(defaults, option.WithAPIKey(o)) } @@ -57,9 +60,9 @@ func DefaultClientOptions() []option.RequestOption { } // NewClient generates a new client with the default option read from the -// environment (ONEBUSAWAY_API_KEY). The option passed in as arguments are applied -// after these default arguments, and all option will be passed down to the -// services and requests that this client makes. +// environment (ONEBUSAWAY_API_KEY, ONEBUSAWAY_SDK_BASE_URL). The option passed in +// as arguments are applied after these default arguments, and all option will be +// passed down to the services and requests that this client makes. func NewClient(opts ...option.RequestOption) (r *Client) { opts = append(DefaultClientOptions(), opts...) From 6c4e05895395d160766d8186a39b923398927d9d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 03:45:03 +0000 Subject: [PATCH 19/23] chore(ci): add timeout thresholds for CI jobs --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 917696b..d22e236 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ on: jobs: lint: + timeout-minutes: 10 name: lint runs-on: ubuntu-latest steps: @@ -23,6 +24,7 @@ jobs: - name: Run lints run: ./scripts/lint test: + timeout-minutes: 10 name: test runs-on: ubuntu-latest steps: From db7e619fd67b7365885ca9964ffaa61d52e984e1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 02:41:30 +0000 Subject: [PATCH 20/23] chore(internal): codegen related update --- .github/workflows/ci.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d22e236..4b9fb4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,19 @@ name: CI on: push: - branches: - - main - pull_request: - branches: - - main - - next + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: timeout-minutes: 10 name: lint - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 + steps: - uses: actions/checkout@v4 @@ -26,7 +27,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 steps: - uses: actions/checkout@v4 From 27ea83482c078d8cff0077f180289833a0b4c7f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 02:41:53 +0000 Subject: [PATCH 21/23] chore(ci): only use depot for staging repos --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b9fb4c..2f9ee7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/open-transit-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -27,7 +27,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/open-transit-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 From f117b7d53c948c4b39f423a3bea6253db5883a9d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 03:03:12 +0000 Subject: [PATCH 22/23] fix: handle empty bodies in WithJSONSet --- option/requestoption.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/option/requestoption.go b/option/requestoption.go index c26cfcf..898c1fd 100644 --- a/option/requestoption.go +++ b/option/requestoption.go @@ -169,17 +169,26 @@ func WithQueryDel(key string) RequestOption { // [sjson format]: https://github.com/tidwall/sjson func WithJSONSet(key string, value interface{}) RequestOption { return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) { - if buffer, ok := r.Body.(*bytes.Buffer); ok { - b := buffer.Bytes() + var b []byte + + if r.Body == nil { + b, err = sjson.SetBytes(nil, key, value) + if err != nil { + return err + } + } else if buffer, ok := r.Body.(*bytes.Buffer); ok { + b = buffer.Bytes() b, err = sjson.SetBytes(b, key, value) if err != nil { return err } - r.Body = bytes.NewBuffer(b) return nil + } else { + return fmt.Errorf("cannot use WithJSONSet on a body that is not serialized as *bytes.Buffer") } - return fmt.Errorf("cannot use WithJSONSet on a body that is not serialized as *bytes.Buffer") + r.Body = bytes.NewBuffer(b) + return nil }) } From de2dbe63c0bf044d318103402cb47c49ee1d3c4b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 03:03:28 +0000 Subject: [PATCH 23/23] release: 0.1.0-alpha.24 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 44 +++++++++++++++++++++++++++++++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1c0bb88..380b6f9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.23" + ".": "0.1.0-alpha.24" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ec0b1a2..f2731cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # Changelog +## 0.1.0-alpha.24 (2025-04-30) + +Full Changelog: [v0.1.0-alpha.23...v0.1.0-alpha.24](https://github.com/OneBusAway/go-sdk/compare/v0.1.0-alpha.23...v0.1.0-alpha.24) + +### Features + +* add SKIP_BREW env var to ./scripts/bootstrap ([#71](https://github.com/OneBusAway/go-sdk/issues/71)) ([249be00](https://github.com/OneBusAway/go-sdk/commit/249be00c6f37b9927493404b8d15f25cfce2a09c)) +* **client:** accept RFC6838 JSON content types ([#72](https://github.com/OneBusAway/go-sdk/issues/72)) ([8496c56](https://github.com/OneBusAway/go-sdk/commit/8496c56f4eeef5023732a2df3c9520245273a693)) +* **client:** add support for reading base URL from environment variable ([aa9e078](https://github.com/OneBusAway/go-sdk/commit/aa9e078338065441f57bbd9da3e0ab5c8ca31ee7)) +* **client:** allow custom baseurls without trailing slash ([#69](https://github.com/OneBusAway/go-sdk/issues/69)) ([bd6d607](https://github.com/OneBusAway/go-sdk/commit/bd6d6078a909b7997f82794c70f3336dfc320802)) +* **client:** improve default client options support ([#74](https://github.com/OneBusAway/go-sdk/issues/74)) ([703d7bc](https://github.com/OneBusAway/go-sdk/commit/703d7bce4e38e23971f26e64a99b335b2417785b)) +* **client:** support custom http clients ([#81](https://github.com/OneBusAway/go-sdk/issues/81)) ([19d138e](https://github.com/OneBusAway/go-sdk/commit/19d138e89e3926508836ef3ff7cf6b7b95abef3f)) + + +### Bug Fixes + +* **client:** return error on bad custom url instead of panic ([#80](https://github.com/OneBusAway/go-sdk/issues/80)) ([70a742d](https://github.com/OneBusAway/go-sdk/commit/70a742db5646d7a6c7c5ded09029a1fe76c989b2)) +* handle empty bodies in WithJSONSet ([f117b7d](https://github.com/OneBusAway/go-sdk/commit/f117b7d53c948c4b39f423a3bea6253db5883a9d)) +* **test:** return early after test failure ([#78](https://github.com/OneBusAway/go-sdk/issues/78)) ([a3975d5](https://github.com/OneBusAway/go-sdk/commit/a3975d5cfc9c9323ae81c7be878459ce73eac1a0)) + + +### Chores + +* add request options to client tests ([#77](https://github.com/OneBusAway/go-sdk/issues/77)) ([a1409d6](https://github.com/OneBusAway/go-sdk/commit/a1409d69548e61a745a2ccaf308657ee43f1bfcb)) +* **ci:** add timeout thresholds for CI jobs ([6c4e058](https://github.com/OneBusAway/go-sdk/commit/6c4e05895395d160766d8186a39b923398927d9d)) +* **ci:** only use depot for staging repos ([27ea834](https://github.com/OneBusAway/go-sdk/commit/27ea83482c078d8cff0077f180289833a0b4c7f5)) +* **docs:** document pre-request options ([1d1d81c](https://github.com/OneBusAway/go-sdk/commit/1d1d81c5d5b5fc251bcf6c23faaf17356a765e8c)) +* **docs:** improve security documentation ([#76](https://github.com/OneBusAway/go-sdk/issues/76)) ([301ca94](https://github.com/OneBusAway/go-sdk/commit/301ca94a7f6f7925d76ce9031fc9733ccda4dfce)) +* fix typos ([#79](https://github.com/OneBusAway/go-sdk/issues/79)) ([1b71db2](https://github.com/OneBusAway/go-sdk/commit/1b71db2b5d785c5657c8e2efed3202f562a941c8)) +* **internal:** codegen related update ([db7e619](https://github.com/OneBusAway/go-sdk/commit/db7e619fd67b7365885ca9964ffaa61d52e984e1)) +* **internal:** expand CI branch coverage ([39a0bd5](https://github.com/OneBusAway/go-sdk/commit/39a0bd532bd1884c5c0354cec004ec8be274732c)) +* **internal:** reduce CI branch coverage ([dd831b8](https://github.com/OneBusAway/go-sdk/commit/dd831b8fa18ed73c2a8170cf428f63697cfbf675)) +* **internal:** remove extra empty newlines ([#75](https://github.com/OneBusAway/go-sdk/issues/75)) ([b943deb](https://github.com/OneBusAway/go-sdk/commit/b943debfa05d346f776ea79477e83d6d382d81f5)) + + +### Documentation + +* update documentation links to be more uniform ([82d2142](https://github.com/OneBusAway/go-sdk/commit/82d21422f00dfe21f1562ea49406bc3671a9686e)) + + +### Refactors + +* tidy up dependencies ([#73](https://github.com/OneBusAway/go-sdk/issues/73)) ([d2fd02d](https://github.com/OneBusAway/go-sdk/commit/d2fd02d6c29f38cffaef48b61e50b3e34101daae)) + ## 0.1.0-alpha.23 (2025-03-01) Full Changelog: [v0.1.0-alpha.22...v0.1.0-alpha.23](https://github.com/OneBusAway/go-sdk/compare/v0.1.0-alpha.22...v0.1.0-alpha.23) diff --git a/README.md b/README.md index e0d805d..8856391 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Or to pin the version: ```sh -go get -u 'github.com/OneBusAway/go-sdk@v0.1.0-alpha.23' +go get -u 'github.com/OneBusAway/go-sdk@v0.1.0-alpha.24' ``` diff --git a/internal/version.go b/internal/version.go index 9c3c699..1072dcb 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.1.0-alpha.23" // x-release-please-version +const PackageVersion = "0.1.0-alpha.24" // x-release-please-version