@google-cloud/cloud-run-mcp 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
16
 
17
+ import { getServiceUsageClient } from '../clients.js';
17
18
  import { ensureBillingEnabled } from './billing.js';
18
19
 
19
20
  const PREREQUISITE_APIS = [
@@ -93,7 +94,6 @@ async function checkAndEnableApi(
93
94
 
94
95
  /**
95
96
  * Enables a single Google Cloud API with retry logic.
96
- * @param {object} serviceUsageClient - The Service Usage client.
97
97
  * @param {string} projectId - The Google Cloud project ID.
98
98
  * @param {string} api - The API identifier (e.g., 'run.googleapis.com').
99
99
  * @param {function(string, string=): void} progressCallback - A function to call with progress updates.
@@ -101,11 +101,15 @@ async function checkAndEnableApi(
101
101
  * @throws {Error} If the API fails to enable or if there's an issue checking its status.
102
102
  */
103
103
  export async function enableApiWithRetry(
104
- serviceUsageClient,
105
104
  projectId,
106
105
  api,
106
+ accessToken,
107
107
  progressCallback
108
108
  ) {
109
+ const serviceUsageClient = await getServiceUsageClient(
110
+ projectId,
111
+ accessToken
112
+ );
109
113
  const serviceName = `projects/${projectId}/services/${api}`;
110
114
  try {
111
115
  await checkAndEnableApi(
@@ -145,7 +149,6 @@ export async function enableApiWithRetry(
145
149
  * Throws an error if an API cannot be enabled.
146
150
  *
147
151
  * @async
148
- * @param {object} context - The context object containing clients and other parameters.
149
152
  * @param {string} projectId - The Google Cloud project ID.
150
153
  * @param {string[]} apis - An array of API identifiers to check and enable (e.g., 'run.googleapis.com').
151
154
  * @param {function(string, string=): void} progressCallback - A function to call with progress updates.
@@ -154,34 +157,24 @@ export async function enableApiWithRetry(
154
157
  * @returns {Promise<void>} A promise that resolves when all specified APIs are enabled.
155
158
  */
156
159
  export async function ensureApisEnabled(
157
- context,
158
160
  projectId,
159
161
  apis,
162
+ accessToken,
160
163
  progressCallback
161
164
  ) {
162
165
  for (const api of PREREQUISITE_APIS) {
163
- await enableApiWithRetry(
164
- context.serviceUsageClient,
165
- projectId,
166
- api,
167
- progressCallback
168
- );
166
+ await enableApiWithRetry(projectId, api, accessToken, progressCallback);
169
167
  }
170
168
 
171
169
  // Before enabling other APIs, ensure billing is enabled.
172
- await ensureBillingEnabled(context, projectId, progressCallback);
170
+ await ensureBillingEnabled(projectId, accessToken, progressCallback);
173
171
 
174
172
  const message = 'Checking and enabling required APIs...';
175
173
  console.log(message);
176
174
  if (progressCallback) progressCallback({ level: 'info', data: message });
177
175
 
178
176
  for (const api of apis) {
179
- await enableApiWithRetry(
180
- context.serviceUsageClient,
181
- projectId,
182
- api,
183
- progressCallback
184
- );
177
+ await enableApiWithRetry(projectId, api, accessToken, progressCallback);
185
178
  }
186
179
  const successMsg = 'All required APIs are enabled.';
187
180
  console.log(successMsg);
@@ -18,6 +18,7 @@ import {
18
18
  listBillingAccounts,
19
19
  attachProjectToBillingAccount,
20
20
  } from './billing.js';
21
+ import { getProjectsClient } from '../clients.js';
21
22
 
22
23
  /**
23
24
  * Lists all accessible Google Cloud Platform projects.
@@ -25,9 +26,8 @@ import {
25
26
  * @function listProjects
26
27
  * @returns {Promise<Array<{id: string}>>} A promise that resolves to an array of project objects, each with an 'id' property. Returns an empty array on error.
27
28
  */
28
- export async function listProjects() {
29
- const { ProjectsClient } = await import('@google-cloud/resource-manager');
30
- const client = new ProjectsClient();
29
+ export async function listProjects(accessToken) {
30
+ const client = await getProjectsClient(accessToken);
31
31
  try {
32
32
  const [projects] = await client.searchProjects();
33
33
  return projects.map((project) => ({
@@ -71,9 +71,8 @@ export function generateProjectId() {
71
71
  * @param {string} [parent] - Optional. The resource name of the parent under which the project is to be created. e.g., "organizations/123" or "folders/456".
72
72
  * @returns {Promise<{projectId: string}|null>} A promise that resolves to an object containing the new project's ID.
73
73
  */
74
- export async function createProject(projectId, parent) {
75
- const { ProjectsClient } = await import('@google-cloud/resource-manager');
76
- const client = new ProjectsClient();
74
+ export async function createProject(projectId, parent, accessToken) {
75
+ const client = await getProjectsClient(accessToken);
77
76
  let projectIdToUse = projectId;
78
77
 
79
78
  if (!projectIdToUse) {
@@ -113,10 +112,14 @@ export async function createProject(projectId, parent) {
113
112
  * @param {string} [parent] - Optional. The resource name of the parent under which the project is to be created. e.g., "organizations/123" or "folders/456".
114
113
  * @returns {Promise<{projectId: string, billingMessage: string}>} A promise that resolves to an object containing the project ID and a billing status message.
115
114
  */
116
- export async function createProjectAndAttachBilling(projectIdParam, parent) {
115
+ export async function createProjectAndAttachBilling(
116
+ projectIdParam,
117
+ parent,
118
+ accessToken
119
+ ) {
117
120
  let newProject;
118
121
  try {
119
- newProject = await createProject(projectIdParam, parent);
122
+ newProject = await createProject(projectIdParam, parent, accessToken);
120
123
  } catch (error) {
121
124
  throw new Error(`Failed to create project: ${error.message}`);
122
125
  }
@@ -129,7 +132,7 @@ export async function createProjectAndAttachBilling(projectIdParam, parent) {
129
132
  let billingMessage = `Project ${projectId} created successfully.`;
130
133
 
131
134
  try {
132
- const billingAccounts = await listBillingAccounts();
135
+ const billingAccounts = await listBillingAccounts(accessToken);
133
136
  if (billingAccounts && billingAccounts.length > 0) {
134
137
  const firstBillingAccount = billingAccounts.find((acc) => acc.open); // Prefer an open account
135
138
  if (firstBillingAccount) {
@@ -138,7 +141,8 @@ export async function createProjectAndAttachBilling(projectIdParam, parent) {
138
141
  );
139
142
  const billingInfo = await attachProjectToBillingAccount(
140
143
  projectId,
141
- firstBillingAccount.name
144
+ firstBillingAccount.name,
145
+ accessToken
142
146
  );
143
147
  if (billingInfo && billingInfo.billingEnabled) {
144
148
  billingMessage += ` It has been attached to billing account ${firstBillingAccount.displayName}.`;
@@ -172,9 +176,8 @@ export async function createProjectAndAttachBilling(projectIdParam, parent) {
172
176
  * @param {string} projectId - The ID of the project to delete.
173
177
  * @returns {Promise<void>} A promise that resolves when the delete operation is initiated.
174
178
  */
175
- export async function deleteProject(projectId) {
176
- const { ProjectsClient } = await import('@google-cloud/resource-manager');
177
- const client = new ProjectsClient();
179
+ export async function deleteProject(projectId, accessToken) {
180
+ const client = await getProjectsClient(accessToken);
178
181
  try {
179
182
  console.log(`Attempting to delete project with ID: ${projectId}`);
180
183
  await client.deleteProject({ name: `projects/${projectId}` });
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
16
 
17
+ import { getArtifactRegistryClient } from '../clients.js';
17
18
  import { callWithRetry } from './helpers.js';
18
19
  import { logAndProgress } from '../util/helpers.js';
19
20
 
@@ -22,7 +23,6 @@ import { logAndProgress } from '../util/helpers.js';
22
23
  * If the repository does not exist, it attempts to create it with the specified format.
23
24
  *
24
25
  * @async
25
- * @param {object} context - The context object containing clients and other parameters.
26
26
  * @param {string} projectId - The Google Cloud project ID.
27
27
  * @param {string} location - The Google Cloud region for the repository.
28
28
  * @param {string} repositoryId - The ID for the Artifact Registry repository.
@@ -32,15 +32,19 @@ import { logAndProgress } from '../util/helpers.js';
32
32
  * @throws {Error} If there's an error checking or creating the repository.
33
33
  */
34
34
  export async function ensureArtifactRegistryRepoExists(
35
- context,
36
35
  projectId,
36
+ accessToken,
37
37
  location,
38
38
  repositoryId,
39
39
  format = 'DOCKER',
40
40
  progressCallback
41
41
  ) {
42
+ const artifactRegistryClient = await getArtifactRegistryClient(
43
+ projectId,
44
+ accessToken
45
+ );
42
46
  const parent = `projects/${projectId}/locations/${location}`;
43
- const repoPath = context.artifactRegistryClient.repositoryPath(
47
+ const repoPath = artifactRegistryClient.repositoryPath(
44
48
  projectId,
45
49
  location,
46
50
  repositoryId
@@ -48,7 +52,7 @@ export async function ensureArtifactRegistryRepoExists(
48
52
 
49
53
  try {
50
54
  const [repository] = await callWithRetry(
51
- () => context.artifactRegistryClient.getRepository({ name: repoPath }),
55
+ () => artifactRegistryClient.getRepository({ name: repoPath }),
52
56
  `artifactRegistry.getRepository ${repositoryId}`
53
57
  );
54
58
  await logAndProgress(
@@ -68,7 +72,7 @@ export async function ensureArtifactRegistryRepoExists(
68
72
 
69
73
  const [operation] = await callWithRetry(
70
74
  () =>
71
- context.artifactRegistryClient.createRepository({
75
+ artifactRegistryClient.createRepository({
72
76
  parent: parent,
73
77
  repository: repositoryToCreate,
74
78
  repositoryId: repositoryId,
@@ -15,20 +15,22 @@ limitations under the License.
15
15
  */
16
16
 
17
17
  import protofiles from 'google-proto-files';
18
+ import {
19
+ getRunClient,
20
+ getServiceUsageClient,
21
+ getLoggingClient,
22
+ } from '../clients.js';
18
23
  import { callWithRetry, ensureApisEnabled } from './helpers.js';
19
24
  import { logAndProgress } from '../util/helpers.js';
20
25
 
21
- let runClient;
22
- let serviceUsageClient;
23
- let loggingClient;
24
-
25
- async function listCloudRunLocations(projectId) {
26
+ async function listCloudRunLocations(projectId, accessToken) {
26
27
  const listLocationsRequest = {
27
28
  name: `projects/${projectId}`,
28
29
  };
29
30
 
30
31
  const availableLocations = [];
31
32
  try {
33
+ const runClient = await getRunClient(projectId, accessToken);
32
34
  console.log('Listing Cloud Run supported locations:');
33
35
  const iterable = runClient.listLocationsAsync(listLocationsRequest);
34
36
  for await (const location of iterable) {
@@ -49,20 +51,11 @@ async function listCloudRunLocations(projectId) {
49
51
  * @param {string} projectId - The Google Cloud project ID.
50
52
  * @returns {Promise<object>} - A promise that resolves to an object mapping region to list of service objects in that region.
51
53
  */
52
- export async function listServices(projectId) {
53
- if (!runClient) {
54
- const { v2 } = await import('@google-cloud/run');
55
- const { ServicesClient } = v2;
56
- const { ServiceUsageClient } = await import('@google-cloud/service-usage');
57
- runClient = new ServicesClient({ projectId });
58
- serviceUsageClient = new ServiceUsageClient({ projectId });
59
- }
60
- const context = {
61
- runClient: runClient,
62
- serviceUsageClient: serviceUsageClient,
63
- };
64
- await ensureApisEnabled(context, projectId, ['run.googleapis.com']);
65
- const locations = await listCloudRunLocations(projectId);
54
+ export async function listServices(projectId, accessToken) {
55
+ const runClient = await getRunClient(projectId, accessToken);
56
+
57
+ await ensureApisEnabled(projectId, ['run.googleapis.com'], accessToken);
58
+ const locations = await listCloudRunLocations(projectId, accessToken);
66
59
 
67
60
  const allServices = {};
68
61
  for (const location of locations) {
@@ -92,12 +85,8 @@ export async function listServices(projectId) {
92
85
  * @param {string} serviceId - The ID of the Cloud Run service.
93
86
  * @returns {Promise<object>} - A promise that resolves to the service object.
94
87
  */
95
- export async function getService(projectId, location, serviceId) {
96
- if (!runClient) {
97
- const { v2 } = await import('@google-cloud/run');
98
- const { ServicesClient } = v2;
99
- runClient = new ServicesClient({ projectId });
100
- }
88
+ export async function getService(projectId, location, serviceId, accessToken) {
89
+ const runClient = await getRunClient(projectId, accessToken);
101
90
 
102
91
  const servicePath = runClient.servicePath(projectId, location, serviceId);
103
92
 
@@ -136,13 +125,10 @@ export async function getServiceLogs(
136
125
  projectId,
137
126
  location,
138
127
  serviceId,
128
+ accessToken,
139
129
  requestOptions
140
130
  ) {
141
- if (!loggingClient) {
142
- const { Logging } = await import('@google-cloud/logging');
143
- loggingClient = new Logging({ projectId });
144
- }
145
-
131
+ const loggingClient = await getLoggingClient(projectId, accessToken);
146
132
  try {
147
133
  const LOG_SEVERITY = 'DEFAULT'; // e.g., 'DEFAULT', 'INFO', 'WARNING', 'ERROR'
148
134
  const PAGE_SIZE = 100; // Number of log entries to retrieve per page
@@ -237,21 +223,17 @@ function formatLogEntry(entry) {
237
223
  * @throws {Error} If there's an error checking the service (other than not found).
238
224
  */
239
225
  export async function checkCloudRunServiceExists(
240
- context,
241
226
  projectId,
242
227
  location,
243
228
  serviceId,
229
+ accessToken,
244
230
  progressCallback
245
231
  ) {
246
- const parent = context.runClient.locationPath(projectId, location);
247
- const servicePath = context.runClient.servicePath(
248
- projectId,
249
- location,
250
- serviceId
251
- );
232
+ const runClient = await getRunClient(projectId, accessToken);
233
+ const servicePath = runClient.servicePath(projectId, location, serviceId);
252
234
  try {
253
235
  await callWithRetry(
254
- () => context.runClient.getService({ name: servicePath }),
236
+ () => runClient.getService({ name: servicePath }),
255
237
  `getService ${serviceId}`
256
238
  );
257
239
  await logAndProgress(
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
16
 
17
+ import { getStorageClient } from '../clients.js';
17
18
  import { callWithRetry } from './helpers.js';
18
19
  import { logAndProgress } from '../util/helpers.js';
19
20
 
@@ -22,7 +23,7 @@ import { logAndProgress } from '../util/helpers.js';
22
23
  * If the bucket does not exist, it attempts to create it in the specified location.
23
24
  *
24
25
  * @async
25
- * @param {object} context - The context object containing clients and other parameters.
26
+ * @param {string} projectId - The Google Cloud project ID.
26
27
  * @param {string} bucketName - The name of the storage bucket.
27
28
  * @param {string} [location='us'] - The location to create the bucket in if it doesn't exist. Defaults to 'us'.
28
29
  * @param {function(object): void} [progressCallback] - Optional callback for progress updates.
@@ -30,12 +31,14 @@ import { logAndProgress } from '../util/helpers.js';
30
31
  * @throws {Error} If there's an error checking or creating the bucket.
31
32
  */
32
33
  export async function ensureStorageBucketExists(
33
- context,
34
+ projectId,
34
35
  bucketName,
35
36
  location = 'us',
37
+ accessToken,
36
38
  progressCallback
37
39
  ) {
38
- const bucket = context.storage.bucket(bucketName);
40
+ const storage = await getStorageClient(projectId, accessToken);
41
+ const bucket = storage.bucket(bucketName);
39
42
  try {
40
43
  const [exists] = await callWithRetry(
41
44
  () => bucket.exists(),
@@ -54,8 +57,7 @@ export async function ensureStorageBucketExists(
54
57
  );
55
58
  try {
56
59
  const [createdBucket] = await callWithRetry(
57
- () =>
58
- context.storage.createBucket(bucketName, { location: location }),
60
+ () => storage.createBucket(bucketName, { location: location }),
59
61
  `storage.createBucket ${bucketName}`
60
62
  );
61
63
  await logAndProgress(
@@ -85,7 +87,6 @@ export async function ensureStorageBucketExists(
85
87
  * Uploads a buffer to a specified Google Cloud Storage bucket and blob name.
86
88
  *
87
89
  * @async
88
- * @param {object} context - The context object containing clients and other parameters.
89
90
  * @param {import('@google-cloud/storage').Bucket} bucket - The Google Cloud Storage bucket object.
90
91
  * @param {Buffer} buffer - The buffer containing the data to upload.
91
92
  * @param {string} destinationBlobName - The name for the blob in the bucket.
@@ -94,7 +95,6 @@ export async function ensureStorageBucketExists(
94
95
  * @throws {Error} If the upload fails.
95
96
  */
96
97
  export async function uploadToStorageBucket(
97
- context,
98
98
  bucket,
99
99
  buffer,
100
100
  destinationBlobName,