-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add ability to detect current project #242
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
base: master
Are you sure you want to change the base?
Changes from 7 commits
58381a0
20337e4
8e81584
dd35574
01074b3
5e93783
155bbec
e2a6713
e275bb0
ddb9878
5adc57e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| FROM golang:1.20 | ||
| FROM golang:1.21 | ||
|
|
||
| RUN go install gotest.tools/gotestsum@v1.12.2 | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "log" | ||
| "os" | ||
|
|
@@ -283,6 +284,29 @@ func getAllAgents(client client.AgentApiV1AlphaApi, agentType string) ([]models. | |
| return agents, nil | ||
| } | ||
|
|
||
| var GetCurrentProjectCmd = &cobra.Command{ | ||
| Use: "current_project", | ||
| Short: "Get project for current directory", | ||
| Aliases: []string{"cur"}, | ||
| Long: ``, | ||
|
danudey marked this conversation as resolved.
Outdated
danudey marked this conversation as resolved.
Outdated
|
||
|
|
||
| Run: func(cmd *cobra.Command, args []string) { | ||
| project, err := utils.InferProject() | ||
| utils.Check(err) | ||
|
|
||
| doJSON, err := cmd.Flags().GetBool("json") | ||
| utils.Check(err) | ||
| if doJSON { | ||
| jsonBody, err := json.MarshalIndent(project, "", " ") | ||
| utils.Check(err) | ||
| fmt.Println(string(jsonBody)) | ||
| } else { | ||
| fmt.Println(project.Metadata.Id, project.Metadata.Name, project.Spec.Repository.Url) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we could format this in some way that is easy to split the string |
||
| } | ||
|
|
||
| }, | ||
| } | ||
|
|
||
| var GetProjectCmd = &cobra.Command{ | ||
| Use: "projects [name]", | ||
| Short: "Get projects.", | ||
|
|
@@ -531,6 +555,9 @@ func init() { | |
| getCmd.AddCommand(GetProjectCmd) | ||
| getCmd.AddCommand(GetAgentTypeCmd) | ||
|
|
||
| getCmd.AddCommand(GetCurrentProjectCmd) | ||
| GetCurrentProjectCmd.Flags().Bool("json", false, "print project information as json") | ||
|
|
||
| GetAgentsCmd.Flags().StringP("agent-type", "t", "", | ||
| "agent type; if specified, returns only agents for this agent type") | ||
| getCmd.AddCommand(GetAgentsCmd) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,12 +2,14 @@ package utils | |
|
|
||
| import ( | ||
| "fmt" | ||
| "slices" | ||
|
|
||
| "log" | ||
| "os/exec" | ||
| "strings" | ||
|
|
||
| "github.com/semaphoreci/cli/api/client" | ||
| "github.com/semaphoreci/cli/api/models" | ||
| ) | ||
|
|
||
| func GetProjectId(name string) string { | ||
|
|
@@ -20,46 +22,68 @@ func GetProjectId(name string) string { | |
| } | ||
|
|
||
| func InferProjectName() (string, error) { | ||
| originUrl, err := getGitOriginUrl() | ||
| project, err := InferProject() | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| return project.Metadata.Name, nil | ||
| } | ||
|
|
||
| log.Printf("Origin url: '%s'\n", originUrl) | ||
| func InferProject() (models.ProjectV1Alpha, error) { | ||
| originURLs, err := getAllGitRemoteURLs() | ||
| if err != nil { | ||
| return models.ProjectV1Alpha{}, err | ||
| } | ||
|
|
||
| projectName, err := getProjectIdFromUrl(originUrl) | ||
| project, err := getProjectFromUrls(originURLs) | ||
| if err != nil { | ||
| return "", err | ||
| log.Printf("no project found for any configured remotes (%s)", strings.Join(originURLs, ", ")) | ||
| return models.ProjectV1Alpha{}, fmt.Errorf("no project found for any configured remotes: %w", err) | ||
| } | ||
|
|
||
| return projectName, nil | ||
| return project, nil | ||
| } | ||
|
|
||
| func getProjectIdFromUrl(url string) (string, error) { | ||
| project, err := getProjectFromUrls([]string{url}) | ||
| if err != nil { | ||
| return "", fmt.Errorf("project with url %s not found in this org", url) | ||
| } | ||
| return project.Metadata.Id, nil | ||
|
|
||
| } | ||
|
|
||
| func getProjectFromUrls(urls []string) (models.ProjectV1Alpha, error) { | ||
| projectClient := client.NewProjectV1AlphaApi() | ||
| projects, err := projectClient.ListProjects() | ||
|
|
||
| if err != nil { | ||
| return "", fmt.Errorf("getting project list failed '%s'", err) | ||
| return models.ProjectV1Alpha{}, fmt.Errorf("getting project list failed '%s'", err) | ||
| } | ||
|
Comment on lines
+111
to
116
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code is to remove duplicates right? This current implementation is O(n²) we could use a map here very easily |
||
|
|
||
| projectName := "" | ||
| for _, p := range projects.Projects { | ||
| if p.Spec.Repository.Url == url { | ||
| projectName = p.Metadata.Name | ||
| break | ||
| if slices.Contains(urls, p.Spec.Repository.Url) { | ||
| return p, nil | ||
| } | ||
| } | ||
|
|
||
| if projectName == "" { | ||
| return "", fmt.Errorf("project with url '%s' not found in this org", url) | ||
| } | ||
| return models.ProjectV1Alpha{}, fmt.Errorf("no project found in this org with a url matching any of this repository's remotes") | ||
| } | ||
|
|
||
| return projectName, nil | ||
| func getGitRemotes() ([]string, error) { | ||
| args := []string{"remote"} | ||
| cmd := exec.Command("git", args...) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| cmd_string := fmt.Sprintf("'%s %s'", "git", strings.Join(args, " ")) | ||
| user_msg := "You are probably not in a git directory?" | ||
| return []string{}, fmt.Errorf("%s failed with message: '%s'\n%s", cmd_string, err, user_msg) | ||
| } | ||
| return strings.Split(strings.TrimSpace(string(out)), "\n"), nil | ||
| } | ||
|
|
||
| func getGitOriginUrl() (string, error) { | ||
| args := []string{"config", "remote.origin.url"} | ||
| func getGitRemoteUrl(remote string) (string, error) { | ||
| args := []string{"config", fmt.Sprintf("remote.%s.url", remote)} | ||
|
|
||
| cmd := exec.Command("git", args...) | ||
| out, err := cmd.CombinedOutput() | ||
|
|
@@ -71,3 +95,24 @@ func getGitOriginUrl() (string, error) { | |
|
|
||
| return strings.TrimSpace(string(out)), nil | ||
| } | ||
|
|
||
| func getAllGitRemoteURLs() ([]string, error) { | ||
| gitRemotes, err := getGitRemotes() | ||
| if err != nil { | ||
| return gitRemotes, err | ||
| } | ||
| var gitRemoteURLs []string | ||
| for _, remote := range gitRemotes { | ||
| remoteURL, err := getGitRemoteUrl(remote) | ||
| if err != nil { | ||
| log.Printf("could not get URL for remote %s", remote) | ||
| } else { | ||
| gitRemoteURLs = append(gitRemoteURLs, remoteURL) | ||
| } | ||
| } | ||
|
Comment on lines
+170
to
+183
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part of the code is O(n*m) because of the nested loops, you could use maps to improve the complexity to O(n+m). I think this is not that much about performance but for readability. But I can see some cases that a few ms can compound in the long run. |
||
| return gitRemoteURLs, nil | ||
| } | ||
|
|
||
| func getGitOriginUrl() (string, error) { | ||
| return getGitRemoteUrl("origin") | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| module github.com/semaphoreci/cli | ||
|
|
||
| go 1.20 | ||
| go 1.21 | ||
|
|
||
| require ( | ||
| github.com/ghodss/yaml v1.0.0 | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.