-
Notifications
You must be signed in to change notification settings - Fork 3
Cloud Deploy MCP tools (vibe coded) #81
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: main
Are you sure you want to change the base?
Changes from all commits
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 | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,162 @@ | ||||||
| // Copyright 2024 Google LLC | ||||||
| // | ||||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
| // you may not use this file except in compliance with the License. | ||||||
| // You may obtain a copy of the License at | ||||||
| // | ||||||
| // https://www.apache.org/licenses/LICENSE-2.0 | ||||||
| // | ||||||
| // Unless required by applicable law or agreed to in writing, software | ||||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
| // See the License for the specific language governing permissions and | ||||||
| // limitations under the License. | ||||||
|
|
||||||
| package clouddeployclient | ||||||
|
|
||||||
| import ( | ||||||
| "context" | ||||||
| "fmt" | ||||||
|
|
||||||
| deploy "cloud.google.com/go/deploy/apiv1" | ||||||
| deploypb "cloud.google.com/go/deploy/apiv1/deploypb" | ||||||
| "google.golang.org/api/iterator" | ||||||
| ) | ||||||
|
|
||||||
| // contextKey is a private type to use as a key for context values. | ||||||
| type contextKey string | ||||||
|
|
||||||
| const ( | ||||||
| cloudDeployClientContextKey contextKey = "cloudDeployClient" | ||||||
| ) | ||||||
|
|
||||||
| // ClientFrom returns the CloudDeployClient stored in the context, if any. | ||||||
| func ClientFrom(ctx context.Context) (CloudDeployClient, bool) { | ||||||
| client, ok := ctx.Value(cloudDeployClientContextKey).(CloudDeployClient) | ||||||
| return client, ok | ||||||
| } | ||||||
|
|
||||||
| // ContextWithClient returns a new context with the provided CloudDeployClient. | ||||||
| func ContextWithClient(ctx context.Context, client CloudDeployClient) context.Context { | ||||||
| return context.WithValue(ctx, cloudDeployClientContextKey, client) | ||||||
| } | ||||||
|
|
||||||
| // CloudDeployClient is an interface for interacting with the Cloud Deploy API. | ||||||
| type CloudDeployClient interface { | ||||||
| ListDeliveryPipelines(ctx context.Context, projectID, location string) ([]*deploypb.DeliveryPipeline, error) | ||||||
| ListTargets(ctx context.Context, projectID, location string) ([]*deploypb.Target, error) | ||||||
| ListReleases(ctx context.Context, projectID, location, pipelineID string) ([]*deploypb.Release, error) | ||||||
| ListRollouts(ctx context.Context, projectID, location, pipelineID, releaseID string) ([]*deploypb.Rollout, error) | ||||||
| CreateRelease(ctx context.Context, projectID, location, pipelineID, releaseID string) (*deploy.CreateReleaseOperation, error) | ||||||
| } | ||||||
|
|
||||||
| // NewCloudDeployClient creates a new Cloud Deploy client. | ||||||
| func NewCloudDeployClient(ctx context.Context) (CloudDeployClient, error) { | ||||||
| c, err := deploy.NewCloudDeployClient(ctx) | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to create Cloud Deploy client: %v", err) | ||||||
| } | ||||||
|
|
||||||
| return &CloudDeployClientImpl{ | ||||||
| client: c, | ||||||
| }, nil | ||||||
| } | ||||||
|
|
||||||
| // CloudDeployClientImpl is an implementation of the CloudDeployClient interface. | ||||||
| type CloudDeployClientImpl struct { | ||||||
| client *deploy.CloudDeployClient | ||||||
| } | ||||||
|
|
||||||
| // ListDeliveryPipelines lists Delivery Pipelines in a given project and location | ||||||
| func (c *CloudDeployClientImpl) ListDeliveryPipelines(ctx context.Context, projectID, location string) ([]*deploypb.DeliveryPipeline, error) { | ||||||
| req := &deploypb.ListDeliveryPipelinesRequest{ | ||||||
| Parent: fmt.Sprintf("projects/%s/locations/%s", projectID, location), | ||||||
| } | ||||||
| it := c.client.ListDeliveryPipelines(ctx, req) | ||||||
| var pipelines []*deploypb.DeliveryPipeline | ||||||
| for { | ||||||
| pipeline, err := it.Next() | ||||||
| if err == iterator.Done { | ||||||
| break | ||||||
| } | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to list delivery pipelines: %w", err) | ||||||
| } | ||||||
| pipelines = append(pipelines, pipeline) | ||||||
| } | ||||||
| return pipelines, nil | ||||||
| } | ||||||
|
|
||||||
| // ListTargets lists Targets in a given project and location | ||||||
| func (c *CloudDeployClientImpl) ListTargets(ctx context.Context, projectID, location string) ([]*deploypb.Target, error) { | ||||||
| req := &deploypb.ListTargetsRequest{ | ||||||
| Parent: fmt.Sprintf("projects/%s/locations/%s", projectID, location), | ||||||
| } | ||||||
| it := c.client.ListTargets(ctx, req) | ||||||
| var targets []*deploypb.Target | ||||||
| for { | ||||||
| target, err := it.Next() | ||||||
| if err == iterator.Done { | ||||||
| break | ||||||
| } | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to list targets: %w", err) | ||||||
| } | ||||||
| targets = append(targets, target) | ||||||
| } | ||||||
| return targets, nil | ||||||
| } | ||||||
|
|
||||||
| // ListReleases lists Releases for a specific Delivery Pipeline | ||||||
| func (c *CloudDeployClientImpl) ListReleases(ctx context.Context, projectID, location, pipelineID string) ([]*deploypb.Release, error) { | ||||||
| req := &deploypb.ListReleasesRequest{ | ||||||
| Parent: fmt.Sprintf("projects/%s/locations/%s/deliveryPipelines/%s", projectID, location, pipelineID), | ||||||
| } | ||||||
| it := c.client.ListReleases(ctx, req) | ||||||
| var releases []*deploypb.Release | ||||||
| for { | ||||||
| release, err := it.Next() | ||||||
| if err == iterator.Done { | ||||||
| break | ||||||
| } | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to list releases: %w", err) | ||||||
| } | ||||||
| releases = append(releases, release) | ||||||
| } | ||||||
| return releases, nil | ||||||
| } | ||||||
|
|
||||||
| // ListRollouts lists Rollouts for a specific Release | ||||||
| func (c *CloudDeployClientImpl) ListRollouts(ctx context.Context, projectID, location, pipelineID, releaseID string) ([]*deploypb.Rollout, error) { | ||||||
| req := &deploypb.ListRolloutsRequest{ | ||||||
| Parent: fmt.Sprintf("projects/%s/locations/%s/deliveryPipelines/%s/releases/%s", projectID, location, pipelineID, releaseID), | ||||||
| } | ||||||
| it := c.client.ListRollouts(ctx, req) | ||||||
| var rollouts []*deploypb.Rollout | ||||||
| for { | ||||||
| rollout, err := it.Next() | ||||||
| if err == iterator.Done { | ||||||
| break | ||||||
| } | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to list rollouts: %w", err) | ||||||
| } | ||||||
| rollouts = append(rollouts, rollout) | ||||||
| } | ||||||
| return rollouts, nil | ||||||
| } | ||||||
|
|
||||||
| // CreateRelease creates a new Release to trigger a deployment | ||||||
| func (c *CloudDeployClientImpl) CreateRelease(ctx context.Context, projectID, location, pipelineID, releaseID string) (*deploy.CreateReleaseOperation, error) { | ||||||
| req := &deploypb.CreateReleaseRequest{ | ||||||
| Parent: fmt.Sprintf("projects/%s/locations/%s/deliveryPipelines/%s", projectID, location, pipelineID), | ||||||
| ReleaseId: releaseID, | ||||||
| Release: &deploypb.Release{}, | ||||||
|
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. The The
Suggested change
|
||||||
| } | ||||||
| op, err := c.client.CreateRelease(ctx, req) | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to create release: %w", err) | ||||||
| } | ||||||
| return op, nil | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| // Copyright 2024 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // https://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package mocks | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| deploy "cloud.google.com/go/deploy/apiv1" | ||
| deploypb "cloud.google.com/go/deploy/apiv1/deploypb" | ||
| ) | ||
|
|
||
| // MockCloudDeployClient is a mock implementation of the CloudDeployClient interface. | ||
| type MockCloudDeployClient struct { | ||
| ListDeliveryPipelinesFunc func(ctx context.Context, projectID, location string) ([]*deploypb.DeliveryPipeline, error) | ||
| ListTargetsFunc func(ctx context.Context, projectID, location string) ([]*deploypb.Target, error) | ||
| ListReleasesFunc func(ctx context.Context, projectID, location, pipelineID string) ([]*deploypb.Release, error) | ||
| ListRolloutsFunc func(ctx context.Context, projectID, location, pipelineID, releaseID string) ([]*deploypb.Rollout, error) | ||
| CreateReleaseFunc func(ctx context.Context, projectID, location, pipelineID, releaseID string) (*deploy.CreateReleaseOperation, error) | ||
| } | ||
|
|
||
| func (m *MockCloudDeployClient) ListDeliveryPipelines(ctx context.Context, projectID, location string) ([]*deploypb.DeliveryPipeline, error) { | ||
| if m.ListDeliveryPipelinesFunc != nil { | ||
| return m.ListDeliveryPipelinesFunc(ctx, projectID, location) | ||
| } | ||
| return nil, nil | ||
| } | ||
|
|
||
| func (m *MockCloudDeployClient) ListTargets(ctx context.Context, projectID, location string) ([]*deploypb.Target, error) { | ||
| if m.ListTargetsFunc != nil { | ||
| return m.ListTargetsFunc(ctx, projectID, location) | ||
| } | ||
| return nil, nil | ||
| } | ||
|
|
||
| func (m *MockCloudDeployClient) ListReleases(ctx context.Context, projectID, location, pipelineID string) ([]*deploypb.Release, error) { | ||
| if m.ListReleasesFunc != nil { | ||
| return m.ListReleasesFunc(ctx, projectID, location, pipelineID) | ||
| } | ||
| return nil, nil | ||
| } | ||
|
|
||
| func (m *MockCloudDeployClient) ListRollouts(ctx context.Context, projectID, location, pipelineID, releaseID string) ([]*deploypb.Rollout, error) { | ||
| if m.ListRolloutsFunc != nil { | ||
| return m.ListRolloutsFunc(ctx, projectID, location, pipelineID, releaseID) | ||
| } | ||
| return nil, nil | ||
| } | ||
|
|
||
| func (m *MockCloudDeployClient) CreateRelease(ctx context.Context, projectID, location, pipelineID, releaseID string) (*deploy.CreateReleaseOperation, error) { | ||
| if m.CreateReleaseFunc != nil { | ||
| return m.CreateReleaseFunc(ctx, projectID, location, pipelineID, releaseID) | ||
| } | ||
| return nil, nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The four
List...functions (ListDeliveryPipelines,ListTargets,ListReleases,ListRollouts) contain very similar logic for iterating through pages of results. This duplicated code can be refactored into a single generic helper function to improve maintainability and reduce boilerplate.Consider creating a generic function to handle the pagination logic, which would make the
List...methods much more concise. For example: