From 19e16339c3a1c2966c6f30d36bbeecaedce8d189 Mon Sep 17 00:00:00 2001 From: Robin Raju Date: Mon, 27 Jul 2020 15:10:54 +0200 Subject: [PATCH] Add support for private repositories --- __tests__/main.test.ts | 3 +- dist/index.js | 58 +++++++++++++++++++--------- src/download-settings.ts | 2 +- src/download.ts | 81 +++++++++++++++++++++++++++++++--------- src/gh-api.ts | 2 +- 5 files changed, 109 insertions(+), 37 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 49f090a..33f7188 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -9,7 +9,8 @@ test("run download", async () => { fileName: "2.13-2.1.1-14-4f2a1b2-bootstrap", tarBall: true, zipBall: true, - outFilePath: "/tmp/release-downloader" + outFilePath: "/tmp/release-downloader", + token: "" } await download(downloadSettings) }, 10000) diff --git a/dist/index.js b/dist/index.js index 7e268b8..7758bc3 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2382,13 +2382,13 @@ function download(_downloadSettings) { return __awaiter(this, void 0, void 0, function* () { let ghRelease; if (_downloadSettings.isLatest) { - ghRelease = yield getlatestRelease(_downloadSettings.sourceRepoPath); + ghRelease = yield getlatestRelease(_downloadSettings.sourceRepoPath, _downloadSettings.token); } else { - ghRelease = yield getReleaseByTag(_downloadSettings.sourceRepoPath, _downloadSettings.tag); + ghRelease = yield getReleaseByTag(_downloadSettings.sourceRepoPath, _downloadSettings.tag, _downloadSettings.token); } const resolvedAssets = resolveAssets(ghRelease, _downloadSettings); - return yield downloadReleaseAssets(resolvedAssets, _downloadSettings.outFilePath); + return yield downloadReleaseAssets(resolvedAssets, _downloadSettings.outFilePath, _downloadSettings.token); }); } exports.download = download; @@ -2396,10 +2396,18 @@ exports.download = download; * Gets the latest release metadata from github api * @param repoPath The source repository path. {owner}/{repo} */ -function getlatestRelease(repoPath) { +function getlatestRelease(repoPath, token) { return __awaiter(this, void 0, void 0, function* () { core.info(`Fetching latest relase for repo ${repoPath}`); - const response = yield httpClient.get(`${API_ROOT}/${repoPath}/releases/latest`); + let headers = {}; + if (token !== "") { + headers = { Authorization: `token ${token}` }; + } + const response = yield httpClient.get(`${API_ROOT}/${repoPath}/releases/latest`, headers); + if (response.message.statusCode !== 200) { + const err = new Error(`[getlatestRelease] Unexpected response: ${response.message.statusCode}`); + throw err; + } const responseBody = yield response.readBody(); const _release = JSON.parse(responseBody.toString()); return _release; @@ -2410,13 +2418,21 @@ function getlatestRelease(repoPath) { * @param repoPath The source repository * @param tag The github tag to fetch release from. */ -function getReleaseByTag(repoPath, tag) { +function getReleaseByTag(repoPath, tag, token) { return __awaiter(this, void 0, void 0, function* () { core.info(`Fetching relase ${tag} from repo ${repoPath}`); if (tag === "") { throw new Error("Config error: Please input a valid tag"); } - const response = yield httpClient.get(`${API_ROOT}/${repoPath}/releases/tags/${tag}`); + let headers = {}; + if (token !== "") { + headers = { Authorization: `token ${token}` }; + } + const response = yield httpClient.get(`${API_ROOT}/${repoPath}/releases/tags/${tag}`, headers); + if (response.message.statusCode !== 200) { + const err = new Error(`[getReleaseByTag] Unexpected response: ${response.message.statusCode}`); + throw err; + } const responseBody = yield response.readBody(); const _release = JSON.parse(responseBody.toString()); return _release; @@ -2429,7 +2445,7 @@ function resolveAssets(_release, _settings) { if (asset) { const dData = { fileName: asset["name"], - url: asset["browser_download_url"] + url: asset["url"] }; downloads.push(dData); } @@ -2451,11 +2467,12 @@ function resolveAssets(_release, _settings) { return downloads; } /** - * Downloads the specified file from a given URL - * @param [fileName, downloadUrl] The filename and url + * Downloads the specified assets from a given URL + * @param dData The download metadata * @param out Target directory + * @param token Personal access token to for private repos */ -function downloadReleaseAssets(dData, out) { +function downloadReleaseAssets(dData, out, token) { return __awaiter(this, void 0, void 0, function* () { const outFileDir = path.resolve(out); if (!fs.existsSync(outFileDir)) { @@ -2463,22 +2480,29 @@ function downloadReleaseAssets(dData, out) { } const downloads = []; for (const asset of dData) { - downloads.push(downloadFile(asset.fileName, asset.url, out)); + downloads.push(downloadFile(asset.fileName, asset.url, out, token)); } const result = yield Promise.all(downloads); return result; }); } -function downloadFile(fileName, url, outputPath) { +function downloadFile(fileName, url, outputPath, token) { return __awaiter(this, void 0, void 0, function* () { - const response = yield httpClient.get(url); - core.info(`Downloading file: ${fileName} to: ${outputPath}`); - const outFilePath = path.resolve(outputPath, fileName); - const fileStream = fs.createWriteStream(outFilePath); + let headers = {}; + if (token !== "") { + headers = { + Authorization: `token ${token}`, + Accept: "application/vnd.github.v3.raw" + }; + } + core.info(`Downloading file: ${fileName} to: ${outputPath} token=${token}`); + const response = yield httpClient.get(url, headers); if (response.message.statusCode !== 200) { const err = new Error(`Unexpected response: ${response.message.statusCode}`); throw err; } + const outFilePath = path.resolve(outputPath, fileName); + const fileStream = fs.createWriteStream(outFilePath); return new Promise((resolve, reject) => { fileStream.on("error", err => reject(err)); const outStream = response.message.pipe(fileStream); diff --git a/src/download-settings.ts b/src/download-settings.ts index c4589b1..0fc6377 100644 --- a/src/download-settings.ts +++ b/src/download-settings.ts @@ -37,5 +37,5 @@ export interface IReleaseDownloadSettings { /** * Github access token to download from private repos (Optional) */ - token?: string + token: string } diff --git a/src/download.ts b/src/download.ts index 53ebf07..8afea0b 100644 --- a/src/download.ts +++ b/src/download.ts @@ -5,6 +5,7 @@ import * as io from "@actions/io" import * as thc from "typed-rest-client/HttpClient" import {IReleaseDownloadSettings} from "./download-settings" import {GithubRelease, DownloadMetaData} from "./gh-api" +import {IHeaders} from "typed-rest-client/Interfaces" const API_ROOT = "https://api.github.com/repos" const httpClient: thc.HttpClient = new thc.HttpClient("gh-api-client") @@ -15,11 +16,15 @@ export async function download( let ghRelease: GithubRelease if (_downloadSettings.isLatest) { - ghRelease = await getlatestRelease(_downloadSettings.sourceRepoPath) + ghRelease = await getlatestRelease( + _downloadSettings.sourceRepoPath, + _downloadSettings.token + ) } else { ghRelease = await getReleaseByTag( _downloadSettings.sourceRepoPath, - _downloadSettings.tag + _downloadSettings.tag, + _downloadSettings.token ) } @@ -30,7 +35,8 @@ export async function download( return await downloadReleaseAssets( resolvedAssets, - _downloadSettings.outFilePath + _downloadSettings.outFilePath, + _downloadSettings.token ) } @@ -38,13 +44,29 @@ export async function download( * Gets the latest release metadata from github api * @param repoPath The source repository path. {owner}/{repo} */ -async function getlatestRelease(repoPath: string): Promise { +async function getlatestRelease( + repoPath: string, + token: string +): Promise { core.info(`Fetching latest relase for repo ${repoPath}`) + let headers: IHeaders = {} + if (token !== "") { + headers = {Authorization: `token ${token}`} + } + const response = await httpClient.get( - `${API_ROOT}/${repoPath}/releases/latest` + `${API_ROOT}/${repoPath}/releases/latest`, + headers ) + if (response.message.statusCode !== 200) { + const err: Error = new Error( + `[getlatestRelease] Unexpected response: ${response.message.statusCode}` + ) + throw err + } + const responseBody = await response.readBody() const _release: GithubRelease = JSON.parse(responseBody.toString()) @@ -58,17 +80,32 @@ async function getlatestRelease(repoPath: string): Promise { */ async function getReleaseByTag( repoPath: string, - tag: string + tag: string, + token: string ): Promise { core.info(`Fetching relase ${tag} from repo ${repoPath}`) if (tag === "") { throw new Error("Config error: Please input a valid tag") } + + let headers: IHeaders = {} + if (token !== "") { + headers = {Authorization: `token ${token}`} + } + const response = await httpClient.get( - `${API_ROOT}/${repoPath}/releases/tags/${tag}` + `${API_ROOT}/${repoPath}/releases/tags/${tag}`, + headers ) + if (response.message.statusCode !== 200) { + const err: Error = new Error( + `[getReleaseByTag] Unexpected response: ${response.message.statusCode}` + ) + throw err + } + const responseBody = await response.readBody() const _release: GithubRelease = JSON.parse(responseBody.toString()) @@ -86,7 +123,7 @@ function resolveAssets( if (asset) { const dData: DownloadMetaData = { fileName: asset["name"], - url: asset["browser_download_url"] + url: asset["url"] } downloads.push(dData) } @@ -112,13 +149,15 @@ function resolveAssets( } /** - * Downloads the specified file from a given URL - * @param [fileName, downloadUrl] The filename and url + * Downloads the specified assets from a given URL + * @param dData The download metadata * @param out Target directory + * @param token Personal access token to for private repos */ async function downloadReleaseAssets( dData: DownloadMetaData[], - out: string + out: string, + token: string ): Promise { const outFileDir = path.resolve(out) @@ -129,7 +168,7 @@ async function downloadReleaseAssets( const downloads: Promise[] = [] for (const asset of dData) { - downloads.push(downloadFile(asset.fileName, asset.url, out)) + downloads.push(downloadFile(asset.fileName, asset.url, out, token)) } const result = await Promise.all(downloads) @@ -139,13 +178,19 @@ async function downloadReleaseAssets( async function downloadFile( fileName: string, url: string, - outputPath: string + outputPath: string, + token: string ): Promise { - const response = await httpClient.get(url) - core.info(`Downloading file: ${fileName} to: ${outputPath}`) - const outFilePath: string = path.resolve(outputPath, fileName) + let headers: IHeaders = {} + if (token !== "") { + headers = { + Authorization: `token ${token}`, + Accept: "application/vnd.github.v3.raw" + } + } - const fileStream: NodeJS.WritableStream = fs.createWriteStream(outFilePath) + core.info(`Downloading file: ${fileName} to: ${outputPath} token=${token}`) + const response = await httpClient.get(url, headers) if (response.message.statusCode !== 200) { const err: Error = new Error( @@ -153,6 +198,8 @@ async function downloadFile( ) throw err } + const outFilePath: string = path.resolve(outputPath, fileName) + const fileStream: NodeJS.WritableStream = fs.createWriteStream(outFilePath) return new Promise((resolve, reject) => { fileStream.on("error", err => reject(err)) diff --git a/src/gh-api.ts b/src/gh-api.ts index 9994600..609c191 100644 --- a/src/gh-api.ts +++ b/src/gh-api.ts @@ -1,6 +1,6 @@ interface GhAsset { name: string - browser_download_url: string + url: string } export interface GithubRelease {