@google-cloud/cloud-run-mcp 1.3.0 → 1.6.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.
Files changed (44) hide show
  1. package/.c8rc.json +9 -0
  2. package/.github/images/deploy_from_apps.gif +0 -0
  3. package/.github/images/deploy_from_ide.gif +0 -0
  4. package/.github/images/deploycli.gif +0 -0
  5. package/.github/workflows/lint-checker.yml +17 -0
  6. package/.github/workflows/local-tests.yml +1 -1
  7. package/.kokoro/kokoro_build.sh +22 -0
  8. package/.kokoro/presubmit.cfg +21 -0
  9. package/.kokoro/run_tests.sh +31 -0
  10. package/CONTRIBUTING.md +29 -8
  11. package/README.md +65 -19
  12. package/REVIEWING.md +20 -0
  13. package/gemini-extension/GEMINI.md +3 -3
  14. package/lib/cloud-api/build.js +200 -0
  15. package/lib/{gcp-api-helpers.js → cloud-api/helpers.js} +12 -8
  16. package/lib/{gcp-projects.js → cloud-api/projects.js} +58 -28
  17. package/lib/cloud-api/registry.js +98 -0
  18. package/lib/{cloud-run-services.js → cloud-api/run.js} +103 -21
  19. package/lib/cloud-api/storage.js +123 -0
  20. package/lib/deployment/deployer.js +474 -0
  21. package/lib/util/archive.js +95 -0
  22. package/lib/util/helpers.js +42 -0
  23. package/mcp-server.js +29 -11
  24. package/package.json +9 -6
  25. package/test/local/cloud-api/build.test.js +436 -0
  26. package/test/local/cloud-api/projects.test.js +18 -0
  27. package/test/local/mcp-server-streamable-http.test.js +57 -0
  28. package/test/local/mcp-server.test.js +0 -1
  29. package/test/local/notifications.test.js +48 -0
  30. package/test/local/tools.test.js +143 -124
  31. package/test/need-gcp/cloud-run-services.test.js +57 -77
  32. package/test/need-gcp/deployer.test.js +71 -0
  33. package/test/need-gcp/gcp-auth-check.test.js +1 -1
  34. package/test/need-gcp/gcp-projects.test.js +6 -60
  35. package/test/need-gcp/test-helpers.js +175 -0
  36. package/test/need-gcp/workflows/deployment-workflows.test.js +100 -0
  37. package/tools/register-tools.js +612 -0
  38. package/tools/tools.js +48 -0
  39. package/lib/cloud-run-deploy.js +0 -917
  40. package/test/need-gcp/cloud-run-deploy.test.js +0 -158
  41. package/tools.js +0 -969
  42. /package/lib/{gcp-auth-check.js → cloud-api/auth.js} +0 -0
  43. /package/lib/{gcp-billing-accounts.js → cloud-api/billing.js} +0 -0
  44. /package/lib/{gcp-metadata.js → cloud-api/metadata.js} +0 -0
package/.c8rc.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "all": true,
3
+ "reporter": ["lcov", "text"],
4
+ "lines": 43,
5
+ "functions": 35,
6
+ "branches": 70,
7
+ "statements": 43,
8
+ "exclude": ["**/test/**", "**/coverage/**"]
9
+ }
Binary file
@@ -0,0 +1,17 @@
1
+ name: Run Lint Checker
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ lint-check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-node@v4
14
+ with:
15
+ node-version: 20
16
+ - run: npm ci
17
+ - run: npm run lint:check
@@ -3,7 +3,7 @@ name: Run Local Tests
3
3
  on:
4
4
  push:
5
5
  pull_request:
6
- branches: [ main ]
6
+ branches: [main]
7
7
 
8
8
  jobs:
