Skip to content

Commit 938f2f6

Browse files
authored
feat: switch to using actions-utils (#243)
1 parent a7536cd commit 938f2f6

File tree

9 files changed

+250
-1040
lines changed

9 files changed

+250
-1040
lines changed

dist/index.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 136 additions & 146 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,27 @@
3232
"license": "Apache-2.0",
3333
"dependencies": {
3434
"@actions/core": "^1.6.0",
35+
"@google-github-actions/actions-utils": "^0.1.0",
3536
"archiver": "^5.3.0",
36-
"google-auth-library": "^7.10.3",
37-
"ignore": "^5.1.9",
38-
"yaml": "^1.10.2"
37+
"google-auth-library": "^7.11.0",
38+
"ignore": "^5.2.0"
3939
},
4040
"devDependencies": {
4141
"@types/archiver": "^5.1.1",
4242
"@types/chai": "^4.3.0",
43-
"@types/lodash": "^4.14.177",
4443
"@types/mocha": "^9.0.0",
45-
"@types/node": "^16.11.12",
46-
"@types/uuid": "^8.3.3",
47-
"@typescript-eslint/eslint-plugin": "^5.6.0",
48-
"@typescript-eslint/parser": "^5.6.0",
49-
"@vercel/ncc": "^0.33.0",
44+
"@types/node": "^17.0.2",
45+
"@typescript-eslint/eslint-plugin": "^5.8.0",
46+
"@typescript-eslint/parser": "^5.8.0",
47+
"@vercel/ncc": "^0.33.1",
5048
"chai": "^4.3.4",
5149
"eslint-config-prettier": "^8.3.0",
5250
"eslint-plugin-prettier": "^4.0.0",
53-
"eslint": "^8.4.1",
51+
"eslint": "^8.5.0",
5452
"mocha": "^9.1.3",
5553
"node-stream-zip": "^1.15.0",
5654
"prettier": "^2.5.1",
5755
"ts-node": "^10.4.0",
58-
"typescript": "^4.5.2"
56+
"typescript": "^4.5.4"
5957
}
6058
}

src/client.ts

Lines changed: 44 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,32 @@
1414
* limitations under the License.
1515
*/
1616

17-
import https, { RequestOptions } from 'https';
18-
import { URL } from 'url';
17+
import { RequestOptions } from 'https';
1918
import { randomBytes } from 'crypto';
2019
import fs from 'fs';
2120
import * as path from 'path';
2221
import { tmpdir } from 'os';
23-
import { errorMessage, removeFile, zipDir } from './util';
22+
2423
import {
2524
CredentialBody,
2625
ExternalAccountClientOptions,
2726
GoogleAuth,
2827
} from 'google-auth-library';
28+
import {
29+
errorMessage,
30+
request,
31+
removeFile,
32+
} from '@google-github-actions/actions-utils';
33+
34+
import { zipDir } from './util';
2935

3036
// Do not listen to the linter - this can NOT be rewritten as an ES6 import statement.
3137
// eslint-disable-next-line @typescript-eslint/no-var-requires
3238
const { version: appVersion } = require('../package.json');
3339

40+
// userAgent is the default user agent.
41+
const userAgent = `google-github-actions:deploy-cloud-functions/${appVersion}`;
42+
3443
// defaultBaseURL is the URL for Cloud Functions.
3544
const defaultBaseURL = 'https://cloudfunctions.googleapis.com/v1';
3645

