Skip to content

Commit

Permalink
feat: switch to using actions-utils (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
sethvargo committed Dec 23, 2021
1 parent a7536cd commit 938f2f6
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 1,040 deletions.
6 changes: 3 additions & 3 deletions dist/index.js

Large diffs are not rendered by default.

282 changes: 136 additions & 146 deletions package-lock.json

Large diffs are not rendered by default.

20 changes: 9 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,27 @@
"license": "Apache-2.0",
"dependencies": {
"@actions/core": "^1.6.0",
"@google-github-actions/actions-utils": "^0.1.0",
"archiver": "^5.3.0",
"google-auth-library": "^7.10.3",
"ignore": "^5.1.9",
"yaml": "^1.10.2"
"google-auth-library": "^7.11.0",
"ignore": "^5.2.0"
},
"devDependencies": {
"@types/archiver": "^5.1.1",
"@types/chai": "^4.3.0",
"@types/lodash": "^4.14.177",
"@types/mocha": "^9.0.0",
"@types/node": "^16.11.12",
"@types/uuid": "^8.3.3",
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0",
"@vercel/ncc": "^0.33.0",
"@types/node": "^17.0.2",
"@typescript-eslint/eslint-plugin": "^5.8.0",
"@typescript-eslint/parser": "^5.8.0",
"@vercel/ncc": "^0.33.1",
"chai": "^4.3.4",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint": "^8.4.1",
"eslint": "^8.5.0",
"mocha": "^9.1.3",
"node-stream-zip": "^1.15.0",
"prettier": "^2.5.1",
"ts-node": "^10.4.0",
"typescript": "^4.5.2"
"typescript": "^4.5.4"
}
}
125 changes: 44 additions & 81 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,32 @@
* limitations under the License.
*/

import https, { RequestOptions } from 'https';
import { URL } from 'url';
import { RequestOptions } from 'https';
import { randomBytes } from 'crypto';
import fs from 'fs';
import * as path from 'path';
import { tmpdir } from 'os';
import { errorMessage, removeFile, zipDir } from './util';

import {
CredentialBody,
ExternalAccountClientOptions,
GoogleAuth,
} from 'google-auth-library';
import {
errorMessage,
request,
removeFile,
} from '@google-github-actions/actions-utils';

import { zipDir } from './util';

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

// userAgent is the default user agent.
const userAgent = `google-github-actions:deploy-cloud-functions/${appVersion}`;

// defaultBaseURL is the URL for Cloud Functions.
const defaultBaseURL = 'https://cloudfunctions.googleapis.com/v1';

Expand Down Expand Up @@ -182,57 +191,20 @@ export class CloudFunctionsClient {
* request is a high-level helper that returns a promise from the executed
* request.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
static request(opts: RequestOptions, data?: any): Promise<string> {
if (!opts.headers) {
opts.headers = {};
}

if (!opts.headers['User-Agent']) {
opts.headers[
'User-Agent'
] = `google-github-actions:deploy-cloud-functions/${appVersion}`;
}

return new Promise((resolve, reject) => {
const req = https.request(opts, (res) => {
res.setEncoding('utf8');

let body = '';
res.on('data', (data) => {
body += data;
});

res.on('end', () => {
if (res.statusCode && res.statusCode >= 400) {
reject(body);
} else {
resolve(body);
}
});
});

req.on('error', (err) => {
reject(err);
});

if (data == null) {
req.end();
return;
}

if (
typeof data === 'string' ||
data instanceof String ||
data instanceof Buffer
) {
req.write(data);
req.end();
return;
}

data.pipe(req);
});
static async request(
method: string,
url: string,
data?: any, // eslint-disable-line @typescript-eslint/no-explicit-any
opts?: RequestOptions,
): Promise<string> {
opts ||= {};
opts.headers = Object.assign(
{
'User-Agent': userAgent,
},
opts.headers,
);
return await request(method, url, data, opts);
}

/**
Expand Down Expand Up @@ -272,23 +244,15 @@ export class CloudFunctionsClient {
async #request(
method: string,
url: string,
opts?: RequestOptions,
data?: any, // eslint-disable-line @typescript-eslint/no-explicit-any
opts?: RequestOptions,
) {
const u = new URL(url);
opts = Object.assign(opts || {}, {
hostname: u.hostname,
port: u.port,
path: u.pathname + u.search,
method: method,
headers: {},
});

const authToken = await this.#auth.getAccessToken();
if (!authToken) {
throw new Error(`Failed to get auth token for ${method} ${url}`);
}

opts ||= {};
opts.headers = Object.assign(
{
'Authorization': `Bearer ${authToken}`,
Expand All @@ -299,10 +263,11 @@ export class CloudFunctionsClient {
);

try {
const resp = await CloudFunctionsClient.request(opts, data);
const resp = await request(method, url, data, opts);
return JSON.parse(resp);
} catch (err) {
throw new Error(`Failed to ${method} ${url}: ${errorMessage(err)}`);
const msg = errorMessage(err);
throw new Error(`Failed to ${method} ${url}: ${msg}`);
}
}

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

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

const u = new URL(uploadURL);
const opts = {
hostname: u.hostname,
port: u.port,
path: u.pathname + u.search,
method: 'PUT',
headers: {
'content-type': 'application/zip',
'x-goog-content-length-range': '0,104857600',
},
};

await CloudFunctionsClient.request(opts, zipFile);
try {
await CloudFunctionsClient.request('PUT', uploadURL, zipFile, {
headers: {
'content-type': 'application/zip',
'x-goog-content-length-range': '0,104857600',
},
});
} catch (err) {
const msg = errorMessage(err);
throw new Error(`Failed to upload source: ${msg}`);
}
}

fullResourceName(name: string): string {
Expand Down
28 changes: 12 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ import {
setOutput,
warning as logWarning,
} from '@actions/core';
import { ExternalAccountClientOptions } from 'google-auth-library';
import {
Credential,
errorMessage,
isServiceAccountKey,
parseCredential,
parseDuration,
parseKVString,
parseKVStringAndFile,
presence,
} from '@google-github-actions/actions-utils';

import {
CloudFunction,
Expand All @@ -33,16 +42,6 @@ import {
SecretVolume,
} from './client';
import { SecretName } from './secret';
import {
errorMessage,
isServiceAccountKey,
parseDuration,
parseKVString,
parseKVStringAndFile,
parseServiceAccountKeyJSON,
presence,
ServiceAccountKey,
} from './util';

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

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

credentialsJSON = parseServiceAccountKeyJSON(credentials);
credentialsJSON = parseCredential(credentials);
}

// Pick the best project ID.
Expand Down

0 comments on commit 938f2f6

Please sign in to comment.