9
9
  test:
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+
3
+ # Copyright 2022 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # Code under repo is checked out to ${KOKORO_ARTIFACTS_DIR}/git.
18
+ # The final directory name in this path is determined by the scm name specified
19
+ # in the job configuration.
20
+
21
+ cd "${KOKORO_ARTIFACTS_DIR}/github/cloud-run-mcp"
22
+ .kokoro/run_tests.sh
@@ -0,0 +1,21 @@
1
+ # -*- protobuffer -*-
2
+ # proto-file: google3/devtools/kokoro/config/proto/build.proto
3
+ # proto-message: BuildConfig
4
+
5
+ # Location of the bash script. Should have value <github_scm.name>/<path_from_repository_root>.
6
+ # github_scm.name is specified in the job configuration (next section).
7
+ build_file: "cloud-run-mcp/.kokoro/kokoro_build.sh"
8
+
9
+ container_properties {
10
+ docker_image: "us-central1-docker.pkg.dev/kokoro-container-bakery/kokoro/ubuntu/ubuntu2204/full:next"
11
+ }
12
+
13
+ env_vars {
14
+ key: "GOOGLE_CLOUD_PROJECT"
15
+ value: "cloud-run-mcp-server-testing"
16
+ }
17
+
18
+ env_vars {
19
+ key: "GCP_PARENT"
20
+ value: "folders/138095058155"
21
+ }
@@ -0,0 +1,31 @@
1
+ #!/bin/bash
2
+ #
3
+ # Copyright 2022 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # Fail on any error.
18
+ set -xe
19
+
20
+ # cd to project root
21
+ cd "$(dirname "$0")"/..
22
+
23
+ # Install dependencies
24
+ npm install
25
+
26
+ # Run tests
27
+ npm run test:workflows # Run tests related to all workflows
28
+ npm run test:projects # Run tests related to GCP projects
29
+ npm run test:services # Run tests related to services
30
+ npm run test:deploy # Run tests related to deployments
31
+ npm run test:gcp-auth # Run tests related to GCP authentication
package/CONTRIBUTING.md CHANGED
@@ -25,6 +25,12 @@ This project follows
25
25
 
26
26
  ## Contribution process
27
27
 
28
+ ### Start with an issue
29
+
30
+ Before sending a pull request, please open an issue describing the bug or feature
31
+ you would like to address. This will allow maintainers of this project to guide
32
+ you in your design and implementation.
33
+
28
34
  ### Code reviews
29
35
 
30
36
  All submissions, including submissions by project members, require review. We
@@ -68,7 +74,7 @@ To use remote MCP Server in a MCP client:
68
74
  Start the MCP server locally with:
69
75
 
70
76
  ```bash
71
- npm run start
77
+ GCP_STDIO=false node /path/to/this/repo/cloud-run-mcp/mcp-server.js
72
78
  ```
73
79
 
74
80
  Then, in your MCP client configuration, use the following:
