Skip to content
Snippets Groups Projects
Commit dbe0cdbd authored by Shreyas Prabhu's avatar Shreyas Prabhu
Browse files

Create Connection

parents
No related branches found
No related tags found
No related merge requests found
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool
*.out
# Dependency directories
vendor/
# Go workspace file
go.work
# IDE specific files
.idea/
.vscode/
*.swp
*.swo
# Mac OS specific files
.DS_Store
# Environment variables
.env
# Log files
*.log
# Build output
build/
# Configuration files that might contain secrets
config/*.local.json
config/local.json
# Cloud Build Go Client
A Go project for interacting with Google Cloud Build, focused on managing connections and other Cloud Build operations.
## Features
- Creating connections in Cloud Build
## Prerequisites
- Go 1.19+
- Google Cloud SDK installed and configured
- Appropriate permissions to use Cloud Build
## Setup
1. Clone this repository
2. Run `go mod download` to fetch dependencies
3. Set up Google Cloud authentication:
```
gcloud auth application-default login
```
## Usage
To run the application:
```
go run main.go
```
You can also build the binary:
```
go build -o cloudbuild-client
./cloudbuild-client
```
## Configuration
The application uses the default Google Cloud credentials. Make sure you have the necessary permissions to create connections in Cloud Build.
## License
MIT
File added
package cloudbuild
import (
"context"
"fmt"
"os"
"golang.org/x/oauth2/google"
)
// AuthConfig represents authentication configuration
type AuthConfig struct {
AccessToken string // Bearer token
}
// LoadAuthFromEnv loads authentication information from environment variables
func LoadAuthFromEnv() *AuthConfig {
// Try to load access token from environment variables using standard names
var accessToken string
// Alternative environment variable names (excluding GOOGLE_ACCESS_TOKEN)
for _, envVar := range []string{"CLOUDBUILD_TOKEN", "GCP_ACCESS_TOKEN", "GOOGLE_OAUTH_TOKEN"} {
if token := os.Getenv(envVar); token != "" {
accessToken = token
break
}
}
return &AuthConfig{
AccessToken: accessToken,
}
}
// GetAccessToken gets the access token either from the provided config,
// from environment variables, or falls back to application default credentials
func GetAccessToken(ctx context.Context, authConfig *AuthConfig) (string, error) {
// If auth config is provided and has access token, use it
if authConfig != nil && authConfig.AccessToken != "" {
return authConfig.AccessToken, nil
}
// Try to load from environment
envAuth := LoadAuthFromEnv()
if envAuth.AccessToken != "" {
return envAuth.AccessToken, nil
}
// Fall back to application default credentials
tokenSource, err := google.DefaultTokenSource(ctx, "https://www.googleapis.com/auth/cloud-platform")
if err != nil {
return "", fmt.Errorf("error getting default token source: %w", err)
}
token, err := tokenSource.Token()
if err != nil {
return "", fmt.Errorf("error getting token: %w", err)
}
return token.AccessToken, nil
}
// CreateEnvFile creates a .env file with authentication information
func CreateEnvFile(path string, accessToken string) error {
content := fmt.Sprintf("# Google Cloud Build authentication\n"+
"GOOGLE_ACCESS_TOKEN=%s\n\n"+
"# Your project configuration\n"+
"CLOUDBUILD_PROJECT_ID=vison-code\n"+
"CLOUDBUILD_LOCATION=asia-east1\n", accessToken)
return os.WriteFile(path, []byte(content), 0600)
}
package cloudbuild
import (
"context"
"fmt"
"github.com/niveus/cloud-build-go/config"
"golang.org/x/oauth2"
"google.golang.org/api/cloudbuild/v2"
"google.golang.org/api/option"
)
// Client is a wrapper around the Cloud Build service
type Client struct {
service *cloudbuild.Service
}
// NewClient creates a new Cloud Build client using Google's standard authentication
func NewClient(ctx context.Context) (*Client, error) {
// Create client with appropriate scopes
opts := []option.ClientOption{
option.WithScopes("https://www.googleapis.com/auth/cloud-platform"),
}
// Create service using standard authentication
service, err := cloudbuild.NewService(ctx, opts...)
if err != nil {
return nil, fmt.Errorf("failed to create Cloud Build service: %w", err)
}
return &Client{service: service}, nil
}
// NewClientWithToken creates a client with a token
// The token is expected to be a valid OAuth2 token
func NewClientWithToken(ctx context.Context, token string) (*Client, error) {
// Create a token source using oauth2 directly
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: token,
TokenType: "Bearer",
})
// Create client with appropriate scopes and token
opts := []option.ClientOption{
option.WithScopes("https://www.googleapis.com/auth/cloud-platform"),
option.WithTokenSource(tokenSource),
}
// Create the Cloud Build service
service, err := cloudbuild.NewService(ctx, opts...)
if err != nil {
return nil, fmt.Errorf("failed to create Cloud Build service: %w", err)
}
return &Client{service: service}, nil
}
// CreateConnection creates a new connection in Cloud Build using v2 API
func (c *Client) CreateConnection(projectID, location, name, connType string) error {
// Format the parent string as required by the API
parent := fmt.Sprintf("projects/%s/locations/%s", projectID, location)
// Create a new connection object
connection := &cloudbuild.Connection{
Name: fmt.Sprintf("%s/connections/%s", parent, name),
Disabled: false,
}
// Set connection type based on the input
switch connType {
case "GITHUB":
// GitHub config would be specified here - we don't set it here as we'll add specific config later
case "GITLAB":
// GitLab config is handled separately in CreateGitLabConnection
return fmt.Errorf("for GitLab connections, please use CreateGitLabConnection method")
default:
return fmt.Errorf("unsupported connection type: %s", connType)
}
// Make the API call to create the connection
_, err := c.service.Projects.Locations.Connections.Create(
parent,
connection,
).ConnectionId(name).Do()
if err != nil {
return fmt.Errorf("error creating connection: %w", err)
}
return nil
}
// CreateGitLabConnection creates a new GitLab connection in Cloud Build using v2 API
func (c *Client) CreateGitLabConnection(projectID, location, name string, connConfig *config.GitlabConnectionConfig, annotations map[string]string) error {
// Format the parent string as required by the API
parent := fmt.Sprintf("projects/%s/locations/%s", projectID, location)
// Create the GitLab configuration using the proper v2 API types
// Set up the credentials first with required token secret versions
readCredential := &cloudbuild.UserCredential{
Username: "oauth2",
UserTokenSecretVersion: connConfig.ReadTokenVersion,
}
authCredential := &cloudbuild.UserCredential{
Username: "oauth2",
UserTokenSecretVersion: connConfig.AuthTokenVersion,
}
// Create the GitLab config
gitlabConfig := &cloudbuild.GoogleDevtoolsCloudbuildV2GitLabConfig{
HostUri: connConfig.HostURI,
WebhookSecretSecretVersion: connConfig.WebhookSecretVersion,
ReadAuthorizerCredential: readCredential,
AuthorizerCredential: authCredential,
}
// According to the v2 API, when creating a connection:
// 1. The Name should not be set - it's determined by the API
// 2. The connection ID is passed as a parameter to Create()
connection := &cloudbuild.Connection{
Disabled: false,
Annotations: annotations,
GitlabConfig: gitlabConfig,
}
// Make the API call to create the connection
_, err := c.service.Projects.Locations.Connections.Create(
parent,
connection,
).ConnectionId(name).Do()
if err != nil {
return fmt.Errorf("error creating GitLab connection: %w", err)
}
// Successfully created the connection
// Note: Due to eventual consistency in Google Cloud APIs, the connection
// might not be immediately available after creation. We'll skip the validation
// step as it's not necessary to confirm success, and we've already received
// a successful response from the API.
fmt.Printf("Successfully created GitLab connection: %s\n",
fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectID, location, name))
return nil
}
// GetConnection retrieves an existing connection from Cloud Build using v2 API
func (c *Client) GetConnection(projectID, location, name string) (*cloudbuild.Connection, error) {
// Format the connection name as required by the API
connectionName := fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectID, location, name)
// Make the API call to get the connection
resp, err := c.service.Projects.Locations.Connections.Get(connectionName).Do()
if err != nil {
return nil, fmt.Errorf("error getting connection: %w", err)
}
return resp, nil
}
// ListConnections lists all connections in the specified project and location using v2 API
func (c *Client) ListConnections(projectID, location string) ([]*cloudbuild.Connection, error) {
// Format the parent string as required by the API
parent := fmt.Sprintf("projects/%s/locations/%s", projectID, location)
// Make the API call to list connections
resp, err := c.service.Projects.Locations.Connections.List(parent).Do()
if err != nil {
return nil, fmt.Errorf("error listing connections: %w", err)
}
return resp.Connections, nil
}
// DeleteConnection deletes an existing connection from Cloud Build using v2 API
func (c *Client) DeleteConnection(projectID, location, name string) error {
// Format the connection name as required by the API
connectionName := fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectID, location, name)
// Make the API call to delete the connection
_, err := c.service.Projects.Locations.Connections.Delete(connectionName).Do()
if err != nil {
return fmt.Errorf("error deleting connection: %w", err)
}
return nil
}
package config
import (
"encoding/json"
"fmt"
"os"
)
// Config represents the configuration for the Cloud Build client
type Config struct {
ProjectID string `json:"project_id"`
Location string `json:"location"`
DefaultConnType string `json:"default_conn_type"`
Connections []ConnectionConfig `json:"connections,omitempty"`
}
// ConnectionConfig represents a connection configuration
type ConnectionConfig struct {
Name string `json:"name"`
Disabled bool `json:"disabled"`
Annotations map[string]string `json:"annotations,omitempty"`
GitlabConfig *GitlabConnectionConfig `json:"gitlab_config,omitempty"`
}
// GitlabConnectionConfig represents GitLab-specific connection configuration
type GitlabConnectionConfig struct {
HostURI string `json:"host_uri"`
WebhookSecretVersion string `json:"webhook_secret_version"`
ReadTokenVersion string `json:"read_token_version"`
AuthTokenVersion string `json:"auth_token_version"`
}
// LoadConfig loads the configuration from a JSON file
func LoadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
var config Config
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("failed to parse config file: %w", err)
}
// Set defaults if not specified
if config.Location == "" {
config.Location = "global"
}
if config.DefaultConnType == "" {
config.DefaultConnType = "GITHUB"
}
return &config, nil
}
// SaveConfig saves the configuration to a JSON file
func SaveConfig(config *Config, path string) error {
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal config: %w", err)
}
if err := os.WriteFile(path, data, 0644); err != nil {
return fmt.Errorf("failed to write config file: %w", err)
}
return nil
}
{
"project_id": "vison-code",
"location": "asia-east1",
"default_conn_type": "GITLAB",
"connections": [
{
"name": "rest-test-connection",
"disabled": false,
"annotations": {
"purpose": "Main connection for GitLab.com repositories",
"environment": "production"
},
"gitlab_config": {
"host_uri": "https://gitlab.niveussolutions.com",
"webhook_secret_version": "projects/584597185739/secrets/secreat-key/versions/1",
"read_token_version": "projects/584597185739/secrets/gitlab-access-token/versions/1",
"auth_token_version": "projects/584597185739/secrets/gitlab-access-token/versions/1"
}
}
]
}
go.mod 0 → 100644
module github.com/niveus/cloud-build-go
go 1.24.2
require (
cloud.google.com/go/auth v0.16.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
google.golang.org/api v0.233.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/grpc v1.72.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)
go.sum 0 → 100644
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
google.golang.org/api v0.233.0 h1:iGZfjXAJiUFSSaekVB7LzXl6tRfEKhUN7FkZN++07tI=
google.golang.org/api v0.233.0/go.mod h1:TCIVLLlcwunlMpZIhIp7Ltk77W+vUSdUKAAIlbxY44c=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 h1:IqsN8hx+lWLqlN+Sc3DoMy/watjofWiU8sRFgQ8fhKM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
main 0 → 100755
File added
main.go 0 → 100644
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"github.com/niveus/cloud-build-go/cloudbuild"
"github.com/niveus/cloud-build-go/config"
)
func main() {
// Define command-line flags
projectID := flag.String("project", "", "Google Cloud Project ID")
location := flag.String("location", "global", "Location for the connection (e.g., global, us-central1)")
connectionName := flag.String("name", "", "Name for the connection")
connectionType := flag.String("type", "GITHUB", "Type of connection (e.g., GITHUB, GITLAB)")
action := flag.String("action", "create", "Action to perform: create, get, list, delete, create-gitlab")
configPath := flag.String("config", "", "Path to config file (optional)")
token := flag.String("token", "", "Access token for authentication (optional)")
flag.Parse()
// Project ID can come from config file or command line
var projectIDValue, locationValue, connTypeValue string
// Load config file if specified
if *configPath != "" {
cfg, err := config.LoadConfig(*configPath)
if err != nil {
log.Printf("Warning: Failed to load config file: %v", err)
} else {
log.Printf("Loaded configuration from %s (Project: %s, Location: %s)",
*configPath, cfg.ProjectID, cfg.Location)
// Set defaults from config file
projectIDValue = cfg.ProjectID
locationValue = cfg.Location
connTypeValue = cfg.DefaultConnType
// Log the values that will be used
log.Printf("Config values initially set to: Project=%s, Location=%s, Type=%s",
projectIDValue, locationValue, connTypeValue)
}
}
// Command line arguments take precedence ONLY if they have non-default values
if *projectID != "" {
projectIDValue = *projectID
log.Printf("Using command-line project ID: '%s'", projectIDValue)
}
if *location != "" && *location != "global" {
locationValue = *location
log.Printf("Using command-line location: '%s'", locationValue)
}
if *connectionType != "" && *connectionType != "GITHUB" {
connTypeValue = *connectionType
log.Printf("Using command-line connection type: '%s'", connTypeValue)
}
// Check for required values after potentially loading from config
if projectIDValue == "" {
log.Fatal("project ID is required (provide via --project flag or config file)")
}
// Additional validation based on the action
if (*action == "create" || *action == "get" || *action == "delete") && *connectionName == "" {
log.Fatal("name flag is required for create, get, and delete actions")
}
ctx := context.Background()
// Create a Cloud Build client using our package
var client *cloudbuild.Client
var err error
// Authentication approach
// If a token is provided via command line, use that
// Otherwise, rely on Application Default Credentials
if *token != "" {
log.Printf("Using provided access token for authentication")
client, err = cloudbuild.NewClientWithToken(ctx, *token)
} else {
// Use Application Default Credentials
log.Printf("Using Application Default Credentials for authentication")
client, err = cloudbuild.NewClient(ctx)
}
if err != nil {
log.Fatalf("Failed to create Cloud Build client: %v", err)
}
// Perform the requested action
switch *action {
case "create":
err = client.CreateConnection(projectIDValue, locationValue, *connectionName, connTypeValue)
if err != nil {
log.Fatalf("Failed to create connection: %v", err)
}
fmt.Printf("Successfully created connection: %s\n", fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectIDValue, locationValue, *connectionName))
case "create-gitlab":
// Check if we have a configuration for GitLab
var connConfig *config.ConnectionConfig
if *configPath != "" {
cfg, err := config.LoadConfig(*configPath)
if err != nil {
log.Fatalf("Failed to load config file: %v", err)
}
// Find the connection config for the given name
for _, conn := range cfg.Connections {
if conn.Name == *connectionName || *connectionName == "" && len(cfg.Connections) == 1 {
connConfig = &conn
break
}
}
if connConfig == nil {
log.Fatalf("Connection configuration not found for '%s'", *connectionName)
}
if connConfig.GitlabConfig == nil {
log.Fatalf("GitLab configuration not found for connection '%s'", connConfig.Name)
}
// For GitLab connections, we'll use the values directly from the config file
// This is the most reliable way to ensure we're using the right values
projectIDValue = cfg.ProjectID
locationValue = cfg.Location
log.Printf("For GitLab connection, using config values: Project='%s', Location='%s'",
projectIDValue, locationValue)
fmt.Printf("Creating GitLab connection '%s' in project '%s' (location: '%s')\n",
connConfig.Name, projectIDValue, locationValue)
// Create the GitLab connection using the Cloud Build SDK
// This uses the official SDK methods, not manual URL construction
err = client.CreateGitLabConnection(
projectIDValue,
locationValue,
connConfig.Name,
connConfig.GitlabConfig,
connConfig.Annotations,
)
if err != nil {
log.Fatalf("Failed to create GitLab connection: %v", err)
}
fmt.Printf("Successfully created GitLab connection: %s\n",
fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectIDValue, locationValue, connConfig.Name))
} else {
log.Fatal("Config file is required for creating GitLab connections")
}
// Save example config if it doesn't exist
if *configPath == "" {
defaultConfigPath := filepath.Join("config", "config.json")
_, err := os.Stat(defaultConfigPath)
if os.IsNotExist(err) {
cfg := &config.Config{
ProjectID: projectIDValue,
Location: locationValue,
DefaultConnType: connTypeValue,
}
err = config.SaveConfig(cfg, defaultConfigPath)
if err != nil {
log.Printf("Note: Failed to save example config file: %v", err)
} else {
log.Printf("Note: Created example config file at %s", defaultConfigPath)
}
}
}
case "get":
connection, err := client.GetConnection(projectIDValue, locationValue, *connectionName)
if err != nil {
log.Fatalf("Failed to get connection: %v", err)
}
fmt.Printf("Connection details:\nName: %s\nDisabled: %t\n", connection.Name, connection.Disabled)
// Show type-specific details
if connection.GithubConfig != nil {
fmt.Printf("Type: GitHub\n")
if connection.GithubConfig.AppInstallationId > 0 {
fmt.Printf("App Installation ID: %d\n", connection.GithubConfig.AppInstallationId)
}
} else if connection.GitlabConfig != nil {
fmt.Printf("Type: GitLab\n")
fmt.Printf("Host URI: %s\n", connection.GitlabConfig.HostUri)
}
case "list":
connections, err := client.ListConnections(projectIDValue, locationValue)
if err != nil {
log.Fatalf("Failed to list connections: %v", err)
}
fmt.Printf("Found %d connections in project %s (location: %s):\n",
len(connections), projectIDValue, locationValue)
for i, conn := range connections {
// Determine connection type based on config
connType := "Unknown"
if conn.GithubConfig != nil {
connType = "GitHub"
} else if conn.GitlabConfig != nil {
connType = "GitLab"
}
fmt.Printf("%d. %s (Type: %s)\n", i+1, conn.Name, connType)
}
case "delete":
err := client.DeleteConnection(projectIDValue, locationValue, *connectionName)
if err != nil {
log.Fatalf("Failed to delete connection: %v", err)
}
fmt.Printf("Successfully deleted connection: %s\n", *connectionName)
default:
log.Fatalf("Unknown action: %s. Supported actions are: create, get, list, delete", *action)
}
}
#!/bin/bash
# This script helps set up the environment for using the Google Cloud Build Go client
# Extract access token from command line or environment
if [ "$1" != "" ]; then
ACCESS_TOKEN="$1"
else
# Try to extract from clipboard if it contains a token
if command -v xclip &> /dev/null; then
CLIPBOARD=$(xclip -selection clipboard -o 2>/dev/null | grep -oE 'Bearer [A-Za-z0-9._-]+' | cut -d ' ' -f 2)
if [ -n "$CLIPBOARD" ] && [[ $CLIPBOARD =~ ^ya29\..+ ]]; then
ACCESS_TOKEN="$CLIPBOARD"
echo "Found access token in clipboard"
fi
fi
# If still empty, ask for it
if [ -z "$ACCESS_TOKEN" ]; then
read -p "Enter your Google Cloud access token: " ACCESS_TOKEN
fi
fi
# Create .env file
cat > .env << EOF
# Google Cloud Build authentication
# Created: $(date)
GOOGLE_ACCESS_TOKEN=$ACCESS_TOKEN
# Project configuration (edit as needed)
CLOUDBUILD_PROJECT_ID=vison-code
CLOUDBUILD_LOCATION=asia-east1
EOF
echo "Created .env file with access token and project configuration"
echo "To use these settings in your terminal session, run:"
echo " export GOOGLE_ACCESS_TOKEN=$ACCESS_TOKEN"
echo " export CLOUDBUILD_PROJECT_ID=vison-code"
echo " export CLOUDBUILD_LOCATION=asia-east1"
# Make the file only readable by the owner
chmod 600 .env
# Offer to create the example connection
read -p "Do you want to create a sample GitLab connection using this token? (y/N): " CREATE_CONNECTION
if [[ $CREATE_CONNECTION =~ ^[Yy] ]]; then
export GOOGLE_ACCESS_TOKEN=$ACCESS_TOKEN
go run main.go --action create-gitlab --config config/config.json
fi
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment