Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace shurcooL/graphql with hasura/go-graphql-client #281

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"net/url"
"strings"

"github.com/shurcooL/graphql"
"github.com/hasura/go-graphql-client"
"github.com/spacelift-io/spacectl/client/session"
"golang.org/x/oauth2"
)
Expand All @@ -22,13 +22,15 @@ func New(wraps *http.Client, session session.Session) Client {
return &client{wraps: wraps, session: session}
}

func (c *client) Mutate(ctx context.Context, mutation interface{}, variables map[string]interface{}, opts ...graphql.RequestOption) error {
apiClient, err := c.apiClient(ctx)
func (c *client) Mutate(ctx context.Context, mutation interface{}, variables map[string]interface{}, opts ...RequestOption) error {
options := parseOptions(opts...)

apiClient, err := c.apiClient(ctx, options)
if err != nil {
return nil
}

err = apiClient.Mutate(ctx, mutation, variables, opts...)
err = apiClient.Mutate(ctx, mutation, variables, options.graphqlOptions...)

if err != nil && err.Error() == "unauthorized" {
return fmt.Errorf("unauthorized: you can re-login using `spacectl profile login`")
Expand All @@ -37,13 +39,15 @@ func (c *client) Mutate(ctx context.Context, mutation interface{}, variables map
return err
}

func (c *client) Query(ctx context.Context, query interface{}, variables map[string]interface{}, opts ...graphql.RequestOption) error {
apiClient, err := c.apiClient(ctx)
func (c *client) Query(ctx context.Context, query interface{}, variables map[string]interface{}, opts ...RequestOption) error {
options := parseOptions(opts...)

apiClient, err := c.apiClient(ctx, options)
if err != nil {
return nil
}

err = apiClient.Query(ctx, query, variables, opts...)
err = apiClient.Query(ctx, query, variables, options.graphqlOptions...)

if err != nil && err.Error() == "unauthorized" {
return fmt.Errorf("unauthorized: you can re-login using `spacectl profile login`")
Expand All @@ -65,17 +69,18 @@ func (c *client) URL(format string, a ...interface{}) string {
return endpointURL.String()
}

func (c *client) apiClient(ctx context.Context) (*graphql.Client, error) {
func (c *client) apiClient(ctx context.Context, opts requestOptions) (*graphql.Client, error) {
httpC, err := c.httpClient(ctx)
if err != nil {
return nil, fmt.Errorf("graphql client creation failed at http client creation: %w", err)
}

requestOptions := []graphql.RequestOption{
graphql.WithHeader("Spacelift-Client-Type", "spacectl"),
}

return graphql.NewClient(c.session.Endpoint(), httpC, requestOptions...), nil
return graphql.NewClient(c.session.Endpoint(), httpC).WithRequestModifier(func(request *http.Request) {
request.Header.Set("Spacelift-Client-Type", "spacectl")
for _, modifyRequest := range opts.modifyRequest {
modifyRequest(request)
}
}), nil
}

func (c *client) Do(req *http.Request) (*http.Response, error) {
Expand Down
6 changes: 2 additions & 4 deletions client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ package client
import (
"context"
"net/http"

"github.com/shurcooL/graphql"
)

// Client abstracts away Spacelift's client API.
type Client interface {
// Query executes a single GraphQL query request.
Query(context.Context, interface{}, map[string]interface{}, ...graphql.RequestOption) error
Query(context.Context, interface{}, map[string]interface{}, ...RequestOption) error

// Mutate executes a single GraphQL mutation request.
Mutate(context.Context, interface{}, map[string]interface{}, ...graphql.RequestOption) error
Mutate(context.Context, interface{}, map[string]interface{}, ...RequestOption) error

// URL returns a full URL given a formatted path.
URL(string, ...interface{}) string
Expand Down
45 changes: 45 additions & 0 deletions client/request_option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package client

import (
"net/http"

"github.com/hasura/go-graphql-client"
)

type RequestOption func(*requestOptions)

// WithHeader sets a header on the request.
func WithHeader(key, value string) RequestOption {
return func(o *requestOptions) {
o.modifyRequest = append(o.modifyRequest, func(request *http.Request) {
request.Header.Set(key, value)
})
}
}

// WithModifyRequest allows you to modify the request before sending it to the server.
func WithModifyRequest(f func(request *http.Request)) RequestOption {
return func(o *requestOptions) {
o.modifyRequest = append(o.modifyRequest, f)
}
}

// WithGraphqlOptions sets [graphql.Option] options.
func WithGraphqlOptions(options ...graphql.Option) RequestOption {
return func(o *requestOptions) {
o.graphqlOptions = append(o.graphqlOptions, options...)
}
}

func parseOptions(options ...RequestOption) requestOptions {
var opts requestOptions
for _, opt := range options {
opt(&opts)
}
return opts
}

type requestOptions struct {
modifyRequest []func(*http.Request)
graphqlOptions []graphql.Option
}
4 changes: 2 additions & 2 deletions client/session/api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http"
"time"

"github.com/shurcooL/graphql"
"github.com/hasura/go-graphql-client"
)

// FromAPIKey builds a Spacelift session from a combination of endpoint, API key
Expand Down Expand Up @@ -57,7 +57,7 @@ func (g *apiKey) exchange(ctx context.Context) error {

variables := map[string]interface{}{
"id": graphql.ID(g.keyID),
"secret": graphql.String(g.keySecret),
"secret": g.keySecret,
}

if err := g.mutate(ctx, &mutation, variables); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion client/session/api_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/shurcooL/graphql"
"github.com/hasura/go-graphql-client"
)

// If the token is about to expire, we'd rather exchange it now than risk having
Expand Down
4 changes: 1 addition & 3 deletions client/session/github_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"fmt"
"net/http"
"time"

"github.com/shurcooL/graphql"
)

// FromGitHubToken builds a Spacelift session from a combination of endpoint,
Expand Down Expand Up @@ -54,7 +52,7 @@ func (g *gitHubToken) exchange(ctx context.Context) error {
APIKeyUser user `graphql:"oauthUser(token: $token)"`
}

variables := map[string]interface{}{"token": graphql.String(g.accessToken)}
variables := map[string]interface{}{"token": g.accessToken}

if err := g.mutate(ctx, &mutation, variables); err != nil {
return fmt.Errorf("could not exchange access token for Spacelift one: %w", err)
Expand Down
22 changes: 10 additions & 12 deletions client/structs/search.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
package structs

import "github.com/shurcooL/graphql"

// SearchInput is the main object provided to any search query.
type SearchInput struct {
First *graphql.Int `json:"first"`
After *graphql.String `json:"after"`
FullTextSearch *graphql.String `json:"fullTextSearch"`
First *int `json:"first"`
After *string `json:"after"`
FullTextSearch *string `json:"fullTextSearch"`
Predicates *[]QueryPredicate `json:"predicates"`
OrderBy *QueryOrder `json:"orderBy"`
}

// QueryOrder is the order in which the results
// should be returned.
type QueryOrder struct {
Field graphql.String `json:"field"`
Direction graphql.String `json:"direction"`
Field string `json:"field"`
Direction string `json:"direction"`
}

// QueryPredicate Field and Constraint pair
// for search input.
type QueryPredicate struct {
Field graphql.String `json:"field"`
Field string `json:"field"`
Constraint QueryFieldConstraint `json:"constraint"`
Exclude graphql.Boolean `json:"exclude"`
Exclude bool `json:"exclude"`
}

// QueryFieldConstraint is a constraint used
// in a search query.
type QueryFieldConstraint struct {
BooleanEquals *[]graphql.Boolean `json:"booleanEquals"`
EnumEquals *[]graphql.String `json:"enumEquals"`
StringMatches *[]graphql.String `json:"stringMatches"`
BooleanEquals *[]bool `json:"booleanEquals"`
EnumEquals *[]string `json:"enumEquals"`
StringMatches *[]string `json:"stringMatches"`
}

// PageInfo is the extra information about
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/cheggaaa/pb/v3 v3.1.5
github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/hasura/go-graphql-client v0.13.1
github.com/manifoldco/promptui v0.9.0
github.com/mattn/go-isatty v0.0.20
github.com/mholt/archiver/v3 v3.5.1
Expand All @@ -18,7 +19,6 @@ require (
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.79
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
github.com/urfave/cli/v2 v2.27.3
golang.org/x/oauth2 v0.22.0
golang.org/x/sync v0.10.0
Expand All @@ -40,6 +40,7 @@ require (
github.com/charmbracelet/x/windows v0.1.0 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/coder/websocket v1.8.12 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/dsnet/compress v0.0.1 // indirect
Expand All @@ -48,6 +49,7 @@ require (
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/klauspost/compress v1.9.2 // indirect
github.com/klauspost/pgzip v1.2.1 // indirect
Expand Down Expand Up @@ -76,5 +78,3 @@ require (
)

replace github.com/mholt/archiver/v3 => github.com/spacelift-io/archiver/v3 v3.3.1-0.20221117135619-d7d90ab08987

replace github.com/shurcooL/graphql => github.com/spacelift-io/graphql v1.2.0
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWs
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
Expand Down Expand Up @@ -85,10 +87,14 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/hasura/go-graphql-client v0.13.1 h1:kKbjhxhpwz58usVl+Xvgah/TDha5K2akNTRQdsEHN6U=
github.com/hasura/go-graphql-client v0.13.1/go.mod h1:k7FF7h53C+hSNFRG3++DdVZWIuHdCaTbI7siTJ//zGQ=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY=
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
Expand Down Expand Up @@ -162,8 +168,6 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/spacelift-io/archiver/v3 v3.3.1-0.20221117135619-d7d90ab08987 h1:L8buChChTRSHaGHco2ptAFivZUDYHhr7+OG5haf5FJI=
github.com/spacelift-io/archiver/v3 v3.3.1-0.20221117135619-d7d90ab08987/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao=
github.com/spacelift-io/graphql v1.2.0 h1:oUS1fyO4cqMGOcydu26BVbZkTf/pdDnLWVal6lYv49Q=
github.com/spacelift-io/graphql v1.2.0/go.mod h1:Q/JMkvFWF8uXZQkDn8i9Nc3aXucbgTFeuFZ6WQMt0Wg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down
36 changes: 10 additions & 26 deletions internal/cmd/blueprint/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

"github.com/pkg/errors"
"github.com/shurcooL/graphql"
"github.com/spacelift-io/spacectl/client/structs"
"github.com/spacelift-io/spacectl/internal"
"github.com/spacelift-io/spacectl/internal/cmd"
Expand Down Expand Up @@ -48,19 +47,14 @@ func listBlueprintsJSON(
search *string,
limit *uint,
) error {
var first *graphql.Int
var first *int
if limit != nil {
first = graphql.NewInt(graphql.Int(*limit)) //nolint: gosec
}

var fullTextSearch *graphql.String
if search != nil {
fullTextSearch = graphql.NewString(graphql.String(*search))
first = internal.Ptr(int(*limit))
}

blueprints, err := searchAllBlueprints(ctx.Context, structs.SearchInput{
First: first,
FullTextSearch: fullTextSearch,
FullTextSearch: search,
})
if err != nil {
return err
Expand All @@ -74,19 +68,14 @@ func listBlueprintsTable(
search *string,
limit *uint,
) error {
var first *graphql.Int
var first *int
if limit != nil {
first = graphql.NewInt(graphql.Int(*limit)) //nolint: gosec
}

var fullTextSearch *graphql.String
if search != nil {
fullTextSearch = graphql.NewString(graphql.String(*search))
first = internal.Ptr(int(*limit))
}

input := structs.SearchInput{
First: first,
FullTextSearch: fullTextSearch,
FullTextSearch: search,
OrderBy: &structs.QueryOrder{
Field: "name",
Direction: "DESC",
Expand Down Expand Up @@ -130,24 +119,19 @@ func searchAllBlueprints(ctx context.Context, input structs.SearchInput) ([]blue

var limit int
if input.First != nil {
limit = int(*input.First)
limit = *input.First
}
fetchAll := limit == 0

out := []blueprintNode{}
pageInput := structs.SearchInput{
First: graphql.NewInt(maxPageSize),
First: internal.Ptr(maxPageSize),
FullTextSearch: input.FullTextSearch,
}
for {
if !fetchAll {
// Fetch exactly the number of items requested
pageInput.First = graphql.NewInt(
//nolint: gosec
graphql.Int(
slices.Min([]int{maxPageSize, limit - len(out)}),
),
)
pageInput.First = internal.Ptr(slices.Min([]int{maxPageSize, limit - len(out)}))
}

result, err := searchBlueprints(ctx, pageInput)
Expand All @@ -158,7 +142,7 @@ func searchAllBlueprints(ctx context.Context, input structs.SearchInput) ([]blue
out = append(out, result.Blueprints...)

if result.PageInfo.HasNextPage && (fetchAll || limit > len(out)) {
pageInput.After = graphql.NewString(graphql.String(result.PageInfo.EndCursor))
pageInput.After = internal.Ptr(result.PageInfo.EndCursor)
} else {
break
}
Expand Down
Loading