Skip to content

Commit

Permalink
Merge pull request #1050 from CircleCI-Public/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
JulesFaucherre authored Mar 5, 2024
2 parents 16acd35 + 6584b7b commit 314ca7a
Show file tree
Hide file tree
Showing 23 changed files with 1,666 additions and 1,655 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ stage/
bin/golangci-lint
integration_tests/tmp
*.exe
cmd/.circleci
78 changes: 53 additions & 25 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ const (
Remove
)

type ErrorWithMessage struct {
Message string `json:"message"`
}

func (e ErrorWithMessage) Error() string {
if e.Message != "" {
return e.Message
}
return "unknown error"
}

// GQLErrorsCollection is a slice of errors returned by the GraphQL server.
// Each error is made up of a GQLResponseError type.
type GQLErrorsCollection []GQLResponseError
Expand Down Expand Up @@ -185,13 +196,6 @@ type RenameNamespaceResponse struct {
}
}

// GetOrganizationResponse type wraps the GQL response for fetching an organization and ID.
type GetOrganizationResponse struct {
Organization struct {
ID string
}
}

// WhoamiResponse type matches the data shape of the GQL response for the current user
type WhoamiResponse struct {
Me struct {
Expand Down Expand Up @@ -744,30 +748,54 @@ func CreateNamespaceWithOwnerID(cl *graphql.Client, name string, ownerID string)
return &response, nil
}

func getOrganization(cl *graphql.Client, organizationName string, organizationVcs string) (*GetOrganizationResponse, error) {
var response GetOrganizationResponse
type GetOrganizationParams struct {
OrgName string
VCSType string
OrgID string
}

query := `query($organizationName: String!, $organizationVcs: VCSType!) {
organization(
name: $organizationName
vcsType: $organizationVcs
) {
id
}
}`
// GetOrganizationResponse type wraps the GQL response for fetching an organization and ID.
type GetOrganizationResponse struct {
Organization struct {
ID string
Name string
VCSType string
}
}

request := graphql.NewRequest(query)
request.SetToken(cl.Token)
func GetOrganization(cl *graphql.Client, params GetOrganizationParams) (*GetOrganizationResponse, error) {
if params.OrgID == "" && (params.VCSType == "" || params.OrgName == "") {
return nil, errors.New("need to define either org-id or vcs-type and org name")
}

request.Var("organizationName", organizationName)
request.Var("organizationVcs", strings.ToUpper(organizationVcs))
var request *graphql.Request
if params.OrgID != "" {
request = graphql.NewRequest(`query($orgId: ID!) {
organization(id: $orgId) {
id
name
vcsType
}
}`)
request.Var("orgId", params.OrgID)
} else {
request = graphql.NewRequest(`query($orgName: String!, $vcsType: VCSType!) {
organization(name: $orgName, vcsType: $vcsType) {
id
name
vcsType
}
}`)
request.Var("orgName", params.OrgName)
request.Var("vcsType", strings.ToUpper(params.VCSType))
}

var response GetOrganizationResponse
request.SetToken(cl.Token)
err := cl.Run(request, &response)

if err != nil {
return nil, errors.Wrapf(err, "Unable to find organization %s of vcs-type %s", organizationName, organizationVcs)
return nil, errors.Wrap(err, "fetching organization")
}

return &response, nil
}

Expand Down Expand Up @@ -857,7 +885,7 @@ mutation($id: UUID!) {

// CreateNamespace creates (reserves) a namespace for an organization
func CreateNamespace(cl *graphql.Client, name string, organizationName string, organizationVcs string) (*CreateNamespaceResponse, error) {
getOrgResponse, getOrgError := getOrganization(cl, organizationName, organizationVcs)
getOrgResponse, getOrgError := GetOrganization(cl, GetOrganizationParams{OrgName: organizationName, VCSType: organizationVcs})

if getOrgError != nil {
return nil, errors.Wrap(organizationNotFound(organizationName, organizationVcs), getOrgError.Error())
Expand Down
34 changes: 0 additions & 34 deletions api/context.go

This file was deleted.

87 changes: 87 additions & 0 deletions api/context/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package context

import (
"errors"
"fmt"
"time"

"github.com/CircleCI-Public/circleci-cli/api/graphql"
"github.com/CircleCI-Public/circleci-cli/api/rest"
"github.com/CircleCI-Public/circleci-cli/settings"
)

// An EnvironmentVariable has a Variable, a ContextID (its owner), and a
// CreatedAt date.
type EnvironmentVariable struct {
Variable string `json:"variable"`
ContextID string `json:"context_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

// A Context is the owner of EnvironmentVariables.
type Context struct {
CreatedAt time.Time `json:"created_at"`
ID string `json:"id"`
Name string `json:"name"`
}

// ContextInterface is the interface to interact with contexts and environment
// variables.
type ContextInterface interface {
Contexts() ([]Context, error)
ContextByName(name string) (Context, error)
CreateContext(name string) error
DeleteContext(contextID string) error
EnvironmentVariables(contextID string) ([]EnvironmentVariable, error)
CreateEnvironmentVariable(contextID, variable, value string) error
DeleteEnvironmentVariable(contextID, variable string) error
}

func NewContextClient(config *settings.Config, orgID, vcsType, orgName string) ContextInterface {
restClient := restClient{
client: rest.NewFromConfig(config.Host, config),
orgID: orgID,
vcsType: vcsType,
orgName: orgName,
}

if config.Host == "https://circleci.com" {
return restClient
}
if err := IsRestAPIAvailable(restClient); err != nil {
fmt.Printf("err = %+v\n", err)
return &gqlClient{
client: graphql.NewClient(config.HTTPClient, config.Host, config.Endpoint, config.Token, config.Debug),
orgID: orgID,
vcsType: vcsType,
orgName: orgName,
}
}
return restClient
}

func IsRestAPIAvailable(c restClient) error {
u, err := c.client.BaseURL.Parse("openapi.json")
if err != nil {
return err
}
req, err := c.client.NewRequest("GET", u, nil)
if err != nil {
return err
}

var resp struct {
Paths struct {
ContextEndpoint interface{} `json:"/context"`
}
}
if _, err := c.client.DoRequest(req, &resp); err != nil {
return err
}
if resp.Paths.ContextEndpoint == nil {
return errors.New("No context endpoint exists")
}

return nil
}
Loading

0 comments on commit 314ca7a

Please sign in to comment.