-
Notifications
You must be signed in to change notification settings - Fork 6
add get repo command #661
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
Merged
Merged
add get repo command #661
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
30cc2e6
add get repo command
sami-alajrami 748e1b5
add provider and repo-id filters to get and list repo commands
sami-alajrami 9909566
correct comment
sami-alajrami 95a1fec
Merge branch 'main' into get-repo
sami-alajrami a060ecb
fix linting issue
sami-alajrami b8b03b3
change the org used in list repos test
sami-alajrami c6bf936
update indirect dep cloudflare/circl to fix a vulnerability
sami-alajrami 7d92025
add missing provider in the expected output
sami-alajrami b9f15a0
fix whitespace mismatching
sami-alajrami b7a3d10
ensure get repos tests use a different org
sami-alajrami 376f512
update comments for clarity
sami-alajrami File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net/http" | ||
| neturl "net/url" | ||
|
|
||
| "github.com/kosli-dev/cli/internal/output" | ||
| "github.com/kosli-dev/cli/internal/requests" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| const getRepoShortDesc = `Get a repo for an org.` | ||
|
|
||
| const getRepoLongDesc = getRepoShortDesc + ` | ||
| The name of the repo is specified as an argument (e.g. "my-org/my-repo"). | ||
| Use --provider or --repo-id to narrow down the result when multiple repos | ||
| match the given name.` | ||
|
|
||
| const getRepoExample = ` | ||
| # get a repo | ||
| kosli get repo my-org/my-repo \ | ||
| --api-token yourAPIToken \ | ||
| --org KosliOrgName | ||
|
|
||
| # get a repo filtering by provider | ||
| kosli get repo my-org/my-repo \ | ||
| --provider github \ | ||
| --api-token yourAPIToken \ | ||
| --org KosliOrgName` | ||
|
|
||
| type getRepoOptions struct { | ||
| output string | ||
| provider string | ||
| repoID string | ||
| } | ||
|
|
||
| func newGetRepoCmd(out io.Writer) *cobra.Command { | ||
| o := new(getRepoOptions) | ||
| cmd := &cobra.Command{ | ||
| Use: "repo REPO-NAME", | ||
| Hidden: true, | ||
| Short: getRepoShortDesc, | ||
| Long: getRepoLongDesc, | ||
| Example: getRepoExample, | ||
| Args: cobra.ExactArgs(1), | ||
| PreRunE: func(cmd *cobra.Command, args []string) error { | ||
| err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) | ||
| if err != nil { | ||
| return ErrorBeforePrintingUsage(cmd, err.Error()) | ||
| } | ||
| return nil | ||
| }, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| return o.run(out, args) | ||
| }, | ||
| } | ||
|
|
||
| cmd.Flags().StringVarP(&o.output, "output", "o", "table", outputFlag) | ||
| cmd.Flags().StringVar(&o.provider, "provider", "", "[optional] The VCS provider to filter repos by (e.g. github, gitlab).") | ||
| cmd.Flags().StringVar(&o.repoID, "repo-id", "", "[optional] The external repo ID to filter repos by.") | ||
|
|
||
| return cmd | ||
| } | ||
|
|
||
| func (o *getRepoOptions) run(out io.Writer, args []string) error { | ||
| params := neturl.Values{} | ||
| params.Set("name", args[0]) | ||
| if o.provider != "" { | ||
| params.Set("provider", o.provider) | ||
| } | ||
| if o.repoID != "" { | ||
| params.Set("repo_id", o.repoID) | ||
| } | ||
| reqURL := fmt.Sprintf("%s/api/v2/repos/%s?%s", global.Host, global.Org, params.Encode()) | ||
|
|
||
| reqParams := &requests.RequestParams{ | ||
| Method: http.MethodGet, | ||
| URL: reqURL, | ||
| Token: global.ApiToken, | ||
| } | ||
| response, err := kosliClient.Do(reqParams) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| var parsed struct { | ||
| Embedded struct { | ||
| Repos []map[string]any `json:"repos"` | ||
| } `json:"_embedded"` | ||
| } | ||
| if err := json.Unmarshal([]byte(response.Body), &parsed); err != nil { | ||
| return err | ||
| } | ||
| if len(parsed.Embedded.Repos) > 1 { | ||
| return fmt.Errorf("found %d repos matching %q. Use --provider or --repo-id to narrow down the search", len(parsed.Embedded.Repos), args[0]) | ||
| } | ||
|
|
||
| return output.FormattedPrint(response.Body, o.output, out, 0, | ||
| map[string]output.FormatOutputFunc{ | ||
| "table": printRepoAsTable, | ||
| "json": output.PrintJson, | ||
| }) | ||
| } | ||
|
|
||
| func printRepoAsTable(raw string, out io.Writer, page int) error { | ||
| var response struct { | ||
| Embedded struct { | ||
| Repos []map[string]any `json:"repos"` | ||
| } `json:"_embedded"` | ||
| } | ||
|
|
||
| err := json.Unmarshal([]byte(raw), &response) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| repos := response.Embedded.Repos | ||
| if len(repos) == 0 { | ||
| logger.Info("Repo was not found.") | ||
| return nil | ||
| } | ||
|
|
||
| repo := repos[0] | ||
| rows := []string{ | ||
| fmt.Sprintf("Name:\t%s", repo["name"]), | ||
| fmt.Sprintf("URL:\t%s", repo["url"]), | ||
| fmt.Sprintf("Provider:\t%s", repo["provider"]), | ||
| fmt.Sprintf("Latest Activity:\t%s", repo["latest_activity"]), | ||
| } | ||
|
|
||
| tabFormattedPrint(out, []string{}, rows) | ||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/suite" | ||
| ) | ||
|
|
||
| // Define the suite, and absorb the built-in basic suite | ||
| // functionality from testify - including a T() method which | ||
| // returns the current testing context | ||
| type GetRepoCommandTestSuite struct { | ||
| suite.Suite | ||
| defaultKosliArguments string | ||
| acmeOrgKosliArguments string | ||
| } | ||
|
|
||
| func (suite *GetRepoCommandTestSuite) SetupTest() { | ||
| global = &GlobalOpts{ | ||
| ApiToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImNkNzg4OTg5In0.e8i_lA_QrEhFncb05Xw6E_tkCHU9QfcY4OLTVUCHffY", | ||
| Org: "docs-cmd-test-user", | ||
| Host: "http://localhost:8001", | ||
| } | ||
| suite.defaultKosliArguments = fmt.Sprintf(" --host %s --org %s --api-token %s", global.Host, global.Org, global.ApiToken) | ||
|
|
||
| global.Org = "iu-org-shared" | ||
| global.ApiToken = "qM9u2_grv6pJLbACwsMMMT5LIQy82tQj2k1zjZnlXti1smnFaGwCKW4jzk0La7ae9RrSYvEwCXSsXknD6YZqd-onLaaIUUKtEn6-B6yh53vWIe9EC5u85FCbKZjFbaicp_d0Me0Zcqq_KcCgrAZRX9xggl_pBb2oaCsNdllqNjk" | ||
| suite.acmeOrgKosliArguments = fmt.Sprintf(" --host %s --org %s --api-token %s", global.Host, global.Org, global.ApiToken) | ||
| CreateFlowWithTemplate("get-repo", "testdata/valid_template.yml", suite.T()) | ||
| SetEnvVars(map[string]string{ | ||
| "GITHUB_RUN_NUMBER": "1234", | ||
| "GITHUB_SERVER_URL": "https://github.com", | ||
| "GITHUB_REPOSITORY": "kosli-dev/cli", | ||
| "GITHUB_REPOSITORY_ID": "1234567890", | ||
| }, suite.T()) | ||
| BeginTrail("trail-name", "get-repo", "", suite.T()) | ||
| } | ||
|
|
||
| func (suite *GetRepoCommandTestSuite) TearDownTest() { | ||
| UnSetEnvVars(map[string]string{ | ||
| "GITHUB_RUN_NUMBER": "", | ||
| "GITHUB_SERVER_URL": "", | ||
| "GITHUB_REPOSITORY": "", | ||
| "GITHUB_REPOSITORY_ID": "", | ||
| }, suite.T()) | ||
| } | ||
|
|
||
| func (suite *GetRepoCommandTestSuite) TestGetRepoCmd() { | ||
| tests := []cmdTestCase{ | ||
| { | ||
| name: "01-getting a non-existing repo returns not-found message", | ||
| cmd: fmt.Sprintf(`get repo non-existing/repo %s`, suite.defaultKosliArguments), | ||
| golden: "Repo was not found.\n", | ||
| }, | ||
| { | ||
| name: "02-getting an existing repo works", | ||
| cmd: fmt.Sprintf(`get repo kosli-dev/cli %s`, suite.acmeOrgKosliArguments), | ||
| }, | ||
| { | ||
| name: "03-getting an existing repo with --output json works", | ||
| cmd: fmt.Sprintf(`get repo kosli-dev/cli --output json %s`, suite.acmeOrgKosliArguments), | ||
| goldenJson: []jsonCheck{{"_embedded.repos", "non-empty"}}, | ||
| }, | ||
| { | ||
| name: "04-getting an existing repo with matching --provider works", | ||
| cmd: fmt.Sprintf(`get repo kosli-dev/cli --provider github %s`, suite.acmeOrgKosliArguments), | ||
| }, | ||
| { | ||
| name: "05-getting an existing repo with matching --provider and --output json works", | ||
| cmd: fmt.Sprintf(`get repo kosli-dev/cli --provider github --output json %s`, suite.acmeOrgKosliArguments), | ||
| goldenJson: []jsonCheck{{"_embedded.repos", "non-empty"}}, | ||
| }, | ||
| { | ||
| name: "06-getting a repo with a non-matching --provider returns not-found message", | ||
| cmd: fmt.Sprintf(`get repo kosli-dev/cli --provider gitlab %s`, suite.acmeOrgKosliArguments), | ||
| golden: "Repo was not found.\n", | ||
| }, | ||
| { | ||
| name: "07-getting a repo with a non-matching --repo-id returns not-found message", | ||
| cmd: fmt.Sprintf(`get repo kosli-dev/cli --repo-id non-existing-id %s`, suite.acmeOrgKosliArguments), | ||
| golden: "Repo was not found.\n", | ||
| }, | ||
| { | ||
| wantError: true, | ||
| name: "08-providing no argument fails", | ||
| cmd: fmt.Sprintf(`get repo %s`, suite.defaultKosliArguments), | ||
| golden: "Error: accepts 1 arg(s), received 0\n", | ||
| }, | ||
| { | ||
| wantError: true, | ||
| name: "09-providing more than one argument fails", | ||
| cmd: fmt.Sprintf(`get repo foo bar %s`, suite.defaultKosliArguments), | ||
| golden: "Error: accepts 1 arg(s), received 2\n", | ||
| }, | ||
| } | ||
|
|
||
| runTestCmd(suite.T(), tests) | ||
| } | ||
|
|
||
| // In order for 'go test' to run this suite, we need to create | ||
| // a normal test function and pass our suite to suite.Run | ||
| func TestGetRepoCommandTestSuite(t *testing.T) { | ||
| suite.Run(t, new(GetRepoCommandTestSuite)) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.