diff --git a/cloudbuild/repository.go b/cloudbuild/repository.go new file mode 100644 index 0000000000000000000000000000000000000000..868d36dc30a8b7c0b74f4f7e8cda29c23e6776a0 --- /dev/null +++ b/cloudbuild/repository.go @@ -0,0 +1,48 @@ +package cloudbuild + +import ( + "fmt" + + "google.golang.org/api/cloudbuild/v2" +) + +// LinkRepository links a repository to Cloud Build +// It creates a repository resource in Cloud Build that points to the specified repository +// in the source provider (GitHub, GitLab, etc.) +func (c *Client) LinkRepository(projectID, location, connectionName, repoName, remoteURI string) error { + // Format the connection name as required by the API (this is the parent for repository creation) + connectionRef := fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectID, location, connectionName) + + // Create a repository object with the required remoteUri field + repository := &cloudbuild.Repository{ + RemoteUri: remoteURI, // The API requires the remote URI to be specified + } + + // Make the API call to create/link the repository + _, err := c.service.Projects.Locations.Connections.Repositories.Create( + connectionRef, // The parent (connection) + repository, // Repository object with required fields + ).RepositoryId(repoName).Do() // Set the repository ID + + if err != nil { + return fmt.Errorf("error linking repository: %w", err) + } + + return nil +} + +// GetRepository retrieves information about a specific repository +func (c *Client) GetRepository(projectID, location, connectionName, repoName string) (*cloudbuild.Repository, error) { + // Format the repository name as required by the API + repoFullName := fmt.Sprintf("projects/%s/locations/%s/connections/%s/repositories/%s", + projectID, location, connectionName, repoName) + + // Make the API call to get the repository + repo, err := c.service.Projects.Locations.Connections.Repositories.Get(repoFullName).Do() + + if err != nil { + return nil, fmt.Errorf("error getting repository: %w", err) + } + + return repo, nil +} diff --git a/main.go b/main.go index 2bac49b69f14099f19f78e143a32cc646854e40d..6245a915a94f053d7af85a6715117ca34b020113 100644 --- a/main.go +++ b/main.go @@ -164,6 +164,123 @@ func main() { fmt.Println() } } + + case "link-repository": + // If connection name not provided via command line, get it from config + connNameToLink := *connectionName + if connNameToLink == "" { + // If there's only one connection in config, use that + if len(cfg.Connections) == 1 { + connNameToLink = cfg.Connections[0].Name + fmt.Printf("Using connection name from config: %s\n", connNameToLink) + } else if len(cfg.Connections) > 1 { + // If multiple connections, show the available options + fmt.Println("Multiple connections found in config. Please specify which one to use with --name flag:") + for i, conn := range cfg.Connections { + fmt.Printf("%d. %s\n", i+1, conn.Name) + } + os.Exit(1) + } else { + log.Fatalf("No connections found in config file") + } + } + + // Get the linkable repositories for this connection + log.Printf("Finding linkable repositories for connection %s in project %s (location: %s)", + connNameToLink, projectIDValue, locationValue) + + linkableRepos, err := client.ListLinkableRepositories(projectIDValue, locationValue, connNameToLink) + if err != nil { + log.Fatalf("Failed to list linkable repositories: %v", err) + } + + if len(linkableRepos) == 0 { + log.Fatalf("No linkable repositories found for connection %s", connNameToLink) + } + + // Use the first repository in the list + repoToLink := linkableRepos[0] + + // Extract and use a valid repository name + // First check if the repository has a RemoteUri field which usually contains the repo info + var repoName string + if repoToLink.RemoteUri != "" { + // Extract name from the remote URI (e.g., https://gitlab.com/namespace/repo-name) + uriParts := strings.Split(repoToLink.RemoteUri, "/") + if len(uriParts) > 0 { + repoName = uriParts[len(uriParts)-1] + // Remove .git suffix if present + repoName = strings.TrimSuffix(repoName, ".git") + } + } + + // If we still don't have a name, use attributes (which is a more reliable way) + if repoName == "" { + // For GitLab repositories, the name is in the attributes + printRepositoryInfo(repoToLink) // Print debug info + + // Try common attribute keys that might contain the name + if repoToLink.Annotations != nil { + if name, ok := repoToLink.Annotations["name"]; ok && name != "" { + repoName = name + } else if name, ok := repoToLink.Annotations["repository_name"]; ok && name != "" { + repoName = name + } + } + } + + // If we still don't have a name, ask the user to provide one manually + if repoName == "" { + fmt.Println("Unable to automatically determine repository name. Please provide one manually:") + fmt.Print("Repository name: ") + fmt.Scanln(&repoName) + } + + // Make sure the repository name is valid + if repoName == "" { + log.Fatalf("Cannot link repository: No valid repository name provided") + } + + fmt.Printf("Linking repository: %s\n", repoName) + + // We need to get the remote URI for the repository + var remoteURI string + if repoToLink.RemoteUri != "" { + // Use the remote URI from the repository object if available + remoteURI = repoToLink.RemoteUri + fmt.Printf("Using remote URI from repository data: %s\n", remoteURI) + } else { + // Otherwise construct a likely URI based on the connection and repository name + // This is a best guess and may need adjustment for different Git providers + for _, conn := range cfg.Connections { + if conn.Name == connNameToLink && conn.GitlabConfig != nil { + // If we have GitLab config, use the host URI to construct a repo URL + remoteURI = fmt.Sprintf("%s/%s.git", strings.TrimSuffix(conn.GitlabConfig.HostURI, "/"), repoName) + break + } + } + + // If we still don't have a remote URI, prompt the user + if remoteURI == "" { + fmt.Println("Please enter the remote URI for the repository (e.g., https://gitlab.com/namespace/repo.git):") + fmt.Print("Remote URI: ") + fmt.Scanln(&remoteURI) + + if remoteURI == "" { + log.Fatalf("Remote URI is required to link a repository") + } + } else { + fmt.Printf("Constructed remote URI: %s\n", remoteURI) + } + } + + // Link the repository with the remote URI + err = client.LinkRepository(projectIDValue, locationValue, connNameToLink, repoName, remoteURI) + if err != nil { + log.Fatalf("Failed to link repository: %v", err) + } + + fmt.Printf("Successfully linked repository %s to connection %s\n", repoName, connNameToLink) case "delete-connection": // If connection name not provided via command line, get it from config