From 4887979af80ed6f9edf3f14cb4ac23155c266d60 Mon Sep 17 00:00:00 2001 From: David Kale Date: Wed, 5 Feb 2020 09:24:37 -0500 Subject: [PATCH] proxy support (#166) * Replace typed rest client with new http-client * Send Content-Type: application/json and fix up some types * Lint * Consume @actions/http-client:1.0.5 * Consume @actions/http-client:1.0.6 * Dont send headers manually, http-client automatically will --- .gitignore | 3 ++ package-lock.json | 28 +++++------ package.json | 2 +- src/cacheHttpClient.ts | 105 +++++++++++++++++++++-------------------- 4 files changed, 70 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index 4917f3f..696edbe 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,6 @@ typings/ # DynamoDB Local files .dynamodb/ + +# Text editor files +.vscode/ diff --git a/package-lock.json b/package-lock.json index d60f8ae..3ca4841 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,14 @@ "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.1.tgz", "integrity": "sha512-nvFkxwiicvpzNiCBF4wFBDfnBvi7xp/as7LE1hBxBxKG2L29+gkIPBiLKMVORL+Hg3JNf07AKRfl0V5djoypjQ==" }, + "@actions/http-client": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.6.tgz", + "integrity": "sha512-LGmio4w98UyGX33b/W6V6Nx/sQHRXZ859YlMkn36wPsXPB82u8xTVlA/Dq2DXrm6lEq9RVmisRJa1c+HETAIJA==", + "requires": { + "tunnel": "0.0.6" + } + }, "@actions/io": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.1.tgz", @@ -5933,9 +5941,9 @@ } }, "tunnel": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz", - "integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=" + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" }, "tunnel-agent": { "version": "0.6.0", @@ -5973,15 +5981,6 @@ "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", "dev": true }, - "typed-rest-client": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.5.0.tgz", - "integrity": "sha512-DVZRlmsfnTjp6ZJaatcdyvvwYwbWvR4YDNFDqb+qdTxpvaVP99YCpBkA8rxsLtAPjBVoDe4fNsnMIdZTiPuKWg==", - "requires": { - "tunnel": "0.0.4", - "underscore": "1.8.3" - } - }, "typescript": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz", @@ -5999,11 +5998,6 @@ "source-map": "~0.6.1" } }, - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" - }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", diff --git a/package.json b/package.json index 7de321b..476b675 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "dependencies": { "@actions/core": "^1.2.0", "@actions/exec": "^1.0.1", + "@actions/http-client": "^1.0.6", "@actions/io": "^1.0.1", - "typed-rest-client": "^1.5.0", "uuid": "^3.3.3" }, "devDependencies": { diff --git a/src/cacheHttpClient.ts b/src/cacheHttpClient.ts index 97c9672..62ae2c1 100644 --- a/src/cacheHttpClient.ts +++ b/src/cacheHttpClient.ts @@ -1,13 +1,12 @@ import * as core from "@actions/core"; import * as fs from "fs"; -import { BearerCredentialHandler } from "typed-rest-client/Handlers"; -import { HttpClient, HttpCodes } from "typed-rest-client/HttpClient"; -import { IHttpClientResponse } from "typed-rest-client/Interfaces"; +import { BearerCredentialHandler } from "@actions/http-client/auth"; +import { HttpClient, HttpCodes } from "@actions/http-client"; import { + IHttpClientResponse, IRequestOptions, - RestClient, - IRestResponse -} from "typed-rest-client/RestClient"; + ITypedResponse +} from "@actions/http-client/interfaces"; import { ArtifactCacheEntry, CommitCacheRequest, @@ -16,11 +15,17 @@ import { } from "./contracts"; import * as utils from "./utils/actionUtils"; -function isSuccessStatusCode(statusCode: number): boolean { +function isSuccessStatusCode(statusCode?: number): boolean { + if (!statusCode) { + return false; + } return statusCode >= 200 && statusCode < 300; } -function isRetryableStatusCode(statusCode: number): boolean { +function isRetryableStatusCode(statusCode?: number): boolean { + if (!statusCode) { + return false; + } const retryableStatusCodes = [ HttpCodes.BadGateway, HttpCodes.ServiceUnavailable, @@ -29,7 +34,7 @@ function isRetryableStatusCode(statusCode: number): boolean { return retryableStatusCodes.includes(statusCode); } -function getCacheApiUrl(): string { +function getCacheApiUrl(resource: string): string { // Ideally we just use ACTIONS_CACHE_URL const baseUrl: string = ( process.env["ACTIONS_CACHE_URL"] || @@ -42,8 +47,9 @@ function getCacheApiUrl(): string { ); } - core.debug(`Cache Url: ${baseUrl}`); - return `${baseUrl}_apis/artifactcache/`; + const url = `${baseUrl}_apis/artifactcache/${resource}`; + core.debug(`Resource Url: ${url}`); + return url; } function createAcceptHeader(type: string, apiVersion: string): string { @@ -52,30 +58,33 @@ function createAcceptHeader(type: string, apiVersion: string): string { function getRequestOptions(): IRequestOptions { const requestOptions: IRequestOptions = { - acceptHeader: createAcceptHeader("application/json", "6.0-preview.1") + headers: { + Accept: createAcceptHeader("application/json", "6.0-preview.1") + } }; return requestOptions; } -function createRestClient(): RestClient { +function createHttpClient(): HttpClient { const token = process.env["ACTIONS_RUNTIME_TOKEN"] || ""; const bearerCredentialHandler = new BearerCredentialHandler(token); - return new RestClient("actions/cache", getCacheApiUrl(), [ - bearerCredentialHandler - ]); + return new HttpClient( + "actions/cache", + [bearerCredentialHandler], + getRequestOptions() + ); } export async function getCacheEntry( keys: string[] ): Promise { - const restClient = createRestClient(); + const httpClient = createHttpClient(); const resource = `cache?keys=${encodeURIComponent(keys.join(","))}`; - const response = await restClient.get( - resource, - getRequestOptions() + const response = await httpClient.getJson( + getCacheApiUrl(resource) ); if (response.statusCode === 204) { return null; @@ -83,6 +92,7 @@ export async function getCacheEntry( if (!isSuccessStatusCode(response.statusCode)) { throw new Error(`Cache service responded with ${response.statusCode}`); } + const cacheResult = response.result; const cacheDownloadUrl = cacheResult?.archiveLocation; if (!cacheDownloadUrl) { @@ -118,17 +128,15 @@ export async function downloadCache( // Reserve Cache export async function reserveCache(key: string): Promise { - const restClient = createRestClient(); + const httpClient = createHttpClient(); const reserveCacheRequest: ReserveCacheRequest = { key }; - const response = await restClient.create( - "caches", - reserveCacheRequest, - getRequestOptions() + const response = await httpClient.postJson( + getCacheApiUrl("caches"), + reserveCacheRequest ); - return response?.result?.cacheId ?? -1; } @@ -142,7 +150,7 @@ function getContentRange(start: number, end: number): string { } async function uploadChunk( - restClient: RestClient, + httpClient: HttpClient, resourceUrl: string, data: NodeJS.ReadableStream, start: number, @@ -156,38 +164,37 @@ async function uploadChunk( end )}` ); - const requestOptions = getRequestOptions(); - requestOptions.additionalHeaders = { + const additionalHeaders = { "Content-Type": "application/octet-stream", "Content-Range": getContentRange(start, end) }; - const uploadChunkRequest = async (): Promise> => { - return await restClient.uploadStream( + const uploadChunkRequest = async (): Promise => { + return await httpClient.sendStream( "PATCH", resourceUrl, data, - requestOptions + additionalHeaders ); }; const response = await uploadChunkRequest(); - if (isSuccessStatusCode(response.statusCode)) { + if (isSuccessStatusCode(response.message.statusCode)) { return; } - if (isRetryableStatusCode(response.statusCode)) { + if (isRetryableStatusCode(response.message.statusCode)) { core.debug( - `Received ${response.statusCode}, retrying chunk at offset ${start}.` + `Received ${response.message.statusCode}, retrying chunk at offset ${start}.` ); const retryResponse = await uploadChunkRequest(); - if (isSuccessStatusCode(retryResponse.statusCode)) { + if (isSuccessStatusCode(retryResponse.message.statusCode)) { return; } } throw new Error( - `Cache service responded with ${response.statusCode} during chunk upload.` + `Cache service responded with ${response.message.statusCode} during chunk upload.` ); } @@ -200,13 +207,13 @@ function parseEnvNumber(key: string): number | undefined { } async function uploadFile( - restClient: RestClient, + httpClient: HttpClient, cacheId: number, archivePath: string ): Promise { // Upload Chunks const fileSize = fs.statSync(archivePath).size; - const resourceUrl = getCacheApiUrl() + "caches/" + cacheId.toString(); + const resourceUrl = getCacheApiUrl(`caches/${cacheId.toString()}`); const fd = fs.openSync(archivePath, "r"); const concurrency = parseEnvNumber("CACHE_UPLOAD_CONCURRENCY") ?? 4; // # of HTTP requests in parallel @@ -237,7 +244,7 @@ async function uploadFile( }); await uploadChunk( - restClient, + httpClient, resourceUrl, chunk, start, @@ -253,16 +260,14 @@ async function uploadFile( } async function commitCache( - restClient: RestClient, + httpClient: HttpClient, cacheId: number, filesize: number -): Promise> { - const requestOptions = getRequestOptions(); +): Promise> { const commitCacheRequest: CommitCacheRequest = { size: filesize }; - return await restClient.create( - `caches/${cacheId.toString()}`, - commitCacheRequest, - requestOptions + return await httpClient.postJson( + getCacheApiUrl(`caches/${cacheId.toString()}`), + commitCacheRequest ); } @@ -270,16 +275,16 @@ export async function saveCache( cacheId: number, archivePath: string ): Promise { - const restClient = createRestClient(); + const httpClient = createHttpClient(); core.debug("Upload cache"); - await uploadFile(restClient, cacheId, archivePath); + await uploadFile(httpClient, cacheId, archivePath); // Commit Cache core.debug("Commiting cache"); const cacheSize = utils.getArchiveFileSize(archivePath); const commitCacheResponse = await commitCache( - restClient, + httpClient, cacheId, cacheSize );