@@ -78,7 +84,19 @@ Then, in your MCP client configuration, use the following:
78
84
  "mcpServers": {
79
85
  "cloud-run": {
80
86
  "command": "npx",
81
- "args": ["mcp-remote", "http://localhost:3000/sse"]
87
+ "args": ["mcp-remote", "http://localhost:3000/mcp"]
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ or, if your client supports the `url` attribute, you can use:
94
+
95
+ ```
96
+ {
97
+ "mcpServers": {
98
+ "cloud-run": {
99
+ "url": "http://localhost:3000/mcp"
82
100
  }
83
101
  }
84
102
  }
@@ -112,10 +130,13 @@ To update the [npm package]https://www.npmjs.com/package/@google-cloud/cloud-run
112
130
 
113
131
  Run the following:
114
132
 
115
- * `git checkout -b new-release`
116
- * `npm test`
117
- * `npm version minor`
118
- * `git push --follow-tags`
119
- * On GitHub, [create a new release](https://github.com/GoogleCloudPlatform/cloud-run-mcp/releases/new) for this tag.
133
+ - `git checkout -b new-release`
134
+ - `npm test`
135
+ - `npm version minor`
136
+ - `git push --set-upstream origin new-release --follow-tags`
137
+ - Create a [pull request for 'new-release' on GitHub](https://github.com/GoogleCloudPlatform/cloud-run-mcp/pull/new/new-release)
138
+ - Get approval
139
+ - Rebase and merge into main
140
+ - On GitHub, [create a new release](https://github.com/GoogleCloudPlatform/cloud-run-mcp/releases/new) for this tag.
120
141
 
121
- Then a [GitHub Action]https://github.com/GoogleCloudPlatform/cloud-run-mcp/blob/main/.github/workflows/npm-publish.yml) automatically publishes to npm when new releases are pushes.
142
+ Then a [GitHub Action](https://github.com/GoogleCloudPlatform/cloud-run-mcp/blob/main/.github/workflows/npm-publish.yml) automatically publishes to npm when new releases are pushes.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # MCP server to deploy code to Google Cloud Run
1
+ # Cloud Run MCP server and Gemini CLI extension
2
2
 
3
3
  Enable MCP-compatible AI agents to deploy apps to Cloud Run.
4
4
 
@@ -11,13 +11,17 @@ Enable MCP-compatible AI agents to deploy apps to Cloud Run.
11
11
  }
12
12
  ```
13
13
 
14
+ Deploy from Gemini CLI and other AI-powered CLI agents:
15
+
16
+ <img src="https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/refs/heads/main/.github/images/deploycli.gif" width="800">
17
+
14
18
  Deploy from AI-powered IDEs:
15
19
 
16
- <img src="https://github.com/user-attachments/assets/9fdcec30-2b38-4362-9eb1-54cab09e99d4" width="800">
20
+ <img src="https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/refs/heads/main/.github/images/deploy_from_ide.gif" width="800">
17
21
 
18
22
  Deploy from AI assistant apps:
19
23
 
20
- <img src="https://github.com/user-attachments/assets/b10f0335-b332-4640-af38-ea015b46b57c" width="800">
24
+ <img src="https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/refs/heads/main/.github/images/deploy_from_apps.gif" width="800">
21
25
 
22
26
  Deploy from agent SDKs, like the [Google Gen AI SDK](https://ai.google.dev/gemini-api/docs/function-calling?example=meeting#use_model_context_protocol_mcp) or [Agent Development Kit](https://google.github.io/adk-docs/tools/mcp-tools/).
23
27
 
@@ -30,7 +34,7 @@ Deploy from agent SDKs, like the [Google Gen AI SDK](https://ai.google.dev/gemin
30
34
  - `list-services`: Lists Cloud Run services in a given project and region.
31
35
  - `get-service`: Gets details for a specific Cloud Run service.
32
36
  - `get-service-log`: Gets Logs and Error Messages for a specific Cloud Run service.
33
- - `deploy-local-files`\*: Deploys files from the local file system to a Google Cloud Run service.
37
+
34
38
  - `deploy-local-folder`\*: Deploys a local folder to a Google Cloud Run service.
35
39
  - `list-projects`\*: Lists available GCP projects.
36
40
  - `create-project`\*: Creates a new GCP project and attach it to the first available billing account. A project ID can be optionally specified.
@@ -44,7 +48,58 @@ Prompts are natural language commands that can be used to perform common tasks.
44
48
  - `deploy`: Deploys the current working directory to Cloud Run. If a service name is not provided, it will use the `DEFAULT_SERVICE_NAME` environment variable, or the name of the current working directory.
45
49
  - `logs`: Gets the logs for a Cloud Run service. If a service name is not provided, it will use the `DEFAULT_SERVICE_NAME` environment variable, or the name of the current working directory.
46
50
 
47
- ## Use as local MCP server
51
+ ## Environment Variables
52
+
53
+ The Cloud Run MCP server can be configured using the following environment variables:
54
+
55
+ | Variable | Description |
56
+ | :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
57
+ | `GOOGLE_CLOUD_PROJECT` | The default project ID to use for Cloud Run services. |
58
+ | `GOOGLE_CLOUD_REGION` | The default region to use for Cloud Run services. |
59
+ | `DEFAULT_SERVICE_NAME` | The default service name to use for Cloud Run services. |
60
+ | `SKIP_IAM_CHECK` | Controls whether to check for IAM permissions for a Cloud Run service. Set to `false` to enable checks. This is `true` by default which is a recommended way to make the service public. |
61
+ | `ENABLE_HOST_VALIDATION` | Prevents [DNS Rebinding](https://en.wikipedia.org/wiki/DNS_rebinding) attacks by validating the Host header. This is disabled by default. |
62
+ | `ALLOWED_HOSTS` | Comma-separated list of allowed Host headers (if host validation is enabled). The default value is `localhost,127.0.0.1,::1`. |
63
+
64
+ ## Use as a Gemini CLI extension
65
+
66
+ To install this as a [Gemini CLI](https://github.com/google-gemini/gemini-cli) extension, run the following command:
67
+
68
+ 2. Install the extension:
69
+
70
+ ```bash
71
+ gemini extensions install https://github.com/GoogleCloudPlatform/cloud-run-mcp
72
+ ```
73
+
74
+ 3. Log in to your Google Cloud account using the command:
75
+
76
+ ```bash
77
+ gcloud auth login
78
+ ```
79
+
80
+ 4. Set up application credentials using the command:
81
+ ```bash
82
+ gcloud auth application-default login
83
+ ```
84
+
85
+ ## Use in MCP Clients
86
+
87
+ ### Learn how to configure your MCP client
88
+
89
+ Most MCP clients require a configuration file to be created or modified to add the MCP server.
90
+
91
+ The configuration file syntax can be different across clients. Please refer to the following links for the latest expected syntax:
92
+
93
+ - [**Antigravity**](https://antigravity.google/docs/mcp)
94
+ - [**Windsurf**](https://docs.windsurf.com/windsurf/mcp)
95
+ - [**VSCode**](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
96
+ - [**Claude Desktop**](https://modelcontextprotocol.io/quickstart/user)
97
+ - [**Cursor**](https://docs.cursor.com/context/model-context-protocol)
98
+
99
+ Once you have identified how to configure your MCP client, select one of these two options to set up the MCP server.
100
+ We recommend setting up as a local MCP server using Node.js.
101
+
102
+ ### Set up as local MCP server
48
103
 
49
104
  Run the Cloud Run MCP server on your local machine using local Google Cloud credentials. This is best if you are using an AI-assisted IDE (e.g. Cursor) or a desktop AI application (e.g. Claude).
50
105
 
@@ -63,7 +118,7 @@ Run the Cloud Run MCP server on your local machine using local Google Cloud cred
63
118
 
64
119
  Then configure the MCP server using either Node.js or Docker:
65
120
 
66
- ### Using Node.js
121
+ #### Using Node.js
67
122
 
68
123
  0. Install [Node.js](https://nodejs.org/en/download/) (LTS version recommended).
69
124
 
@@ -90,7 +145,7 @@ Then configure the MCP server using either Node.js or Docker:
90
145
  }
91
146
  ```
92
147
 
93
- ### Using Docker
148
+ #### Using Docker
94
149
 
95
150
  See Docker's [MCP catalog](https://hub.docker.com/mcp/server/cloud-run-mcp/overview), or use these manual instructions:
96
151
 
@@ -118,18 +173,7 @@ See Docker's [MCP catalog](https://hub.docker.com/mcp/server/cloud-run-mcp/overv
118
173
  }
119
174
  ```
120
175
 
121
- ## Use as a Gemini CLI extension
122
-
123
- To install this as a [Gemini CLI](https://github.com/google-gemini/gemini-cli) extension, run the following command:
124
-
125
- ```bash
126
- mkdir -p ~/.gemini/extensions/cloud-run/gemini-extension && \
127
- curl -s -L https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/main/gemini-extension.json > ~/.gemini/extensions/cloud-run/gemini-extension.json && \
128
- curl -s -L https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-run-mcp/main/gemini-extension/Gemini.md > ~/.gemini/extensions/cloud-run/gemini-extension/Gemini.md
129
- ```
130
-
131
- ## Use as remote MCP server
132
-
176
+ ### Set up as remote MCP server
133
177
 
134
178
  > [!WARNING]
135
179
  > Do not use the remote MCP server without authentication. In the following instructions, we will use IAM authentication to secure the connection to the MCP server from your local machine. This is important to prevent unauthorized access to your Google Cloud resources.
@@ -190,3 +234,5 @@ With this option, you will only be able to deploy code to the same Google Cloud
190
234
  "args": ["-y", "mcp-remote", "http://localhost:3000/sse"]
191
235
  }
192
236
  ```
237
+
238
+ The Google Cloud Platform Terms of Service (available at https://cloud.google.com/terms/) and the Data Processing and Security Terms (available at https://cloud.google.com/terms/data-processing-terms) do not apply to any component of the Cloud Run MCP Server software.
package/REVIEWING.md ADDED
@@ -0,0 +1,20 @@
1
+ # Reviewing Pull Requests
2
+
3
+ This document provides guidelines for reviewing Pull Requests.
4
+
5
+ ## Guidelines
6
+
7
+ ### Presubmit Tests
8
+
9
+ Running presubmit tests is a mandatory requirement for Pull Requests to be eligible for submission.
10
+
11
+ **Before triggering tests:**
12
+ Review the code changes, especially new or modified tests, to ensure they do not contain any malicious or harmful code that could unnecessarily consume or harm Google's resources during test execution. In particular, ensure the tests:
13
+
14
+ - **Do not modify environment variables:** The tests should not modify environment variables in an unexpected or harmful way.
15
+ - **Do not consume excessive resources:** Ensure tests do not create an excessive number of Google Cloud projects or other high-cost resources.
16
+ - **Do not contain hardcoded credentials:** Credentials should not be present in the code.
17
+ - **Do not rely on untrusted external dependencies:** Any new external dependencies should be reviewed for trustworthiness.
18
+
19
+ **Triggering tests:**
20
+ If the code is safe to run, trigger presubmit tests by adding a comment with `kokoro:run` to the Pull Request. Tests are run via Kokoro.
@@ -3,7 +3,7 @@
3
3
  ## Code that can be deployed
4
4
 
5
5
  Only web servers can be deployed using this MCP server.
6
- The code needs to listen for HTTP reqeusts on the port defined by the $PORT environment variable or 8080.
6
+ The code needs to listen for HTTP requests on the port defined by the $PORT environment variable or 8080.
7
7
 
8
8
  ### Supported languages
9
9
 
@@ -47,11 +47,11 @@ server {
47
47
  The user must have an existing Google Cloud account with billing set up, and ideally an existing Google Cloud project.
48
48
 
49
49
  If deployment fails because of an access or IAM error, it is likely that the user doesn't have Google Cloud credentials on the local machine.
50
- The user mush follow these steps:
50
+ The user must follow these steps:
51
51
 
52
52
  1. Install the [Google Cloud SDK](https://cloud.google.com/sdk/docs/install) and authenticate with their Google account.
53
53
 
54
54
  2. Set up application credentials using the command:
55
55
  ```bash
56
56
  gcloud auth application-default login
57
- ```
57
+ ```
@@ -0,0 +1,200 @@
1
+ /*
2
+ Copyright 2025 Google LLC
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ https://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import { callWithRetry } from './helpers.js';
18
+ import { logAndProgress } from '../util/helpers.js';
19
+
20
+ const DELAY_WAIT_FOR_BUILD_LOGS = 10000; // 10 seconds delay to allow logs to propagate
21
+ const BUILD_LOGS_LINES_TO_FETCH = 100; // Number of log lines to fetch for build logs snippet
22
+
23
+ /**
24
+ * Triggers a Google Cloud Build job to build a container image from source code in a GCS bucket.
25
+ * It uses either a Dockerfile found in the source or Google Cloud Buildpacks if no Dockerfile is present.
26
+ * Waits for the build to complete and returns the build result.
27
+ *
28
+ * @async
29
+ * @param {object} context - The context object containing clients and other parameters.
30
+ * @param {string} projectId - The Google Cloud project ID.
31
+ * @param {string} location - The Google Cloud region for the build.
32
+ * @param {string} sourceBucketName - The GCS bucket name where the source code (zip) is stored.
33
+ * @param {string} sourceBlobName - The GCS blob name (the zip file) for the source code.
34
+ * @param {string} targetRepoName - The name of the target Artifact Registry repository (used for context, not directly in build steps).
35
+ * @param {string} targetImageUrl - The full Artifact Registry URL for the image to be built (e.g., `location-docker.pkg.dev/project/repo/image:tag`).
36
+ * @param {boolean} hasDockerfile - Indicates whether a Dockerfile is present in the source to guide the build process.
37
+ * @param {function(object): void} [progressCallback] - Optional callback for progress updates.
38
+ * @returns {Promise<object>} A promise that resolves with the completed Cloud Build object.
39
+ * @throws {Error} If the Cloud Build job fails, times out, or encounters an error during initiation or execution.
40
+ */
41
+ export async function triggerCloudBuild(
42
+ context,
43
+ projectId,
44
+ location,
45
+ sourceBucketName,
46
+ sourceBlobName,
47
+ targetRepoName,
48
+ targetImageUrl,
49
+ hasDockerfile,
50
+ progressCallback
51
+ ) {
52
+ let buildSteps;
53
+
54
+ if (hasDockerfile) {
55
+ buildSteps = [
56
+ {
57
+ name: 'gcr.io/cloud-builders/docker',
58
+ args: ['build', '-t', targetImageUrl, '.'],
59
+ dir: '/workspace',
60
+ },
61
+ ];
62
+ } else {
63
+ buildSteps = [
64
+ {
65
+ name: 'gcr.io/k8s-skaffold/pack',
66
+ entrypoint: 'pack',
67
+ args: [
68
+ 'build',
69
+ targetImageUrl,
70
+ '--builder',
71
+ 'gcr.io/buildpacks/builder:latest',
72
+ ],
73
+ dir: '/workspace',
74
+ },
75
+ ];
76
+ }
77
+
78
+ const build = {
79
+ source: {
80
+ storageSource: {
81
+ bucket: sourceBucketName,
82
+ object: sourceBlobName,
83
+ },
84
+ },
85
+ steps: buildSteps,
86
+ images: [targetImageUrl],
87
+ };
88
+
89
+ await logAndProgress(
90
+ `Initiating Cloud Build for gs://${sourceBucketName}/${sourceBlobName} in ${location}...`,
91
+ progressCallback
92
+ );
93
+ const [operation] = await callWithRetry(
94
+ () =>
95
+ context.cloudBuildClient.createBuild({
96
+ projectId: projectId,
97
+ build: build,
98
+ }),
99
+ 'cloudBuild.createBuild'
100
+ );
101
+
102
+ await logAndProgress(`Cloud Build job started...`, progressCallback);
103
+ const buildId = operation.metadata.build.id;
104
+ let completedBuild;
105
+ while (true) {
106
+ const [getBuildOperation] = await callWithRetry(
107
+ () =>
108
+ context.cloudBuildClient.getBuild({
109
+ projectId: projectId,
110
+ id: buildId,
111
+ }),
112
+ `cloudBuild.getBuild ${buildId}`
113
+ );
114
+ if (
115
+ ['SUCCESS', 'FAILURE', 'INTERNAL_ERROR', 'TIMEOUT', 'CANCELLED'].includes(
116
+ getBuildOperation.status
117
+ )
118
+ ) {
119
+ completedBuild = getBuildOperation;
120
+ break;
121
+ }
122
+ await logAndProgress(
123
+ `Build status: ${getBuildOperation.status}. Waiting...`,
124
+ progressCallback,
125
+ 'debug'
126
+ );
127
+ await new Promise((resolve) => setTimeout(resolve, 5000));
128
+ }
129
+
130
+ if (completedBuild.status === 'SUCCESS') {
131
+ await logAndProgress(
132
+ `Cloud Build job ${buildId} completed successfully.`,
133
+ progressCallback
134
+ );
135
+ await logAndProgress(
136
+ `Image built: ${completedBuild.results.images[0].name}`,
137
+ progressCallback
138
+ );
139
+ return completedBuild;
140
+ } else {
141
+ const failureMessage = `Cloud Build job ${buildId} failed with status: ${completedBuild.status}`;
142
+ await logAndProgress(failureMessage, progressCallback, 'error');
143
+ const logsMessage = `Build logs: ${completedBuild.logUrl}`;
144
+ await logAndProgress(logsMessage, progressCallback); // Log URL is info, failure is error
145
+
146
+ let buildLogsSnippet = `\n\nRefer to Log URL for full details: ${completedBuild.logUrl}`; // Default snippet
147
+ try {
148
+ const logFilter = `resource.type="build" AND resource.labels.build_id="${buildId}"`;
149
+ await logAndProgress(
150
+ `Attempting to fetch last ${BUILD_LOGS_LINES_TO_FETCH} log lines for build ${buildId}...`,
151
+ progressCallback,
152
+ 'debug'
153
+ );
154
+
155
+ // Wait for a short period to allow logs to propagate
156
+ await new Promise((resolve) =>
157
+ setTimeout(resolve, DELAY_WAIT_FOR_BUILD_LOGS)
158
+ );
159
+
160
+ // Fetch the most recent N log entries
161
+ const [entries] = await callWithRetry(
162
+ () =>
163
+ context.loggingClient.getEntries({
164
+ filter: logFilter,
165
+ orderBy: 'timestamp desc', // Get latest logs first
166
+ pageSize: BUILD_LOGS_LINES_TO_FETCH,
167
+ }),
168
+ `logging.getEntries for build ${buildId}`
169
+ );
170
+
171
+ if (entries && entries.length > 0) {
172
+ // Entries are newest first, reverse for chronological order of the snippet
173
+ const logLines = entries.reverse().map((entry) => entry.data || '');
174
+ if (logLines.length > 0) {
175
+ buildLogsSnippet = `\n\nLast ${logLines.length} log lines from build ${buildId}:\n${logLines.join('\n')}`;
176
+ await logAndProgress(
177
+ `Successfully fetched snippet of build logs for ${buildId}.`,
178
+ progressCallback,
179
+ 'info'
180
+ );
181
+ }
182
+ } else {
183
+ await logAndProgress(
184
+ `No specific log entries retrieved for build ${buildId}. ${buildLogsSnippet}`,
185
+ progressCallback,
186
+ 'warn'
187
+ );
188
+ }
189
+ } catch (logError) {
190
+ console.error(`Error fetching build logs for ${buildId}:`, logError);
191
+ await logAndProgress(
192
+ `Failed to fetch build logs snippet: ${logError.message}. ${buildLogsSnippet}`,
193
+ progressCallback,
194
+ 'warn'
195
+ );
196
+ // buildLogsSnippet already contains the Log URL as a fallback
197
+ }
198
+ throw new Error(`Build ${buildId} failed.${buildLogsSnippet}`);
199
+ }
200
+ }
@@ -90,6 +90,7 @@ async function checkAndEnableApi(
90
90
  * Throws an error if an API cannot be enabled.
91
91
  *
92
92
  * @async
93
+ * @param {object} context - The context object containing clients and other parameters.
93
94
  * @param {string} projectId - The Google Cloud project ID.
94
95
  * @param {string[]} apis - An array of API identifiers to check and enable (e.g., 'run.googleapis.com').
95
96
  * @param {function(string, string=): void} progressCallback - A function to call with progress updates.
@@ -97,19 +98,21 @@ async function checkAndEnableApi(
97
98
  * @throws {Error} If an API fails to enable or if there's an issue checking its status.
98
99
  * @returns {Promise<void>} A promise that resolves when all specified APIs are enabled.
99
100
  */
100
- export async function ensureApisEnabled(projectId, apis, progressCallback) {
101
- const { ServiceUsageClient } = await import('@google-cloud/service-usage');
102
- const serviceUsageClient = new ServiceUsageClient({ projectId });
101
+ export async function ensureApisEnabled(
102
+ context,
103
+ projectId,
104
+ apis,
105
+ progressCallback
106
+ ) {
103
107
  const message = 'Checking and enabling required APIs...';
104
108
  console.log(message);
105
109
  if (progressCallback) progressCallback({ level: 'info', data: message });
106
110
 
107
-
108
111
  for (const api of apis) {
109
112
  const serviceName = `projects/${projectId}/services/${api}`;
110
113
  try {
111
114
  await checkAndEnableApi(
112
- serviceUsageClient,
115
+ context.serviceUsageClient,
113
116
  serviceName,
114
117
  api,
115
118
  progressCallback
@@ -123,7 +126,7 @@ export async function ensureApisEnabled(projectId, apis, progressCallback) {
123
126
  await new Promise((resolve) => setTimeout(resolve, 1000));
124
127
  try {
125
128
  await checkAndEnableApi(
126
- serviceUsageClient,
129
+ context.serviceUsageClient,
127
130
  serviceName,
128
131
  api,
129
132
  progressCallback
@@ -132,7 +135,8 @@ export async function ensureApisEnabled(projectId, apis, progressCallback) {
132
135
  // If the retry also fails, throw an error.
133
136
  const errorMessage = `Failed to ensure API [${api}] is enabled after retry. Please check manually.`;
134
137
  console.error(errorMessage, retryError);
135
- if (progressCallback) progressCallback({ level: 'error', data: errorMessage });
138
+ if (progressCallback)
139
+ progressCallback({ level: 'error', data: errorMessage });
136
140
  throw new Error(errorMessage);
137
141
  }
138
142
  }
@@ -140,4 +144,4 @@ export async function ensureApisEnabled(projectId, apis, progressCallback) {
140
144
  const successMsg = 'All required APIs are enabled.';
141
145
  console.log(successMsg);
142
146
  if (progressCallback) progressCallback({ level: 'info', data: successMsg });
143
- }
147
+ }