From 1e54f4de18198c07b7fec895c2528e99281f6681 Mon Sep 17 00:00:00 2001 From: kelvintaywl Date: Tue, 15 Nov 2022 16:13:24 +0900 Subject: [PATCH 01/10] feat: allow installer to download releases for ARM64 --- install.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index cac9c1989..fda7ef11d 100755 --- a/install.sh +++ b/install.sh @@ -34,7 +34,7 @@ function error { trap error ERR -# Determine release filename. This can be expanded with CPU arch in the future. +# Determine release filename. case "$(uname)" in Linux) OS='linux' @@ -48,7 +48,20 @@ case "$(uname)" in ;; esac -RELEASE_URL="${GITHUB_BASE_URL}/releases/download/v${VERSION}/circleci-cli_${VERSION}_${OS}_amd64.tar.gz" +case "$(uname -m)" in + aarch64 | arm64) + ARCH='arm64' + ;; + x86_64) + ARCH="amd64" + ;; + *) + echo "This architecture is not supported." + exit 1 + ;; +esac + +RELEASE_URL="${GITHUB_BASE_URL}/releases/download/v${VERSION}/circleci-cli_${VERSION}_${OS}_${ARCH}.tar.gz" # Download & unpack the release tarball. curl -sL --retry 3 "${RELEASE_URL}" | tar zx --strip 1 From a061e185eec3bef685c0af9c7e8347ba47f1424a Mon Sep 17 00:00:00 2001 From: William Yardley Date: Thu, 4 May 2023 10:41:42 -0700 Subject: [PATCH 02/10] fix: use bold rather than backticks around command output Use `color` module to bold output of update command error Tests seem to pass despite not having control codes --- cmd/disabled.go | 4 +++- cmd/root_test.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/disabled.go b/cmd/disabled.go index 005572cbd..743b395ee 100644 --- a/cmd/disabled.go +++ b/cmd/disabled.go @@ -5,6 +5,7 @@ import ( "github.com/CircleCI-Public/circleci-cli/settings" "github.com/CircleCI-Public/circleci-cli/version" + "github.com/fatih/color" "github.com/spf13/cobra" ) @@ -39,7 +40,8 @@ func newDisabledCommand(config *settings.Config, command string) *cobra.Command } func disableCommand(opts disableOptions) { - fmt.Printf("`%s` is not available because this tool was installed using `%s`.\n", opts.command, version.PackageManager()) + bold := color.New(color.Bold).SprintFunc() + fmt.Printf("%s is not available because this tool was installed using %s.\n", bold(opts.command), bold(version.PackageManager())) if opts.command == "update" { fmt.Println("Please consult the package manager's documentation on how to update the CLI.") diff --git a/cmd/root_test.go b/cmd/root_test.go index def65ae10..c23982b18 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -64,7 +64,7 @@ var _ = Describe("Root", func() { Eventually(session.Err.Contents()).Should(BeEmpty()) - Eventually(session.Out).Should(gbytes.Say("`update` is not available because this tool was installed using `homebrew`.")) + Eventually(session.Out).Should(gbytes.Say("update is not available because this tool was installed using homebrew.")) Eventually(session.Out).Should(gbytes.Say("Please consult the package manager's documentation on how to update the CLI.")) Eventually(session).Should(gexec.Exit(0)) }) From 15acfb82954d69e9b6aefee31279ad2d321ce41a Mon Sep 17 00:00:00 2001 From: Glen Mailer Date: Thu, 28 Nov 2019 18:13:19 +0000 Subject: [PATCH 03/10] Make the install script a little bit safer when being piped --- install.sh | 122 ++++++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/install.sh b/install.sh index fcdf1055e..e3793aa0b 100755 --- a/install.sh +++ b/install.sh @@ -10,66 +10,72 @@ set -o errexit -echo "Starting installation." - -# GitHub's URL for the latest release, will redirect. -GITHUB_BASE_URL="https://github.com/CircleCI-Public/circleci-cli" -LATEST_URL="${GITHUB_BASE_URL}/releases/latest/" -DESTDIR="${DESTDIR:-/usr/local/bin}" - -if [ -z "$VERSION" ]; then - VERSION=$(curl -sLI -o /dev/null -w '%{url_effective}' "$LATEST_URL" | cut -d "v" -f 2) -fi - -echo "Installing CircleCI CLI v${VERSION}" - -# Run the script in a temporary directory that we know is empty. -SCRATCH=$(mktemp -d || mktemp -d -t 'tmp') -cd "$SCRATCH" - function error { echo "An error occured installing the tool." echo "The contents of the directory $SCRATCH have been left in place to help to debug the issue." } -trap error ERR - -# Determine release filename. -case "$(uname)" in - Linux) - OS='linux' - ;; - Darwin) - OS='darwin' - ;; - *) - echo "This operating system is not supported." - exit 1 - ;; -esac - -case "$(uname -m)" in - aarch64 | arm64) - ARCH='arm64' - ;; - x86_64) - ARCH="amd64" - ;; - *) - echo "This architecture is not supported." - exit 1 - ;; -esac - -RELEASE_URL="${GITHUB_BASE_URL}/releases/download/v${VERSION}/circleci-cli_${VERSION}_${OS}_${ARCH}.tar.gz" - -# Download & unpack the release tarball. -curl --ssl-reqd -sL --retry 3 "${RELEASE_URL}" | tar zx --strip 1 - -echo "Installing to $DESTDIR" -install circleci "$DESTDIR" - -command -v circleci - -# Delete the working directory when the install was successful. -rm -r "$SCRATCH" +# Use a function to ensure connection errors don't partially execute when being piped +function install { + + echo "Starting installation." + + # GitHub's URL for the latest release, will redirect. + GITHUB_BASE_URL="https://github.com/CircleCI-Public/circleci-cli" + LATEST_URL="${GITHUB_BASE_URL}/releases/latest/" + DESTDIR="${DESTDIR:-/usr/local/bin}" + + if [ -z "$VERSION" ]; then + VERSION=$(curl -sLI -o /dev/null -w '%{url_effective}' "$LATEST_URL" | cut -d "v" -f 2) + fi + + echo "Installing CircleCI CLI v${VERSION}" + + # Run the script in a temporary directory that we know is empty. + SCRATCH=$(mktemp -d || mktemp -d -t 'tmp') + cd "$SCRATCH" + + trap error ERR + + # Determine release filename. + case "$(uname)" in + Linux) + OS='linux' + ;; + Darwin) + OS='darwin' + ;; + *) + echo "This operating system is not supported." + exit 1 + ;; + esac + + case "$(uname -m)" in + aarch64 | arm64) + ARCH='arm64' + ;; + x86_64) + ARCH="amd64" + ;; + *) + echo "This architecture is not supported." + exit 1 + ;; + esac + + RELEASE_URL="${GITHUB_BASE_URL}/releases/download/v${VERSION}/circleci-cli_${VERSION}_${OS}_${ARCH}.tar.gz" + + # Download & unpack the release tarball. + curl --ssl-reqd -sL --retry 3 "${RELEASE_URL}" | tar zx --strip 1 + + echo "Installing to $DESTDIR" + install circleci "$DESTDIR" + + command -v circleci + + # Delete the working directory when the install was successful. + rm -r "$SCRATCH" +} + +install From dee7feebcc32e76eced02ec96e97ef5d95648bbf Mon Sep 17 00:00:00 2001 From: JulesFaucherre Date: Wed, 10 May 2023 15:07:45 +0200 Subject: [PATCH 04/10] chore: Updated goreleaser version --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 79dc8cb66..ea10828d5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,7 @@ commands: parameters: GORELEASER_URL: type: string - default: https://github.com/goreleaser/goreleaser/releases/download/v0.127.0/goreleaser_amd64.deb + default: https://github.com/goreleaser/goreleaser/releases/download/v0.184.0/goreleaser_amd64.deb steps: - restore_cache: keys: [v5-goreleaser-] From 854fc38328309880163044d43d225ac87f866773 Mon Sep 17 00:00:00 2001 From: JulesFaucherre Date: Tue, 9 May 2023 10:53:07 +0200 Subject: [PATCH 05/10] fix: Added backward compatibility for orb validation --- api/api.go | 126 ++++++++++++++++++---- clitest/data/orb_with_private.yml | 11 ++ cmd/orb_test.go | 167 +++++++++++++++++++++++++----- 3 files changed, 260 insertions(+), 44 deletions(-) create mode 100644 clitest/data/orb_with_private.yml diff --git a/api/api.go b/api/api.go index f94c64401..3d283930c 100644 --- a/api/api.go +++ b/api/api.go @@ -521,7 +521,28 @@ func OrbQuery(cl *graphql.Client, configPath string, ownerId string) (*ConfigRes return nil, err } - query := ` + request, err := makeOrbRequest(cl, config, ownerId) + if err != nil { + return nil, err + } + + err = cl.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 +} + +func makeOrbRequest(cl *graphql.Client, configContent string, ownerId string) (*graphql.Request, error) { + handlesOwner := orbQueryHandleOwnerId(cl) + + if handlesOwner { + query := ` query ValidateOrb ($config: String!, $owner: UUID) { orbConfig(orbYaml: $config, ownerId: $owner) { valid, @@ -531,26 +552,91 @@ func OrbQuery(cl *graphql.Client, configPath string, ownerId string) (*ConfigRes } }` - request := graphql.NewRequest(query) - request.Var("config", config) + request := graphql.NewRequest(query) + request.Var("config", configContent) + + if ownerId != "" { + request.Var("owner", ownerId) + } + + request.SetToken(cl.Token) + return request, nil + } if ownerId != "" { - request.Var("owner", ownerId) + return nil, errors.Errorf("Your version of server does not support validating orbs that refer private orbs") } + query := ` + query ValidateOrb ($config: String!) { + orbConfig(orbYaml: $config) { + valid, + errors { message }, + sourceYaml, + outputYaml + } + }` + + request := graphql.NewRequest(query) + request.Var("config", configContent) request.SetToken(cl.Token) + return request, nil +} - err = cl.Run(request, &response) +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(cl *graphql.Client) bool { + query := ` +query ValidateOrb { + __schema { + queryType { + fields(includeDeprecated: true) { + name + args { + name + __typename + type { + name + } + } + } + } + } +}` + request := graphql.NewRequest(query) + response := OrbIntrospectionResponse{} + err := cl.Run(request, &response) if err != nil { - return nil, errors.Wrap(err, "Unable to validate config") + return false } - if len(response.OrbConfig.ConfigResponse.Errors) > 0 { - return nil, response.OrbConfig.ConfigResponse.Errors + request.SetToken(cl.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 + } + } + } } - return &response.OrbConfig.ConfigResponse, nil + // else return false, ownerId is not supported + + return false } // OrbImportVersion publishes a new version of an orb using the provided source and id. @@ -1239,18 +1325,18 @@ func OrbSetOrbListStatus(cl *graphql.Client, namespace string, orb string, list var response OrbSetOrbListStatusResponse query := ` - mutation($orbId: UUID!, $list: Boolean!) { - setOrbListStatus( - orbId: $orbId, - list: $list - ) { - listed - errors { - message - type - } - } +mutation($orbId: UUID!, $list: Boolean!) { + setOrbListStatus( + orbId: $orbId, + list: $list + ) { + listed + errors { + message + type } + } +} ` request := graphql.NewRequest(query) diff --git a/clitest/data/orb_with_private.yml b/clitest/data/orb_with_private.yml new file mode 100644 index 000000000..504688570 --- /dev/null +++ b/clitest/data/orb_with_private.yml @@ -0,0 +1,11 @@ +version: 2.1 + +orbs: + vuln-scanner: cci-internal/snyk-vuln-scanner@0.6.2 + +jobs: + some-job: + executor: vuln-scanner/default + steps: + - run: + command: echo "Hello world" diff --git a/cmd/orb_test.go b/cmd/orb_test.go index 2ab23c889..3d2f586d5 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -109,6 +109,8 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs It("works", func() { By("setting up a mock server") + mockOrbIntrospection(true, "", tempSettings) + gqlResponse := `{ "orbConfig": { "sourceYaml": "{}", @@ -145,6 +147,7 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs Status: http.StatusOK, Request: string(expected), Response: gqlResponse}) + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) Expect(err).ShouldNot(HaveOccurred()) @@ -175,6 +178,8 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs By("setting up a mock server") orb.Write([]byte(`{}`)) + mockOrbIntrospection(true, "", tempSettings) + gqlResponse := `{ "orbConfig": { "sourceYaml": "{}", @@ -222,6 +227,9 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs It("works", func() { By("setting up a mock server") + + mockOrbIntrospection(true, "", tempSettings) + gqlResponse := `{ "orbConfig": { "sourceYaml": "{}", @@ -255,6 +263,8 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs It("prints errors if invalid", func() { By("setting up a mock server") + mockOrbIntrospection(true, "", tempSettings) + gqlResponse := `{ "orbConfig": { "sourceYaml": "hello world", @@ -300,6 +310,8 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs It("works", func() { By("setting up a mock server") + mockOrbIntrospection(true, "", tempSettings) + gqlResponse := `{ "orbConfig": { "outputYaml": "hello world", @@ -332,6 +344,8 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs It("prints errors if invalid", func() { By("setting up a mock server") + mockOrbIntrospection(true, "", tempSettings) + gqlResponse := `{ "orbConfig": { "outputYaml": "hello world", @@ -1469,13 +1483,29 @@ You can now register versions of %s using %s.`, } }`, list) - expectedOrbRequest := fmt.Sprintf(`{ - "query": "\n\t\tmutation($orbId: UUID!, $list: Boolean!) {\n\t\t\tsetOrbListStatus(\n\t\t\t\torbId: $orbId,\n\t\t\t\tlist: $list\n\t\t\t) {\n\t\t\t\tlisted\n\t\t\t\terrors { \n\t\t\t\t\tmessage\n\t\t\t\t\ttype \n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t", - "variables": { - "list": %t, - "orbId": "bb604b45-b6b0-4b81-ad80-796f15eddf87" - } - }`, list) + orbRequest := map[string]interface{}{ + "query": ` +mutation($orbId: UUID!, $list: Boolean!) { + setOrbListStatus( + orbId: $orbId, + list: $list + ) { + listed + errors { + message + type + } + } +} + `, + "variables": map[string]interface{}{ + "list": list, + "orbId": "bb604b45-b6b0-4b81-ad80-796f15eddf87", + }, + } + + expectedOrbRequest, err := json.Marshal(orbRequest) + Expect(err).ToNot(HaveOccurred()) tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ Status: http.StatusOK, @@ -1484,7 +1514,7 @@ You can now register versions of %s using %s.`, tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ Status: http.StatusOK, - Request: expectedOrbRequest, + Request: string(expectedOrbRequest), Response: gqlOrbResponse}) session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) @@ -1537,13 +1567,29 @@ You can now register versions of %s using %s.`, } }` - expectedOrbRequest := fmt.Sprintf(`{ - "query": "\n\t\tmutation($orbId: UUID!, $list: Boolean!) {\n\t\t\tsetOrbListStatus(\n\t\t\t\torbId: $orbId,\n\t\t\t\tlist: $list\n\t\t\t) {\n\t\t\t\tlisted\n\t\t\t\terrors { \n\t\t\t\t\tmessage\n\t\t\t\t\ttype \n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t", - "variables": { - "list": %t, - "orbId": "bb604b45-b6b0-4b81-ad80-796f15eddf87" - } - }`, list) + orbRequest := map[string]interface{}{ + "query": ` +mutation($orbId: UUID!, $list: Boolean!) { + setOrbListStatus( + orbId: $orbId, + list: $list + ) { + listed + errors { + message + type + } + } +} + `, + "variables": map[string]interface{}{ + "list": list, + "orbId": "bb604b45-b6b0-4b81-ad80-796f15eddf87", + }, + } + + expectedOrbRequest, err := json.Marshal(orbRequest) + Expect(err).ToNot(HaveOccurred()) tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ Status: http.StatusOK, @@ -1552,7 +1598,7 @@ You can now register versions of %s using %s.`, tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ Status: http.StatusOK, - Request: expectedOrbRequest, + Request: string(expectedOrbRequest), Response: gqlOrbResponse}) session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) @@ -1686,13 +1732,29 @@ You can now register versions of %s using %s.`, } }` - expectedOrbRequest := fmt.Sprintf(`{ - "query": "\n\t\tmutation($orbId: UUID!, $list: Boolean!) {\n\t\t\tsetOrbListStatus(\n\t\t\t\torbId: $orbId,\n\t\t\t\tlist: $list\n\t\t\t) {\n\t\t\t\tlisted\n\t\t\t\terrors { \n\t\t\t\t\tmessage\n\t\t\t\t\ttype \n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t", - "variables": { - "list": %t, - "orbId": "bb604b45-b6b0-4b81-ad80-796f15eddf87" - } - }`, list) + orbRequest := map[string]interface{}{ + "query": ` +mutation($orbId: UUID!, $list: Boolean!) { + setOrbListStatus( + orbId: $orbId, + list: $list + ) { + listed + errors { + message + type + } + } +} + `, + "variables": map[string]interface{}{ + "list": list, + "orbId": "bb604b45-b6b0-4b81-ad80-796f15eddf87", + }, + } + + expectedOrbRequest, err := json.Marshal(orbRequest) + Expect(err).ToNot(HaveOccurred()) tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ Status: http.StatusOK, @@ -1701,7 +1763,7 @@ You can now register versions of %s using %s.`, tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ Status: http.StatusOK, - Request: expectedOrbRequest, + Request: string(expectedOrbRequest), Response: gqlOrbResponse}) session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) @@ -3453,3 +3515,60 @@ func mockOrbSource(source, orbVersion, token string, tempSettings *clitest.TempS Response: response, }) } + +func mockOrbIntrospection(isValid bool, token string, tempSettings *clitest.TempSettings) { + args := []map[string]interface{}{ + { + "name": "orbYaml", + }, + } + if isValid { + args = append(args, map[string]interface{}{ + "name": "ownerId", + }) + } + + responseStruct := map[string]interface{}{ + "__schema": map[string]interface{}{ + "queryType": map[string]interface{}{ + "fields": []map[string]interface{}{ + { + "name": "orbConfig", + "args": args, + }, + }, + }, + }, + } + response, err := json.Marshal(responseStruct) + Expect(err).ToNot(HaveOccurred()) + + requestStruct := map[string]interface{}{ + "query": ` +query ValidateOrb { + __schema { + queryType { + fields(includeDeprecated: true) { + name + args { + name + __typename + type { + name + } + } + } + } + } +}`, + "variables": map[string]interface{}{}, + } + request, err := json.Marshal(requestStruct) + Expect(err).ToNot(HaveOccurred()) + + tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ + Status: http.StatusOK, + Request: string(request), + Response: string(response), + }) +} From f6c133cf682a389413c5d93c5b57613a181627e8 Mon Sep 17 00:00:00 2001 From: JulesFaucherre Date: Wed, 10 May 2023 16:04:41 +0200 Subject: [PATCH 06/10] doc: Added doc about server compatibility --- README.md | 5 +++++ api/api.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 18beace6c..bece11c0d 100644 --- a/README.md +++ b/README.md @@ -178,3 +178,8 @@ Development instructions for the CircleCI CLI can be found in [HACKING.md](HACKI Please see the [documentation](https://circleci-public.github.io/circleci-cli) or `circleci help` for more. +## Server compatibility + +There are some difference of behavior depending on the version you use: + - config validation will use the GraphQL API until **Server v4.0.5, v4.1.3, v4.2.0**. The above versions will use the new route `compile-config-with-defaults` + - `circleci orb validate` will only allow you to validate orbs using other private orbs with the option `--org-slug` from version **Server v4.2.0** diff --git a/api/api.go b/api/api.go index 3d283930c..c34d606af 100644 --- a/api/api.go +++ b/api/api.go @@ -564,7 +564,7 @@ func makeOrbRequest(cl *graphql.Client, configContent string, ownerId string) (* } if ownerId != "" { - return nil, errors.Errorf("Your version of server does not support validating orbs that refer private orbs") + return nil, errors.Errorf("Your version of Server does not support validating orbs that refer private orbs. Please refer to the README to see compatibility: https://github.com/CircleCI-Public/circleci-cli#server-compatibility") } query := ` query ValidateOrb ($config: String!) { From 30eec4151e4e039ca386e09c9ba83828c7928be1 Mon Sep 17 00:00:00 2001 From: JulesFaucherre Date: Wed, 10 May 2023 16:24:54 +0200 Subject: [PATCH 07/10] test: Added test for compatibility --- api/api.go | 2 +- cmd/orb_test.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/api/api.go b/api/api.go index c34d606af..0c51b486d 100644 --- a/api/api.go +++ b/api/api.go @@ -564,7 +564,7 @@ func makeOrbRequest(cl *graphql.Client, configContent string, ownerId string) (* } if ownerId != "" { - return nil, errors.Errorf("Your version of Server does not support validating orbs that refer private orbs. Please refer to the README to see compatibility: https://github.com/CircleCI-Public/circleci-cli#server-compatibility") + 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") } query := ` query ValidateOrb ($config: String!) { diff --git a/cmd/orb_test.go b/cmd/orb_test.go index 3d2f586d5..7b4e917ba 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -210,6 +210,77 @@ See a full explanation and documentation on orbs here: https://circleci.com/docs }) }) + Describe("with old server version", func() { + BeforeEach(func() { + token = "testtoken" + command = exec.Command(pathCLI, + "orb", "validate", + "--skip-update-check", + "--token", token, + "--host", tempSettings.TestServer.URL(), + "-", + ) + stdin, err := command.StdinPipe() + Expect(err).ToNot(HaveOccurred()) + go func() { + defer stdin.Close() + _, err := io.WriteString(stdin, "{}") + if err != nil { + panic(err) + } + }() + }) + + It("should use the old GraphQL resolver", func() { + By("setting up a mock server") + + mockOrbIntrospection(false, "", tempSettings) + + gqlResponse := `{ + "orbConfig": { + "sourceYaml": "{}", + "valid": true, + "errors": [] + } + }` + + response := struct { + Query string `json:"query"` + Variables struct { + Config string `json:"config"` + } `json:"variables"` + }{ + Query: ` + query ValidateOrb ($config: String!) { + orbConfig(orbYaml: $config) { + valid, + errors { message }, + sourceYaml, + outputYaml + } + }`, + Variables: struct { + Config string `json:"config"` + }{ + Config: "{}", + }, + } + expected, err := json.Marshal(response) + Expect(err).ShouldNot(HaveOccurred()) + + tempSettings.AppendPostHandler(token, clitest.MockRequestResponse{ + Status: http.StatusOK, + Request: string(expected), + Response: gqlResponse}) + + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + Expect(err).ShouldNot(HaveOccurred()) + Eventually(session.Out).Should(gbytes.Say("Orb input is valid.")) + Eventually(session).Should(gexec.Exit(0)) + }) + }) + Context("with 'some orb'", func() { BeforeEach(func() { orb.Write([]byte(`some orb`)) From 4d9dbe56bdd4d3561daee2b6af9ba912225005a5 Mon Sep 17 00:00:00 2001 From: KyleTryon Date: Mon, 15 May 2023 09:45:38 -0400 Subject: [PATCH 08/10] docs: remove preview message. Now GA --- cmd/orb.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/orb.go b/cmd/orb.go index 435504563..5cc227c21 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -1055,7 +1055,6 @@ func inlineIncludes(node *yaml.Node, orbRoot string) error { func initOrb(opts orbOptions) error { orbPath := opts.args[0] var err error - fmt.Println("Note: This command is in preview. Please report any bugs! https://github.com/CircleCI-Public/circleci-cli/issues/new/choose") fullyAutomated := 0 prompt := &survey.Select{ From 766a863477847397fcd773d44f61e957696a147b Mon Sep 17 00:00:00 2001 From: KyleTryon Date: Mon, 15 May 2023 10:06:03 -0400 Subject: [PATCH 09/10] feat: make orb visibility a prompt --- cmd/orb.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cmd/orb.go b/cmd/orb.go index 5cc227c21..c5bab5415 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -1056,6 +1056,23 @@ func initOrb(opts orbOptions) error { orbPath := opts.args[0] var err error +if !opts.private { + prompt := &survey.Select{ + Message: "Would you like to create a public or private orb?", + Options: []string{"Public", "Private"}, + } + var selectedOption string + err := survey.AskOne(prompt, &selectedOption) + if err != nil { + return errors.Wrap(err, "Unexpected error") + } + + if selectedOption == "Private" { + opts.private = true + } +} + + fullyAutomated := 0 prompt := &survey.Select{ Message: "Would you like to perform an automated setup of this orb?", From 0ef4187afd27fded2b44ac43d531dcadd5a11daf Mon Sep 17 00:00:00 2001 From: KyleTryon Date: Mon, 15 May 2023 10:21:24 -0400 Subject: [PATCH 10/10] lint: format --- cmd/orb.go | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/cmd/orb.go b/cmd/orb.go index c5bab5415..de540b433 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -1056,22 +1056,21 @@ func initOrb(opts orbOptions) error { orbPath := opts.args[0] var err error -if !opts.private { - prompt := &survey.Select{ - Message: "Would you like to create a public or private orb?", - Options: []string{"Public", "Private"}, - } - var selectedOption string - err := survey.AskOne(prompt, &selectedOption) - if err != nil { - return errors.Wrap(err, "Unexpected error") - } + if !opts.private { + prompt := &survey.Select{ + Message: "Would you like to create a public or private orb?", + Options: []string{"Public", "Private"}, + } + var selectedOption string + err := survey.AskOne(prompt, &selectedOption) + if err != nil { + return errors.Wrap(err, "Unexpected error") + } - if selectedOption == "Private" { - opts.private = true + if selectedOption == "Private" { + opts.private = true + } } -} - fullyAutomated := 0 prompt := &survey.Select{