@@ -182,57 +191,20 @@ export class CloudFunctionsClient {
182191
* request is a high-level helper that returns a promise from the executed
183192
* request.
184193
*/
185-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
186-
static request(opts: RequestOptions, data?: any): Promise<string> {
187-
if (!opts.headers) {
188-
opts.headers = {};
189-
}
190-
191-
if (!opts.headers['User-Agent']) {
192-
opts.headers[
193-
'User-Agent'
194-
] = `google-github-actions:deploy-cloud-functions/${appVersion}`;
195-
}
196-
197-
return new Promise((resolve, reject) => {
198-
const req = https.request(opts, (res) => {
199-
res.setEncoding('utf8');
200-
201-
let body = '';
202-
res.on('data', (data) => {
203-
body += data;
204-
});
205-
206-
res.on('end', () => {
207-
if (res.statusCode && res.statusCode >= 400) {
208-
reject(body);
209-
} else {
210-
resolve(body);
211-
}
212-
});
213-
});
214-
215-
req.on('error', (err) => {
216-
reject(err);
217-
});
218-
219-
if (data == null) {
220-
req.end();
221-
return;
222-
}
223-
224-
if (
225-
typeof data === 'string' ||
226-
data instanceof String ||
227-
data instanceof Buffer
228-
) {
229-
req.write(data);
230-
req.end();
231-
return;
232-
}
233-
234-
data.pipe(req);
235-
});
194+
static async request(
195+
method: string,
196+
url: string,
197+
data?: any, // eslint-disable-line @typescript-eslint/no-explicit-any
198+
opts?: RequestOptions,
199+
): Promise<string> {
200+
opts ||= {};
201+
opts.headers = Object.assign(
202+
{
203+
'User-Agent': userAgent,
204+
},
205+
opts.headers,
206+
);
207+
return await request(method, url, data, opts);
236208
}
237209

238210
/**
@@ -272,23 +244,15 @@ export class CloudFunctionsClient {
272244
async #request(
273245
method: string,
274246
url: string,
275-
opts?: RequestOptions,
276247
data?: any, // eslint-disable-line @typescript-eslint/no-explicit-any
248+
opts?: RequestOptions,
277249
) {
278-
const u = new URL(url);
279-
opts = Object.assign(opts || {}, {
280-
hostname: u.hostname,
281-
port: u.port,
282-
path: u.pathname + u.search,
283-
method: method,
284-
headers: {},
285-
});
286-
287250
const authToken = await this.#auth.getAccessToken();
288251
if (!authToken) {
289252
throw new Error(`Failed to get auth token for ${method} ${url}`);
290253
}
291254

255+
opts ||= {};
292256
opts.headers = Object.assign(
293257
{
294258
'Authorization': `Bearer ${authToken}`,
@@ -299,10 +263,11 @@ export class CloudFunctionsClient {
299263
);
300264

301265
try {
302-
const resp = await CloudFunctionsClient.request(opts, data);
266+
const resp = await request(method, url, data, opts);
303267
return JSON.parse(resp);
304268
} catch (err) {
305-
throw new Error(`Failed to ${method} ${url}: ${errorMessage(err)}`);
269+
const msg = errorMessage(err);
270+
throw new Error(`Failed to ${method} ${url}: ${msg}`);
306271
}
307272
}
308273

@@ -368,7 +333,7 @@ export class CloudFunctionsClient {
368333
const parent = this.parentFromName(resourceName);
369334
const u = `${this.#baseURL}/${parent}/functions`;
370335
const body = JSON.stringify(cf);
371-
const resp: Operation = await this.#request('POST', u, {}, body);
336+
const resp: Operation = await this.#request('POST', u, body);
372337
const op = await this.#pollOperation(resp.name, {
373338
interval: 5,
374339
retries: timeout / 5,
@@ -460,7 +425,7 @@ export class CloudFunctionsClient {
460425

461426
const u = `${this.#baseURL}/${resourceName}?updateMask=${updateMasks}`;
462427
const body = JSON.stringify(cf);
463-
const resp: Operation = await this.#request('PATCH', u, {}, body);
428+
const resp: Operation = await this.#request('PATCH', u, body);
464429
const op = await this.#pollOperation(resp.name, {
465430
interval: 5,
466431
retries: timeout / 5,
@@ -554,19 +519,17 @@ export class CloudFunctionsClient {
554519
async uploadSource(uploadURL: string, zipPath: string): Promise<void> {
555520
const zipFile = fs.createReadStream(zipPath);
556521

557-
const u = new URL(uploadURL);
558-
const opts = {
559-
hostname: u.hostname,
560-
port: u.port,
561-
path: u.pathname + u.search,
562-
method: 'PUT',
563-
headers: {
564-
'content-type': 'application/zip',
565-
'x-goog-content-length-range': '0,104857600',
566-
},
567-
};
568-
569-
await CloudFunctionsClient.request(opts, zipFile);
522+
try {
523+
await CloudFunctionsClient.request('PUT', uploadURL, zipFile, {
524+
headers: {
525+
'content-type': 'application/zip',
526+
'x-goog-content-length-range': '0,104857600',
527+
},
528+
});
529+
} catch (err) {
530+
const msg = errorMessage(err);
531+
throw new Error(`Failed to upload source: ${msg}`);
532+
}
570533
}
571534

572535
fullResourceName(name: string): string {

src/main.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,16 @@ import {
2424
setOutput,
2525
warning as logWarning,
2626
} from '@actions/core';
27-
import { ExternalAccountClientOptions } from 'google-auth-library';
27+
import {
28+
Credential,
29+
errorMessage,
30+
isServiceAccountKey,
31+
parseCredential,
32+
parseDuration,
33+
parseKVString,
34+
parseKVStringAndFile,
35+
presence,
36+
} from '@google-github-actions/actions-utils';
2837

2938
import {
3039
CloudFunction,
@@ -33,16 +42,6 @@ import {
3342
SecretVolume,
3443
} from './client';
3544
import { SecretName } from './secret';
36-
import {
37-
errorMessage,
38-
isServiceAccountKey,
39-
parseDuration,
40-
parseKVString,
41-
parseKVStringAndFile,
42-
parseServiceAccountKeyJSON,
43-
presence,
44-
ServiceAccountKey,
45-
} from './util';
4645

4746
async function run(): Promise<void> {
4847
try {
@@ -89,18 +88,15 @@ async function run(): Promise<void> {
8988
const kmsKeyName = presence(getInput('kms_key_name'));
9089

9190
// Add warning if using credentials
92-
let credentialsJSON:
93-
| ServiceAccountKey
94-
| ExternalAccountClientOptions
95-
| undefined;
91+
let credentialsJSON: Credential | undefined;
9692
if (credentials) {
9793
logWarning(
9894
'The "credentials" input is deprecated. ' +
9995
'Please switch to using google-github-actions/auth which supports both Workload Identity Federation and JSON Key authentication. ' +
10096
'For more details, see https://github.com/google-github-actions/deploy-cloud-functions#authorization',
10197
);
10298

103-
credentialsJSON = parseServiceAccountKeyJSON(credentials);
99+
credentialsJSON = parseCredential(credentials);
104100
}
105101

106102
// Pick the best project ID.

0 commit comments

Comments
 (0)