From e9d35bb1ee5ba3410079e799547308dd576d1195 Mon Sep 17 00:00:00 2001 From: David Kale Date: Fri, 31 Jan 2020 14:04:35 -0500 Subject: [PATCH] Replace typed rest client with new http-client --- .gitignore | 3 + package-lock.json | 34 +++++------ package.json | 2 +- src/cacheHttpClient.ts | 124 +++++++++++++++++++++-------------------- 4 files changed, 84 insertions(+), 79 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..b8ad4b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,21 @@ "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.1.tgz", "integrity": "sha512-nvFkxwiicvpzNiCBF4wFBDfnBvi7xp/as7LE1hBxBxKG2L29+gkIPBiLKMVORL+Hg3JNf07AKRfl0V5djoypjQ==" }, + "@actions/http-client": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.3.tgz", + "integrity": "sha512-wFwh1U4adB/Zsk4cc9kVqaBOHoknhp/pJQk+aWTocbAZWpIl4Zx/At83WFRLXvxB+5HVTWOACM6qjULMZfQSfw==", + "requires": { + "tunnel": "0.0.6" + }, + "dependencies": { + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + } + } + }, "@actions/io": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.1.tgz", @@ -5932,11 +5947,6 @@ "tslib": "^1.8.1" } }, - "tunnel": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz", - "integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=" - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5973,15 +5983,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 +6000,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..2f53d55 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.3", "@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..6cd7cc4 100644 --- a/src/cacheHttpClient.ts +++ b/src/cacheHttpClient.ts @@ -1,13 +1,11 @@ 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 { - IRequestOptions, - RestClient, - IRestResponse -} from "typed-rest-client/RestClient"; + IHttpClientResponse, + IRequestOptions +} from "@actions/http-client/interfaces"; import { ArtifactCacheEntry, CommitCacheRequest, @@ -16,11 +14,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 +33,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"] || @@ -43,7 +47,7 @@ function getCacheApiUrl(): string { } core.debug(`Cache Url: ${baseUrl}`); - return `${baseUrl}_apis/artifactcache/`; + return `${baseUrl}_apis/artifactcache/${resource}`; } function createAcceptHeader(type: string, apiVersion: string): string { @@ -52,39 +56,44 @@ 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() - ); - if (response.statusCode === 204) { + const response = await httpClient.get(getCacheApiUrl(resource)); + if (response.message.statusCode === 204) { return null; } - if (!isSuccessStatusCode(response.statusCode)) { - throw new Error(`Cache service responded with ${response.statusCode}`); + if (!isSuccessStatusCode(response.message.statusCode)) { + throw new Error( + `Cache service responded with ${response.message.statusCode}` + ); } - const cacheResult = response.result; - const cacheDownloadUrl = cacheResult?.archiveLocation; + + const body = await response.readBody(); + const cacheResult = JSON.parse(body) as ArtifactCacheEntry; + const cacheDownloadUrl = cacheResult.archiveLocation; if (!cacheDownloadUrl) { throw new Error("Cache not found."); } @@ -118,18 +127,18 @@ 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.post( + getCacheApiUrl("caches"), + JSON.stringify(reserveCacheRequest) ); - - return response?.result?.cacheId ?? -1; + const body = await response.readBody(); + const cacheResult = JSON.parse(body) as ReserveCacheResponse; + return cacheResult.cacheId || -1; } function getContentRange(start: number, end: number): string { @@ -142,7 +151,7 @@ function getContentRange(start: number, end: number): string { } async function uploadChunk( - restClient: RestClient, + httpClient: HttpClient, resourceUrl: string, data: NodeJS.ReadableStream, start: number, @@ -156,38 +165,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 +208,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 +245,7 @@ async function uploadFile( }); await uploadChunk( - restClient, + httpClient, resourceUrl, chunk, start, @@ -253,16 +261,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.post( + getCacheApiUrl(`caches/${cacheId.toString()}`), + JSON.stringify(commitCacheRequest) ); } @@ -270,22 +276,22 @@ 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 ); - if (!isSuccessStatusCode(commitCacheResponse.statusCode)) { + if (!isSuccessStatusCode(commitCacheResponse.message.statusCode)) { throw new Error( - `Cache service responded with ${commitCacheResponse.statusCode} during commit cache.` + `Cache service responded with ${commitCacheResponse.message.statusCode} during commit cache.` ); }