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

changed the context list table #1047

Merged
merged 1 commit into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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