Skip to content

Commit 624523e

Browse files
author
JulesFaucherre
authored
Merge pull request #990 from CircleCI-Public/develop
Release
2 parents 83956f7 + 7c6c1ea commit 624523e

21 files changed

+740
-309
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ jobs:
253253
- attach_workspace:
254254
at: .
255255
- run: |
256-
TAG=$(./dist/circleci-cli_linux_amd64/circleci version | cut -d' ' -f 1) && export TAG
256+
TAG=$(./dist/circleci-cli_linux_amd64_v1/circleci version | cut -d' ' -f 1) && export TAG
257257
sed -i -- "s/%CLI_VERSION_PLACEHOLDER%/$TAG/g" snap/snapcraft.yaml
258258
- run: snapcraft
259259
- run:

api/api.go

Lines changed: 0 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -512,133 +512,6 @@ func WhoamiQuery(cl *graphql.Client) (*WhoamiResponse, error) {
512512
return &response, nil
513513
}
514514

515-
// OrbQuery validated and processes an orb.
516-
func OrbQuery(cl *graphql.Client, configPath string, ownerId string) (*ConfigResponse, error) {
517-
var response OrbConfigResponse
518-
519-
config, err := loadYaml(configPath)
520-
if err != nil {
521-
return nil, err
522-
}
523-
524-
request, err := makeOrbRequest(cl, config, ownerId)
525-
if err != nil {
526-
return nil, err
527-
}
528-
529-
err = cl.Run(request, &response)
530-
if err != nil {
531-
return nil, errors.Wrap(err, "Unable to validate config")
532-
}
533-
534-
if len(response.OrbConfig.ConfigResponse.Errors) > 0 {
535-
return nil, response.OrbConfig.ConfigResponse.Errors
536-
}
537-
538-
return &response.OrbConfig.ConfigResponse, nil
539-
}
540-
541-
func makeOrbRequest(cl *graphql.Client, configContent string, ownerId string) (*graphql.Request, error) {
542-
handlesOwner := orbQueryHandleOwnerId(cl)
543-
544-
if handlesOwner {
545-
query := `
546-
query ValidateOrb ($config: String!, $owner: UUID) {
547-
orbConfig(orbYaml: $config, ownerId: $owner) {
548-
valid,
549-
errors { message },
550-
sourceYaml,
551-
outputYaml
552-
}
553-
}`
554-
555-
request := graphql.NewRequest(query)
556-
request.Var("config", configContent)
557-
558-
if ownerId != "" {
559-
request.Var("owner", ownerId)
560-
}
561-
562-
request.SetToken(cl.Token)
563-
return request, nil
564-
}
565-
566-
if ownerId != "" {
567-
return nil, errors.Errorf("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")
568-
}
569-
query := `
570-
query ValidateOrb ($config: String!) {
571-
orbConfig(orbYaml: $config) {
572-
valid,
573-
errors { message },
574-
sourceYaml,
575-
outputYaml
576-
}
577-
}`
578-
579-
request := graphql.NewRequest(query)
580-
request.Var("config", configContent)
581-
582-
request.SetToken(cl.Token)
583-
return request, nil
584-
}
585-
586-
type OrbIntrospectionResponse struct {
587-
Schema struct {
588-
Query struct {
589-
Fields []struct {
590-
Name string `json:"name"`
591-
Args []struct {
592-
Name string `json:"name"`
593-
} `json:"args"`
594-
} `json:"fields"`
595-
} `json:"queryType"`
596-
} `json:"__schema"`
597-
}
598-
599-
func orbQueryHandleOwnerId(cl *graphql.Client) bool {
600-
query := `
601-
query ValidateOrb {
602-
__schema {
603-
queryType {
604-
fields(includeDeprecated: true) {
605-
name
606-
args {
607-
name
608-
__typename
609-
type {
610-
name
611-
}
612-
}
613-
}
614-
}
615-
}
616-
}`
617-
request := graphql.NewRequest(query)
618-
response := OrbIntrospectionResponse{}
619-
err := cl.Run(request, &response)
620-
if err != nil {
621-
return false
622-
}
623-
624-
request.SetToken(cl.Token)
625-
626-
// Find the orbConfig query method, look at its arguments, if it has the "ownerId" argument, return true
627-
for _, field := range response.Schema.Query.Fields {
628-
if field.Name == "orbConfig" {
629-
for _, arg := range field.Args {
630-
if arg.Name == "ownerId" {
631-
return true
632-
}
633-
}
634-
}
635-
}
636-
637-
// else return false, ownerId is not supported
638-
639-
return false
640-
}
641-
642515
// OrbImportVersion publishes a new version of an orb using the provided source and id.
643516
func OrbImportVersion(cl *graphql.Client, orbSrc string, orbID string, orbVersion string) (*Orb, error) {
644517
var response OrbImportVersionResponse

api/orb/client.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package orb
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
8+
"github.com/CircleCI-Public/circleci-cli/api"
9+
"github.com/CircleCI-Public/circleci-cli/api/graphql"
10+
"github.com/CircleCI-Public/circleci-cli/settings"
11+
"github.com/pkg/errors"
12+
)
13+
14+
type clientVersion string
15+
16+
// ConfigResponse is a structure that matches the result of the GQL
17+
// query, so that we can use mapstructure to convert from
18+
// nested maps to a strongly typed struct.
19+
type QueryResponse struct {
20+
OrbConfig struct {
21+
api.ConfigResponse
22+
}
23+
}
24+
25+
type Client interface {
26+
OrbQuery(configPath string, ownerId string) (*api.ConfigResponse, error)
27+
}
28+
29+
func NewClient(config *settings.Config) (Client, error) {
30+
gql := graphql.NewClient(config.HTTPClient, config.Host, config.Endpoint, config.Token, config.Debug)
31+
32+
clientVersion, err := detectClientVersion(gql)
33+
if err != nil {
34+
return nil, err
35+
}
36+
37+
switch clientVersion {
38+
case v1_string:
39+
return &v1Client{gql}, nil
40+
case v2_string:
41+
return &v2Client{gql}, nil
42+
default:
43+
return nil, fmt.Errorf("Unable to recognise your server orb API")
44+
}
45+
}
46+
47+
// detectClientVersion returns the highest available version of the orb API
48+
//
49+
// To do that it checks that whether the GraphQL query has the parameter "ownerId" or not.
50+
// If it does not have the parameter, the function returns `v1_string` else it returns `v2_string`
51+
func detectClientVersion(gql *graphql.Client) (clientVersion, error) {
52+
handlesOwnerId, err := orbQueryHandleOwnerId(gql)
53+
if err != nil {
54+
return "", err
55+
}
56+
if !handlesOwnerId {
57+
return v1_string, nil
58+
}
59+
return v2_string, nil
60+
}
61+
62+
type OrbIntrospectionResponse struct {
63+
Schema struct {
64+
Query struct {
65+
Fields []struct {
66+
Name string `json:"name"`
67+
Args []struct {
68+
Name string `json:"name"`
69+
} `json:"args"`
70+
} `json:"fields"`
71+
} `json:"queryType"`
72+
} `json:"__schema"`
73+
}
74+
75+
func orbQueryHandleOwnerId(gql *graphql.Client) (bool, error) {
76+
query := `query IntrospectionQuery {
77+
_schema {
78+
queryType {
79+
fields(includeDeprecated: true) {
80+
name
81+
args {
82+
name
83+
__typename
84+
type {
85+
name
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}`
92+
request := graphql.NewRequest(query)
93+
response := OrbIntrospectionResponse{}
94+
err := gql.Run(request, &response)
95+
if err != nil {
96+
return false, err
97+
}
98+
99+
request.SetToken(gql.Token)
100+
101+
// Find the orbConfig query method, look at its arguments, if it has the "ownerId" argument, return true
102+
for _, field := range response.Schema.Query.Fields {
103+
if field.Name == "orbConfig" {
104+
for _, arg := range field.Args {
105+
if arg.Name == "ownerId" {
106+
return true, nil
107+
}
108+
}
109+
}
110+
}
111+
112+
// else return false, ownerId is not supported
113+
114+
return false, nil
115+
}
116+
117+
func loadYaml(path string) (string, error) {
118+
var err error
119+
var config []byte
120+
if path == "-" {
121+
config, err = io.ReadAll(os.Stdin)
122+
} else {
123+
config, err = os.ReadFile(path)
124+
}
125+
126+
if err != nil {
127+
return "", errors.Wrapf(err, "Could not load config file at %s", path)
128+
}
129+
130+
return string(config), nil
131+
}

