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

Create orb #32

Merged
merged 13 commits into from
Jul 25, 2018
5 changes: 4 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ jobs:

lint:
docker:
- image: supinf/gometalinter:latest
# TODO: use this image once it updates latest gometalinter
#- image: supinf/gometalinter:latest
- image: circleci/golang:1.10
working_directory: /go/src/github.com/CircleCI-Public/circleci-cli
environment:
CGO_ENABLED: 0
steps:
- checkout
- run: make dev
- run: gometalinter ./...

deploy:
Expand Down
2 changes: 1 addition & 1 deletion .gometalinter.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
"Enable": [
"deadcode",
"errcheck",
"gas",
"goconst",
"gocyclo",
"gofmt",
"goimports",
"golint",
"gosec",
"gosimple",
"gotype",
"gotypex",
Expand Down
103 changes: 97 additions & 6 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ type CreateNamespaceResponse struct {
GQLResponseErrors
}

// CreateOrbResponse type matches the data shape of the GQL response for
// creating an orb
type CreateOrbResponse struct {
Orb struct {
ID string
}

GQLResponseErrors
}

// ToError returns all GraphQL errors for a single response concatenated, or
// nil.
func (response GQLResponseErrors) ToError() error {
Expand All @@ -67,6 +77,7 @@ func (response GQLResponseErrors) ToError() error {
return errors.New(strings.Join(messages, ": "))
}

// nolint: gosec
func loadYaml(path string) (string, error) {
var err error
var config []byte
Expand Down Expand Up @@ -162,7 +173,6 @@ func OrbPublish(ctx context.Context, logger *logger.Logger,
) {
orb {
version
createdAt
}
errors { message }
}
Expand All @@ -184,7 +194,7 @@ func OrbPublish(ctx context.Context, logger *logger.Logger,
return &response.PublishOrb.PublishOrbResponse, err
}

func createNamespaceByID(ctx context.Context, logger *logger.Logger, name string, ownerID string) (*CreateNamespaceResponse, error) {
func createNamespaceWithOwnerID(ctx context.Context, logger *logger.Logger, name string, ownerID string) (*CreateNamespaceResponse, error) {
var response struct {
CreateNamespace struct {
CreateNamespaceResponse
Expand All @@ -198,7 +208,6 @@ func createNamespaceByID(ctx context.Context, logger *logger.Logger, name string
organizationId: $organizationId
) {
namespace {
createdAt
id
}
errors {
Expand Down Expand Up @@ -248,8 +257,10 @@ func getOrganization(ctx context.Context, logger *logger.Logger, organizationNam

err := graphQLclient.Run(ctx, request, &response)

if err != nil || response.Organization.ID == "" {
err = errors.Wrap(err, fmt.Sprintf("Unable to find organization %s of vcs-type %s", organizationName, organizationVcs))
if err != nil {
err = errors.Wrapf(err, "Unable to find organization %s of vcs-type %s", organizationName, organizationVcs)
} else if response.Organization.ID == "" {
err = fmt.Errorf("Unable to find organization %s of vcs-type %s", organizationName, organizationVcs)
}

return response.Organization.ID, err
Expand All @@ -262,11 +273,91 @@ func CreateNamespace(ctx context.Context, logger *logger.Logger, name string, or
return nil, err
}

namespace, err := createNamespaceByID(ctx, logger, name, organizationID)
namespace, err := createNamespaceWithOwnerID(ctx, logger, name, organizationID)

if err != nil {
return nil, err
}

return namespace, err
}

func getNamespace(ctx context.Context, logger *logger.Logger, name string) (string, error) {
var response struct {
RegistryNamespace struct {
ID string
}
}

query := `
query($name: String!) {
registryNamespace(
name: $name
){
id
}
}`
request := client.NewAuthorizedRequest(viper.GetString("token"), query)
request.Var("name", name)

graphQLclient := client.NewClient(viper.GetString("endpoint"), logger)

err := graphQLclient.Run(ctx, request, &response)

if err != nil {
err = errors.Wrapf(err, "Unable to find namespace %s", name)
} else if response.RegistryNamespace.ID == "" {
err = fmt.Errorf("Unable to find namespace %s", name)
}

return response.RegistryNamespace.ID, err
}

func createOrbWithNsID(ctx context.Context, logger *logger.Logger, name string, namespaceID string) (*CreateOrbResponse, error) {
var response struct {
CreateOrb struct {
CreateOrbResponse
}
}

query := `mutation($name: String!, $registryNamespaceId: UUID!){
createOrb(
name: $name,
registryNamespaceId: $registryNamespaceId
){
orb {
id
}
errors {
message
type
}
}
}`

request := client.NewAuthorizedRequest(viper.GetString("token"), query)
request.Var("name", name)
request.Var("registryNamespaceId", namespaceID)

graphQLclient := client.NewClient(viper.GetString("endpoint"), logger)

err := graphQLclient.Run(ctx, request, &response)

if err != nil {
err = errors.Wrapf(err, "Unable to create orb %s for namespaceID %s", name, namespaceID)
}

return &response.CreateOrb.CreateOrbResponse, err
}

// CreateOrb creates (reserves) an orb within a namespace
func CreateOrb(ctx context.Context, logger *logger.Logger, name string, namespace string) (*CreateOrbResponse, error) {
namespaceID, err := getNamespace(ctx, logger, namespace)

if err != nil {
return nil, err
}

orb, err := createOrbWithNsID(ctx, logger, name, namespaceID)
return orb, err
}
2 changes: 1 addition & 1 deletion cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func findLatestPicardSha() (string, error) {
latest := sha256.FindString(output)

if latest == "" {
return "", errors.New("failed to parse sha256 from docker pull output")
return "", fmt.Errorf("failed to parse sha256 from docker pull output")
}

err = storeBuildAgentSha(latest)
Expand Down
3 changes: 1 addition & 2 deletions cmd/diagnostic.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package cmd

import (
"errors"

"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
Expand Down
67 changes: 60 additions & 7 deletions cmd/orb.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,15 @@ func newOrbCommand() *cobra.Command {
orbPublishCommand.PersistentFlags().StringVarP(&orbVersion, "orb-version", "o", "", "version of orb to publish")
orbPublishCommand.PersistentFlags().StringVarP(&orbID, "orb-id", "i", "", "id of orb to publish")

orbCreate := &cobra.Command{
Use: "create <namespace>/<name>",
Short: "create an orb",
RunE: createOrb,
Args: cobra.ExactArgs(1),
}

orbCreateNamespace := &cobra.Command{
Use: "create",
Use: "create <name>",
Short: "create an orb namespace",
RunE: createOrbNamespace,
Args: cobra.ExactArgs(1),
Expand All @@ -69,6 +76,7 @@ func newOrbCommand() *cobra.Command {
}

orbCommand.AddCommand(orbListCommand)
orbCommand.AddCommand(orbCreate)

orbCommand.AddCommand(orbValidateCommand)

Expand All @@ -90,20 +98,41 @@ type orb struct {
Executors map[string]struct{}
}

func addOrbElementsToBuffer(buf *bytes.Buffer, name string, elems map[string]struct{}) {
func addOrbElementsToBuffer(buf *bytes.Buffer, name string, elems map[string]struct{}) error {
var err error

if len(elems) > 0 {
buf.WriteString(fmt.Sprintf(" %s:\n", name))
_, err = buf.WriteString(fmt.Sprintf(" %s:\n", name))
if err != nil {
return err
}
for key := range elems {
buf.WriteString(fmt.Sprintf(" - %s\n", key))
_, err = buf.WriteString(fmt.Sprintf(" - %s\n", key))
if err != nil {
return err
}
}
}

return err
}

func (orb orb) String() string {
var buffer bytes.Buffer
addOrbElementsToBuffer(&buffer, "Commands", orb.Commands)
addOrbElementsToBuffer(&buffer, "Jobs", orb.Jobs)
addOrbElementsToBuffer(&buffer, "Executors", orb.Executors)

err := addOrbElementsToBuffer(&buffer, "Commands", orb.Commands)
// FIXME: refactor this to handle the error
if err != nil {
panic(err)
}
err = addOrbElementsToBuffer(&buffer, "Jobs", orb.Jobs)
if err != nil {
panic(err)
}
err = addOrbElementsToBuffer(&buffer, "Executors", orb.Executors)
if err != nil {
panic(err)
}
return buffer.String()
}

Expand Down Expand Up @@ -261,6 +290,30 @@ func publishOrb(cmd *cobra.Command, args []string) error {
return nil
}

func createOrb(cmd *cobra.Command, args []string) error {
var err error
ctx := context.Background()

arr := strings.Split(args[0], "/")

if len(arr) != 2 {
return fmt.Errorf("Invalid orb name: %s", args[0])
}

response, err := api.CreateOrb(ctx, Logger, arr[1], arr[0])

if err != nil {
return err
}

if len(response.Errors) > 0 {
return response.ToError()
}

Logger.Info("Orb created")
return nil
}

func createOrbNamespace(cmd *cobra.Command, args []string) error {
var err error
ctx := context.Background()
Expand Down
Loading