-
Notifications
You must be signed in to change notification settings - Fork 237
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Moved the orb validation in a orb API module
- Loading branch information
1 parent
5b87507
commit 3dd9730
Showing
7 changed files
with
341 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package orb | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
|
||
"github.com/CircleCI-Public/circleci-cli/api" | ||
"github.com/CircleCI-Public/circleci-cli/api/graphql" | ||
"github.com/CircleCI-Public/circleci-cli/settings" | ||
) | ||
|
||
var ( | ||
once sync.Once | ||
client Client | ||
) | ||
|
||
// ConfigResponse is a structure that matches the result of the GQL | ||
// query, so that we can use mapstructure to convert from | ||
// nested maps to a strongly typed struct. | ||
type QueryResponse struct { | ||
OrbConfig struct { | ||
api.ConfigResponse | ||
} | ||
} | ||
|
||
type Client interface { | ||
OrbQuery(configPath string, ownerId string) (*api.ConfigResponse, error) | ||
} | ||
|
||
func GetClient(config *settings.Config) Client { | ||
once.Do(func() { | ||
createClient(config) | ||
}) | ||
return client | ||
} | ||
|
||
func createClient(config *settings.Config) { | ||
gql := graphql.NewClient(config.HTTPClient, config.Host, config.Endpoint, config.Token, config.Debug) | ||
|
||
ok, err := orbQueryHandleOwnerId(gql) | ||
if err != nil { | ||
fmt.Printf("While requesting orb server: %s", err) | ||
return | ||
} else if ok { | ||
client = &latestClient{gql} | ||
} else { | ||
client = &deprecatedClient{gql} | ||
} | ||
} | ||
|
||
type OrbIntrospectionResponse struct { | ||
Schema struct { | ||
Query struct { | ||
Fields []struct { | ||
Name string `json:"name"` | ||
Args []struct { | ||
Name string `json:"name"` | ||
} `json:"args"` | ||
} `json:"fields"` | ||
} `json:"queryType"` | ||
} `json:"__schema"` | ||
} | ||
|
||
func orbQueryHandleOwnerId(gql *graphql.Client) (bool, error) { | ||
query := ` | ||
query ValidateOrb { | ||
__schema { | ||
queryType { | ||
fields(includeDeprecated: true) { | ||
name | ||
args { | ||
name | ||
__typename | ||
type { | ||
name | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}` | ||
request := graphql.NewRequest(query) | ||
response := OrbIntrospectionResponse{} | ||
err := gql.Run(request, &response) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
request.SetToken(gql.Token) | ||
|
||
// Find the orbConfig query method, look at its arguments, if it has the "ownerId" argument, return true | ||
for _, field := range response.Schema.Query.Fields { | ||
if field.Name == "orbConfig" { | ||
for _, arg := range field.Args { | ||
if arg.Name == "ownerId" { | ||
return true, nil | ||
} | ||
} | ||
} | ||
} | ||
|
||
// else return false, ownerId is not supported | ||
|
||
return false, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package orb | ||
|
||
import ( | ||
"github.com/CircleCI-Public/circleci-cli/api" | ||
"github.com/CircleCI-Public/circleci-cli/api/graphql" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type deprecatedClient struct { | ||
gql *graphql.Client | ||
} | ||
|
||
func (deprecated *deprecatedClient) OrbQuery(configPath string, ownerId string) (*api.ConfigResponse, error) { | ||
if ownerId != "" { | ||
return nil, errors.New("Your version of Server does not support validating orbs that refer to other private orbs. Please see the README for more information on server compatibility: https://github.com/CircleCI-Public/circleci-cli#server-compatibility") | ||
} | ||
|
||
var response QueryResponse | ||
|
||
configContent, err := loadYaml(configPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
query := ` | ||
query ValidateOrb ($config: String!) { | ||
orbConfig(orbYaml: $config) { | ||
valid, | ||
errors { message }, | ||
sourceYaml, | ||
outputYaml | ||
} | ||
}` | ||
|
||
request := graphql.NewRequest(query) | ||
request.Var("config", configContent) | ||
|
||
request.SetToken(deprecated.gql.Token) | ||
|
||
err = deprecated.gql.Run(request, &response) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Unable to validate config") | ||
} | ||
|
||
if len(response.OrbConfig.ConfigResponse.Errors) > 0 { | ||
return nil, response.OrbConfig.ConfigResponse.Errors | ||
} | ||
|
||
return &response.OrbConfig.ConfigResponse, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package orb | ||
|
||
import ( | ||
"github.com/CircleCI-Public/circleci-cli/api" | ||
"github.com/CircleCI-Public/circleci-cli/api/graphql" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type latestClient struct { | ||
gql *graphql.Client | ||
} | ||
|
||
func (latest *latestClient) OrbQuery(configPath string, ownerId string) (*api.ConfigResponse, error) { | ||
var response QueryResponse | ||
|
||
configContent, err := loadYaml(configPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
query := ` | ||
query ValidateOrb ($config: String!, $owner: UUID) { | ||
orbConfig(orbYaml: $config, ownerId: $owner) { | ||
valid, | ||
errors { message }, | ||
sourceYaml, | ||
outputYaml | ||
} | ||
}` | ||
request := graphql.NewRequest(query) | ||
request.Var("config", configContent) | ||
|
||
if ownerId != "" { | ||
request.Var("owner", ownerId) | ||
} | ||
request.SetToken(latest.gql.Token) | ||
|
||
err = latest.gql.Run(request, &response) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Unable to validate config") | ||
} | ||
|
||
if len(response.OrbConfig.ConfigResponse.Errors) > 0 { | ||
return nil, response.OrbConfig.ConfigResponse.Errors | ||
} | ||
|
||
return &response.OrbConfig.ConfigResponse, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package orb | ||
|
||
import ( | ||
"io" | ||
"os" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
func loadYaml(path string) (string, error) { | ||
var err error | ||
var config []byte | ||
if path == "-" { | ||
config, err = io.ReadAll(os.Stdin) | ||
} else { | ||
config, err = os.ReadFile(path) | ||
} | ||
|
||
if err != nil { | ||
return "", errors.Wrapf(err, "Could not load config file at %s", path) | ||
} | ||
|
||
return string(config), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.