api/orb/v1_client.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package orb
2+
3+
import (
4+
"github.com/CircleCI-Public/circleci-cli/api"
5+
"github.com/CircleCI-Public/circleci-cli/api/graphql"
6+
"github.com/pkg/errors"
7+
)
8+
9+
// This client makes request to servers that **DON'T** have the field `ownerId` in the GraphQL query method: `orbConfig`
10+
11+
const v1_string clientVersion = "v1"
12+
13+
type v1Client struct {
14+
gql *graphql.Client
15+
}
16+
17+
func (client *v1Client) OrbQuery(configPath string, ownerId string) (*api.ConfigResponse, error) {
18+
if ownerId != "" {
19+
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")
20+
}
21+
22+
var response QueryResponse
23+
24+
configContent, err := loadYaml(configPath)
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
query := `query ValidateOrb ($config: String!) {
30+
orbConfig(orbYaml: $config) {
31+
valid,
32+
errors { message },
33+
sourceYaml,
34+
outputYaml
35+
}
36+
}`
37+
38+
request := graphql.NewRequest(query)
39+
request.Var("config", configContent)
40+
41+
request.SetToken(client.gql.Token)
42+
43+
err = client.gql.Run(request, &response)
44+
if err != nil {
45+
return nil, errors.Wrap(err, "Validating config")
46+
}
47+
48+
if len(response.OrbConfig.ConfigResponse.Errors) > 0 {
49+
return nil, response.OrbConfig.ConfigResponse.Errors
50+
}
51+
52+
return &response.OrbConfig.ConfigResponse, nil
53+
}

