@google-cloud/cloud-run-mcp 1.0.0 → 1.2.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.
- package/.github/workflows/local-tests.yml +17 -0
- package/.github/workflows/npm-publish.yml +23 -0
- package/CONTRIBUTING.md +12 -0
- package/README.md +5 -4
- package/gemini-extension/Gemini.md +57 -0
- package/gemini-extension.json +2 -1
- package/lib/cloud-run-deploy.js +96 -40
- package/lib/gcp-auth-check.js +4 -4
- package/mcp-server.js +5 -2
- package/package.json +9 -9
- package/test/{test-prompts.js → local/prompts.test.js} +1 -1
- package/test/{test-tools.js → local/tools.test.js} +62 -31
- package/test/{test-deploy.js → need-gcp/cloud-run-deploy.test.js} +1 -1
- package/test/{test-service-logs.js → need-gcp/cloud-run-services.test.js} +1 -1
- package/test/{test-gcp-auth.js → need-gcp/gcp-auth-check.test.js} +17 -106
- package/test/{test-create-project.js → need-gcp/gcp-projects.test.js} +1 -1
- package/tools.js +215 -182
- package/test/run-all-tests.js +0 -19
- /package/test/{test-mcp-server.js → local/mcp-server.test.js} +0 -0
|
@@ -9,7 +9,7 @@ You may obtain a copy of the License at
|
|
|
9
9
|
|
|
10
10
|
Unless required by applicable law or agreed to in writing, software
|
|
11
11
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
WITHOUT WARRANTIES, OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
@@ -17,18 +17,16 @@ limitations under the License.
|
|
|
17
17
|
import assert from 'node:assert/strict';
|
|
18
18
|
import { describe, it, mock, beforeEach, afterEach } from 'node:test';
|
|
19
19
|
import { GoogleAuth } from 'google-auth-library';
|
|
20
|
-
import { ensureGCPCredentials } from '
|
|
20
|
+
import { ensureGCPCredentials } from '../../lib/gcp-auth-check.js';
|
|
21
21
|
|
|
22
22
|
describe('ensureGCPCredentials', () => {
|
|
23
23
|
let originalConsoleLog;
|
|
24
24
|
let originalConsoleError;
|
|
25
|
-
let originalProcessExit;
|
|
26
25
|
|
|
27
26
|
let capturedConsoleOutput;
|
|
28
27
|
|
|
29
28
|
let consoleLogMockFn;
|
|
30
29
|
let consoleErrorMockFn;
|
|
31
|
-
let processExitMockFn;
|
|
32
30
|
|
|
33
31
|
let getClientMock;
|
|
34
32
|
let getAccessTokenMock;
|
|
@@ -37,7 +35,6 @@ describe('ensureGCPCredentials', () => {
|
|
|
37
35
|
// Store original methods
|
|
38
36
|
originalConsoleLog = console.log;
|
|
39
37
|
originalConsoleError = console.error;
|
|
40
|
-
originalProcessExit = process.exit;
|
|
41
38
|
|
|
42
39
|
capturedConsoleOutput = []; // Reset for each test
|
|
43
40
|
|
|
@@ -48,14 +45,10 @@ describe('ensureGCPCredentials', () => {
|
|
|
48
45
|
consoleErrorMockFn = mock.fn((...args) => {
|
|
49
46
|
capturedConsoleOutput.push(args.join(' '));
|
|
50
47
|
});
|
|
51
|
-
processExitMockFn = mock.fn((code) => {
|
|
52
|
-
throw new Error(`Mocked process.exit called with code ${code}`);
|
|
53
|
-
});
|
|
54
48
|
|
|
55
49
|
// Overwrite the global console and process methods
|
|
56
50
|
console.log = consoleLogMockFn;
|
|
57
51
|
console.error = consoleErrorMockFn;
|
|
58
|
-
process.exit = processExitMockFn;
|
|
59
52
|
|
|
60
53
|
// Mock GoogleAuth.prototype.getClient and AuthClient.prototype.getAccessToken.
|
|
61
54
|
const mockClient = {
|
|
@@ -73,18 +66,14 @@ describe('ensureGCPCredentials', () => {
|
|
|
73
66
|
// Restore original methods
|
|
74
67
|
console.log = originalConsoleLog;
|
|
75
68
|
console.error = originalConsoleError;
|
|
76
|
-
process.exit = originalProcessExit;
|
|
77
69
|
|
|
78
70
|
// Restore other mocks created with `mock.method`
|
|
79
71
|
mock.restoreAll();
|
|
80
72
|
});
|
|
81
73
|
|
|
82
|
-
it('should
|
|
83
|
-
await
|
|
84
|
-
|
|
85
|
-
}, 'ensureGCPCredentials should resolve on success');
|
|
86
|
-
|
|
87
|
-
await Promise.resolve();
|
|
74
|
+
it('should return true when ADC are found', async () => {
|
|
75
|
+
const result = await ensureGCPCredentials();
|
|
76
|
+
assert.strictEqual(result, true, 'Should return true on success');
|
|
88
77
|
|
|
89
78
|
assert.deepStrictEqual(
|
|
90
79
|
capturedConsoleOutput,
|
|
@@ -95,11 +84,6 @@ describe('ensureGCPCredentials', () => {
|
|
|
95
84
|
'Console output should indicate successful ADC discovery'
|
|
96
85
|
);
|
|
97
86
|
|
|
98
|
-
assert.strictEqual(
|
|
99
|
-
processExitMockFn.mock.callCount(),
|
|
100
|
-
0,
|
|
101
|
-
'process.exit should not be called on success'
|
|
102
|
-
);
|
|
103
87
|
assert.strictEqual(
|
|
104
88
|
consoleErrorMockFn.mock.callCount(),
|
|
105
89
|
1,
|
|
@@ -123,23 +107,15 @@ describe('ensureGCPCredentials', () => {
|
|
|
123
107
|
);
|
|
124
108
|
});
|
|
125
109
|
|
|
126
|
-
it('should
|
|
110
|
+
it('should return false and log error when ADC are not found (generic error)', async () => {
|
|
127
111
|
const errorMessage = 'Failed to find credentials.';
|
|
128
112
|
const errorWithStack = new Error(errorMessage);
|
|
129
113
|
getClientMock.mock.mockImplementation(async () => {
|
|
130
114
|
throw errorWithStack;
|
|
131
115
|
});
|
|
132
116
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
} catch (err) {
|
|
136
|
-
assert.ok(
|
|
137
|
-
err.message.includes('Mocked process.exit called with code 1'),
|
|
138
|
-
'Error message from mocked process.exit should be caught'
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
// Add `await Promise.resolve()` here too for consistency, if needed
|
|
142
|
-
await Promise.resolve();
|
|
117
|
+
const result = await ensureGCPCredentials();
|
|
118
|
+
assert.strictEqual(result, false, 'Should return false on failure');
|
|
143
119
|
|
|
144
120
|
const expectedOutput = [
|
|
145
121
|
'Checking for Google Cloud Application Default Credentials...',
|
|
@@ -157,20 +133,9 @@ describe('ensureGCPCredentials', () => {
|
|
|
157
133
|
expectedOutput,
|
|
158
134
|
'Console output should match generic error messages'
|
|
159
135
|
);
|
|
160
|
-
|
|
161
|
-
assert.strictEqual(
|
|
162
|
-
processExitMockFn.mock.callCount(),
|
|
163
|
-
1,
|
|
164
|
-
'process.exit should be called once'
|
|
165
|
-
);
|
|
166
|
-
assert.strictEqual(
|
|
167
|
-
processExitMockFn.mock.calls[0].arguments[0],
|
|
168
|
-
1,
|
|
169
|
-
'process.exit should be called with code 1'
|
|
170
|
-
);
|
|
171
136
|
});
|
|
172
137
|
|
|
173
|
-
it('should log HTTP error
|
|
138
|
+
it('should return false and log HTTP error when google-auth-library throws an HTTP error', async () => {
|
|
174
139
|
const httpErrorMessage = 'Request failed with status code 401';
|
|
175
140
|
const httpError = new Error(httpErrorMessage);
|
|
176
141
|
httpError.response = { status: 401 };
|
|
@@ -180,15 +145,8 @@ describe('ensureGCPCredentials', () => {
|
|
|
180
145
|
throw httpError;
|
|
181
146
|
});
|
|
182
147
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
} catch (err) {
|
|
186
|
-
assert.ok(
|
|
187
|
-
err.message.includes('Mocked process.exit called with code 1'),
|
|
188
|
-
'Error message from mocked process.exit should be caught'
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
await Promise.resolve();
|
|
148
|
+
const result = await ensureGCPCredentials();
|
|
149
|
+
assert.strictEqual(result, false, 'Should return false on failure');
|
|
192
150
|
|
|
193
151
|
const expectedOutput = [
|
|
194
152
|
'Checking for Google Cloud Application Default Credentials...',
|
|
@@ -206,20 +164,9 @@ describe('ensureGCPCredentials', () => {
|
|
|
206
164
|
expectedOutput,
|
|
207
165
|
'Console output should match HTTP error messages'
|
|
208
166
|
);
|
|
209
|
-
|
|
210
|
-
assert.strictEqual(
|
|
211
|
-
processExitMockFn.mock.callCount(),
|
|
212
|
-
1,
|
|
213
|
-
'process.exit should be called once'
|
|
214
|
-
);
|
|
215
|
-
assert.strictEqual(
|
|
216
|
-
processExitMockFn.mock.calls[0].arguments[0],
|
|
217
|
-
1,
|
|
218
|
-
'process.exit should be called with code 1'
|
|
219
|
-
);
|
|
220
167
|
});
|
|
221
168
|
|
|
222
|
-
it('should
|
|
169
|
+
it('should return false and log TypeError when google-auth-library throws a TypeError', async () => {
|
|
223
170
|
const typeErrorMessage = 'Unexpected token in JSON at position 0';
|
|
224
171
|
const typeError = new TypeError(typeErrorMessage);
|
|
225
172
|
const errorWithStack = typeError;
|
|
@@ -228,15 +175,8 @@ describe('ensureGCPCredentials', () => {
|
|
|
228
175
|
throw typeError;
|
|
229
176
|
});
|
|
230
177
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
} catch (err) {
|
|
234
|
-
assert.ok(
|
|
235
|
-
err.message.includes('Mocked process.exit called with code 1'),
|
|
236
|
-
'Error message from mocked process.exit should be caught'
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
await Promise.resolve();
|
|
178
|
+
const result = await ensureGCPCredentials();
|
|
179
|
+
assert.strictEqual(result, false, 'Should return false on failure');
|
|
240
180
|
|
|
241
181
|
const expectedOutput = [
|
|
242
182
|
'Checking for Google Cloud Application Default Credentials...',
|
|
@@ -254,20 +194,9 @@ describe('ensureGCPCredentials', () => {
|
|
|
254
194
|
expectedOutput,
|
|
255
195
|
'Console output should match TypeError messages'
|
|
256
196
|
);
|
|
257
|
-
|
|
258
|
-
assert.strictEqual(
|
|
259
|
-
processExitMockFn.mock.callCount(),
|
|
260
|
-
1,
|
|
261
|
-
'process.exit should be called once'
|
|
262
|
-
);
|
|
263
|
-
assert.strictEqual(
|
|
264
|
-
processExitMockFn.mock.calls[0].arguments[0],
|
|
265
|
-
1,
|
|
266
|
-
'process.exit should be called with code 1'
|
|
267
|
-
);
|
|
268
197
|
});
|
|
269
198
|
|
|
270
|
-
it('should log general unexpected error
|
|
199
|
+
it('should return false and log general unexpected error for other errors', async () => {
|
|
271
200
|
const unknownErrorMessage = 'Something unexpected happened.';
|
|
272
201
|
const unknownError = new Error(unknownErrorMessage);
|
|
273
202
|
const errorWithStack = unknownError;
|
|
@@ -276,15 +205,8 @@ describe('ensureGCPCredentials', () => {
|
|
|
276
205
|
throw unknownError;
|
|
277
206
|
});
|
|
278
207
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
} catch (err) {
|
|
282
|
-
assert.ok(
|
|
283
|
-
err.message.includes('Mocked process.exit called with code 1'),
|
|
284
|
-
'Error message from mocked process.exit should be caught'
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
await Promise.resolve();
|
|
208
|
+
const result = await ensureGCPCredentials();
|
|
209
|
+
assert.strictEqual(result, false, 'Should return false on failure');
|
|
288
210
|
|
|
289
211
|
const expectedOutput = [
|
|
290
212
|
'Checking for Google Cloud Application Default Credentials...',
|
|
@@ -302,16 +224,5 @@ describe('ensureGCPCredentials', () => {
|
|
|
302
224
|
expectedOutput,
|
|
303
225
|
'Console output should match general error messages'
|
|
304
226
|
);
|
|
305
|
-
|
|
306
|
-
assert.strictEqual(
|
|
307
|
-
processExitMockFn.mock.callCount(),
|
|
308
|
-
1,
|
|
309
|
-
'process.exit should be called once'
|
|
310
|
-
);
|
|
311
|
-
assert.strictEqual(
|
|
312
|
-
processExitMockFn.mock.calls[0].arguments[0],
|
|
313
|
-
1,
|
|
314
|
-
'process.exit should be called with code 1'
|
|
315
|
-
);
|
|
316
227
|
});
|
|
317
228
|
});
|
|
@@ -16,7 +16,7 @@ limitations under the License.
|
|
|
16
16
|
|
|
17
17
|
import readline from 'readline/promises';
|
|
18
18
|
import { stdin as input, stdout as output } from 'process';
|
|
19
|
-
import { createProjectAndAttachBilling } from '
|
|
19
|
+
import { createProjectAndAttachBilling } from '../../lib/gcp-projects.js';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Prompts the user for an optional project ID or allows them to proceed with auto-generation.
|