Skip to content

Commit

Permalink
changed the context list table (#1047)
Browse files Browse the repository at this point in the history
  • Loading branch information
JulesFaucherre authored Mar 4, 2024
1 parent 583e145 commit 1d5a050
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 61 deletions.
6 changes: 3 additions & 3 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ func GetOrganization(cl *graphql.Client, params GetOrganizationParams) (*GetOrga

var request *graphql.Request
if params.OrgID != "" {
request = graphql.NewRequest(`query($orgId: UUID!) {
request = graphql.NewRequest(`query($orgId: ID!) {
organization(id: $orgId) {
id
name
Expand All @@ -787,14 +787,14 @@ func GetOrganization(cl *graphql.Client, params GetOrganizationParams) (*GetOrga
}
}`)
request.Var("orgName", params.OrgName)
request.Var("vcsType", params.VCSType)
request.Var("vcsType", strings.ToUpper(params.VCSType))
}

var response GetOrganizationResponse
request.SetToken(cl.Token)
err := cl.Run(request, &response)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "fetching organization")
}
return &response, nil
}
Expand Down
59 changes: 39 additions & 20 deletions cmd/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"strings"
"time"

"github.com/CircleCI-Public/circleci-cli/api"
"github.com/CircleCI-Public/circleci-cli/api/context"
"github.com/CircleCI-Public/circleci-cli/api/graphql"
"github.com/CircleCI-Public/circleci-cli/prompt"
"github.com/olekukonko/tablewriter"
"github.com/pkg/errors"
Expand Down Expand Up @@ -78,7 +80,21 @@ are injected at runtime.`,
Use: "list --org-id <org-id>",
PreRunE: initClient,
RunE: func(cmd *cobra.Command, args []string) error {
return listContexts(contextClient)
gqlClient := graphql.NewClient(config.HTTPClient, config.Host, config.Endpoint, config.Token, false)
params := api.GetOrganizationParams{
OrgID: orgID,
VCSType: vcsType,
OrgName: orgName,
}
params.OrgID = orgID
params.VCSType = vcsType
params.OrgName = orgName
org, err := api.GetOrganization(gqlClient, params)
if err != nil {
return err
}

return listContexts(contextClient, org.Organization.Name, org.Organization.ID)
},
Args: MultiExactArgs(0, 2),
Example: `circleci context list --org-id 00000000-0000-0000-0000-000000000000
Expand Down Expand Up @@ -158,7 +174,20 @@ are injected at runtime.`,
Use: "delete --org-id <org-id> <context-name>",
PreRunE: initClient,
RunE: func(cmd *cobra.Command, args []string) error {
return deleteContext(contextClient, force, initiatedArgs[0])
gqlClient := graphql.NewClient(config.HTTPClient, config.Host, config.Endpoint, config.Token, false)
params := api.GetOrganizationParams{
OrgID: orgID,
VCSType: vcsType,
OrgName: orgName,
}
params.OrgID = orgID
params.VCSType = vcsType
params.OrgName = orgName
org, err := api.GetOrganization(gqlClient, params)
if err != nil {
return err
}
return deleteContext(contextClient, org.Organization.Name, force, initiatedArgs[0])
},
Args: MultiExactArgs(1, 3),
Example: `circleci context delete --org-id 00000000-0000-0000-0000-000000000000 contextName
Expand All @@ -177,17 +206,18 @@ are injected at runtime.`,
return command
}

func listContexts(contextClient context.ContextInterface) error {
func listContexts(contextClient context.ContextInterface, orgName string, orgId string) error {
contexts, err := contextClient.Contexts()
if err != nil {
return err
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Id", "Name", "Created At"})
table.SetHeader([]string{"Organization", "Org ID", "Name", "Created At"})
for _, context := range contexts {
table.Append([]string{
context.ID,
orgName,
orgId,
context.Name,
context.CreatedAt.Format(time.RFC3339),
})
Expand Down Expand Up @@ -282,27 +312,16 @@ func storeEnvVar(client context.ContextInterface, prompt storeEnvVarPrompt, cont
return err
}

func askForConfirmation(message string) bool {
fmt.Println(message)
var response string
if _, err := fmt.Scanln(&response); err != nil {
return false
}
return strings.HasPrefix(strings.ToLower(response), "y")
}

func deleteContext(client context.ContextInterface, force bool, contextName string) error {
func deleteContext(client context.ContextInterface, orgName string, force bool, contextName string) error {
context, err := client.ContextByName(contextName)
if err != nil {
return err
}

message := fmt.Sprintf("Are you sure that you want to delete this context: %s (y/n)?", context.Name)

shouldDelete := force || askForConfirmation(message)

shouldDelete := force || prompt.AskUserToConfirm(fmt.Sprintf("Are you sure that you want to delete this context: %s %s (y/n)?", orgName, context.Name))
if !shouldDelete {
return errors.New("OK, cancelling")
fmt.Printf("Cancelling context deletion")
return nil
}

err = client.DeleteContext(context.ID)
Expand Down
90 changes: 52 additions & 38 deletions cmd/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,15 @@ import (

var (
contentTypeHeader http.Header = map[string][]string{"Content-Type": {"application/json"}}
)

func mockServerForREST(tempSettings *clitest.TempSettings) {
tempSettings.TestServer.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/openapi.json"),
ghttp.RespondWith(
http.StatusOK,
`{"paths":{"/context":{}}}`,
contentTypeHeader,
),
openAPIHandler = ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/openapi.json"),
ghttp.RespondWith(
http.StatusOK,
`{"paths":{"/context":{}}}`,
contentTypeHeader,
),
)
}
)

var _ = Describe("Context integration tests", func() {
var (
Expand All @@ -45,6 +40,19 @@ var _ = Describe("Context integration tests", func() {
vcsType string = "bitbucket"
orgName string = "test-org"
orgSlug string = fmt.Sprintf("%s/%s", vcsType, orgName)

gqlGetOrgHandler = ghttp.CombineHandlers(
ghttp.VerifyRequest("POST", "/graphql-unstable"),
ghttp.RespondWith(http.StatusOK, fmt.Sprintf(`{
"data": {
"organization": {
"id": "%s",
"name": "%s",
"vcsType": "%s"
}
}
}`, orgID, orgName, vcsType)),
)
)

BeforeEach(func() {
Expand Down Expand Up @@ -73,20 +81,21 @@ https://circleci.com/account/api`))
})

It("should handle errors", func() {
mockServerForREST(tempSettings)
contextName := "context-name"
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-id=%s", orgID)),
ghttp.VerifyRequest("POST", "/api/v2/context"),
ghttp.RespondWith(
http.StatusBadRequest,
`{"message":"no context found"}`,
http.StatusUnauthorized,
`{"message":"permission issue"}`,
contentTypeHeader,
),
),
)

command = commandWithHome(pathCLI, tempSettings.Home,
"context", "list", "--org-id", orgID,
"context", "create", "--org-id", orgID, contextName,
"--skip-update-check",
"--token", token,
"--host", tempSettings.TestServer.URL(),
Expand All @@ -97,14 +106,15 @@ https://circleci.com/account/api`))
Eventually(session).Should(gexec.Exit())
// Exit codes are different between Unix and Windows so we're only checking that it does not equal 0
Expect(session.ExitCode()).ToNot(Equal(0))
Expect(string(session.Err.Contents())).To(Equal("Error: no context found\n"))
Expect(string(session.Err.Contents())).To(Equal("Error: permission issue\n"))
})
})

Describe("list", func() {
It("should list context with VCS / org name", func() {
mockServerForREST(tempSettings)
It("should list contexts with the right columns", func() {
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
gqlGetOrgHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-slug=%s", orgSlug)),
ghttp.RespondWith(
Expand All @@ -125,10 +135,10 @@ https://circleci.com/account/api`))

Expect(err).ShouldNot(HaveOccurred())
Eventually(session).Should(gexec.Exit(0))
Expect(string(session.Out.Contents())).To(Equal(`+----+------+------------+
| ID | NAME | CREATED AT |
+----+------+------------+
+----+------+------------+
Expect(string(session.Out.Contents())).To(Equal(`+--------------+--------+------+------------+
| ORGANIZATION | ORG ID | NAME | CREATED AT |
+--------------+--------+------+------------+
+--------------+--------+------+------------+
`))
})

Expand All @@ -139,8 +149,9 @@ https://circleci.com/account/api`))
}
body, err := json.Marshal(struct{ Items []context.Context }{contexts})
Expect(err).ShouldNot(HaveOccurred())
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
gqlGetOrgHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-slug=%s", orgSlug)),
ghttp.RespondWith(
Expand All @@ -162,7 +173,7 @@ https://circleci.com/account/api`))
Expect(err).ShouldNot(HaveOccurred())
Eventually(session).Should(gexec.Exit(0))
lines := strings.Split(string(session.Out.Contents()), "\n")
Expect(lines[1]).To(MatchRegexp("|\\w+ID\\w+|\\w+NAME\\w+|\\w+CREATED AT\\w+|"))
Expect(lines[1]).To(MatchRegexp("|\\w+ORGANIZATION\\w+|\\w+ORG ID\\w+|\\w+NAME\\w+|\\w+CREATED AT\\w+|"))
Expect(lines).To(HaveLen(7))
})

Expand All @@ -173,8 +184,9 @@ https://circleci.com/account/api`))
}
body, err := json.Marshal(struct{ Items []context.Context }{contexts})
Expect(err).ShouldNot(HaveOccurred())
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
gqlGetOrgHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-id=%s", orgID)),
ghttp.RespondWith(
Expand Down Expand Up @@ -216,8 +228,8 @@ https://circleci.com/account/api`))
)

It("should show context with vcs type / org name", func() {
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-slug=%s", orgSlug)),
ghttp.RespondWith(
Expand Down Expand Up @@ -252,8 +264,8 @@ https://circleci.com/account/api`))
})

It("should show context with org id", func() {
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-id=%s", orgID)),
ghttp.RespondWith(
Expand Down Expand Up @@ -306,8 +318,8 @@ https://circleci.com/account/api`))

It("should store value when giving vcs type / org name", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-slug=%s", orgSlug)),
ghttp.RespondWith(
Expand Down Expand Up @@ -342,8 +354,8 @@ https://circleci.com/account/api`))

It("should store value when giving vcs type / org name", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-id=%s", orgID)),
ghttp.RespondWith(
Expand Down Expand Up @@ -389,8 +401,8 @@ https://circleci.com/account/api`))

It("should remove environment variable with vcs type / org name", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-slug=%s", orgSlug)),
ghttp.RespondWith(
Expand Down Expand Up @@ -424,8 +436,8 @@ https://circleci.com/account/api`))

It("should remove environment variable with org id", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-id=%s", orgID)),
ghttp.RespondWith(
Expand Down Expand Up @@ -469,8 +481,9 @@ https://circleci.com/account/api`))

It("should delete context with vcs type / org name", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
gqlGetOrgHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-slug=%s", orgSlug)),
ghttp.RespondWith(
Expand Down Expand Up @@ -504,8 +517,9 @@ https://circleci.com/account/api`))

It("should delete context with org id", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
gqlGetOrgHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v2/context", fmt.Sprintf("owner-id=%s", orgID)),
ghttp.RespondWith(
Expand Down Expand Up @@ -550,8 +564,8 @@ https://circleci.com/account/api`))

It("should create new context using an org id", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("POST", "/api/v2/context"),
ghttp.VerifyContentType("application/json"),
Expand All @@ -575,8 +589,8 @@ https://circleci.com/account/api`))

It("should create new context using vcs type / org name", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("POST", "/api/v2/context"),
ghttp.VerifyContentType("application/json"),
Expand Down Expand Up @@ -604,8 +618,8 @@ https://circleci.com/account/api`))

It("handles errors", func() {
By("setting up a mock server")
mockServerForREST(tempSettings)
tempSettings.TestServer.AppendHandlers(
openAPIHandler,
ghttp.CombineHandlers(
ghttp.VerifyRequest("POST", "/api/v2/context"),
ghttp.VerifyContentType("application/json"),
Expand Down

0 comments on commit 1d5a050

Please sign in to comment.