api/orb/v2_client.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package orb
2+
3+
import (
4+
"github.com/CircleCI-Public/circleci-cli/api"
5+
"github.com/CircleCI-Public/circleci-cli/api/graphql"
6+
"github.com/pkg/errors"
7+
)
8+
9+
// This client makes request to servers that **DO** have the field `ownerId` in the GraphQL query method: `orbConfig`
10+
11+
const v2_string clientVersion = "v2"
12+
13+
type v2Client struct {
14+
gql *graphql.Client
15+
}
16+
17+
func (client *v2Client) OrbQuery(configPath string, ownerId string) (*api.ConfigResponse, error) {
18+
var response QueryResponse
19+
20+
configContent, err := loadYaml(configPath)
21+
if err != nil {
22+
return nil, err
23+
}
24+
25+
query := `query ValidateOrb ($config: String!, $owner: UUID) {
26+
orbConfig(orbYaml: $config, ownerId: $owner) {
27+
valid,
28+
errors { message },
29+
sourceYaml,
30+
outputYaml
31+
}
32+
}`
33+
34+
request := graphql.NewRequest(query)
35+
request.Var("config", configContent)
36+
37+
if ownerId != "" {
38+
request.Var("owner", ownerId)
39+
}
40+
request.SetToken(client.gql.Token)
41+
42+
err = client.gql.Run(request, &response)
43+
if err != nil {
44+
return nil, errors.Wrap(err, "Validating config")
45+
}
46+
47+
if len(response.OrbConfig.ConfigResponse.Errors) > 0 {
48+
return nil, response.OrbConfig.ConfigResponse.Errors
49+
}
50+
51+
return &response.OrbConfig.ConfigResponse, nil
52+
}

0 commit comments

Comments
 (0)