From 25ac60e43ded675f082e10f444b0ad95ea43622e Mon Sep 17 00:00:00 2001 From: eric sciple Date: Thu, 12 Dec 2019 13:16:16 -0500 Subject: fallback to REST API to download repo (#104) --- src/github-api-helper.ts | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/github-api-helper.ts (limited to 'src/github-api-helper.ts') diff --git a/src/github-api-helper.ts b/src/github-api-helper.ts new file mode 100644 index 0000000..b370d06 --- /dev/null +++ b/src/github-api-helper.ts @@ -0,0 +1,92 @@ +import * as assert from 'assert' +import * as core from '@actions/core' +import * as fs from 'fs' +import * as github from '@actions/github' +import * as io from '@actions/io' +import * as path from 'path' +import * as retryHelper from './retry-helper' +import * as toolCache from '@actions/tool-cache' +import {default as uuid} from 'uuid/v4' +import {ReposGetArchiveLinkParams} from '@octokit/rest' + +const IS_WINDOWS = process.platform === 'win32' + +export async function downloadRepository( + accessToken: string, + owner: string, + repo: string, + ref: string, + commit: string, + repositoryPath: string +): Promise { + // Download the archive + let archiveData = await retryHelper.execute(async () => { + core.info('Downloading the archive') + return await downloadArchive(accessToken, owner, repo, ref, commit) + }) + + // Write archive to disk + core.info('Writing archive to disk') + const uniqueId = uuid() + const archivePath = path.join(repositoryPath, `${uniqueId}.tar.gz`) + await fs.promises.writeFile(archivePath, archiveData) + archiveData = Buffer.from('') // Free memory + + // Extract archive + core.info('Extracting the archive') + const extractPath = path.join(repositoryPath, uniqueId) + await io.mkdirP(extractPath) + if (IS_WINDOWS) { + await toolCache.extractZip(archivePath, extractPath) + } else { + await toolCache.extractTar(archivePath, extractPath) + } + io.rmRF(archivePath) + + // Determine the path of the repository content. The archive contains + // a top-level folder and the repository content is inside. + const archiveFileNames = await fs.promises.readdir(extractPath) + assert.ok( + archiveFileNames.length == 1, + 'Expected exactly one directory inside archive' + ) + const archiveVersion = archiveFileNames[0] // The top-level folder name includes the short SHA + core.info(`Resolved version ${archiveVersion}`) + const tempRepositoryPath = path.join(extractPath, archiveVersion) + + // Move the files + for (const fileName of await fs.promises.readdir(tempRepositoryPath)) { + const sourcePath = path.join(tempRepositoryPath, fileName) + const targetPath = path.join(repositoryPath, fileName) + if (IS_WINDOWS) { + await io.cp(sourcePath, targetPath, {recursive: true}) // Copy on Windows (Windows Defender may have a lock) + } else { + await io.mv(sourcePath, targetPath) + } + } + io.rmRF(extractPath) +} + +async function downloadArchive( + accessToken: string, + owner: string, + repo: string, + ref: string, + commit: string +): Promise { + const octokit = new github.GitHub(accessToken) + const params: ReposGetArchiveLinkParams = { + owner: owner, + repo: repo, + archive_format: IS_WINDOWS ? 'zipball' : 'tarball', + ref: commit || ref + } + const response = await octokit.repos.getArchiveLink(params) + if (response.status != 200) { + throw new Error( + `Unexpected response from GitHub API. Status: ${response.status}, Data: ${response.data}` + ) + } + + return Buffer.from(response.data) // response.data is ArrayBuffer +} -- cgit v1.2.3