diff --git a/main.ts b/main.ts index 38f46232..8f61abc5 100644 --- a/main.ts +++ b/main.ts @@ -8,6 +8,7 @@ import { getViaGit, gitForWindowsUsrBinPath } from './src/git' +import {getViaCIArtifacts} from './src/ci_artifacts' import * as fs from 'fs' const flavor = core.getInput('flavor') @@ -44,11 +45,10 @@ async function run(): Promise { const verbose = core.getInput('verbose') const msysMode = core.getInput('msys') === 'true' - const {artifactName, download, id} = await getViaGit( - flavor, - architecture, - githubToken - ) + const {artifactName, download, id} = + flavor === 'minimal' + ? await getViaCIArtifacts(architecture, githubToken) + : await getViaGit(flavor, architecture, githubToken) const outputDirectory = core.getInput('path') || `${getDriveLetterPrefix()}${artifactName}` core.setOutput('result', outputDirectory) diff --git a/src/ci_artifacts.ts b/src/ci_artifacts.ts new file mode 100644 index 00000000..2ac19ae8 --- /dev/null +++ b/src/ci_artifacts.ts @@ -0,0 +1,92 @@ +import * as core from '@actions/core' +import {Octokit} from '@octokit/rest' +import {getArtifactMetadata} from './git' +import {spawn} from 'child_process' +import * as fs from 'fs' + +export async function getViaCIArtifacts( + architecture: string, + githubToken?: string +): Promise<{ + artifactName: string + id: string + download: ( + outputDirectory: string, + verbose?: number | boolean + ) => Promise +}> { + const owner = 'git-for-windows' + + const {repo, artifactName} = getArtifactMetadata('minimal', architecture) + + const octokit = githubToken ? new Octokit({auth: githubToken}) : new Octokit() + + const ciArtifactsResponse = await octokit.repos.getReleaseByTag({ + owner, + repo, + tag: 'ci-artifacts' + }) + + if (ciArtifactsResponse.status !== 200) { + throw new Error( + `Failed to get ci-artifacts release from the ${owner}/${repo} repo: ${ciArtifactsResponse.status}` + ) + } + + core.info(`Found ci-artifacts release: ${ciArtifactsResponse.data.html_url}`) + const tarGzArtifact = ciArtifactsResponse.data.assets.find(asset => + asset.name.endsWith('.tar.gz') + ) + + if (!tarGzArtifact) { + throw new Error( + `Failed to find a .tar.gz artifact in the ci-artifacts release of the ${owner}/${repo} repo` + ) + } + + const url = tarGzArtifact.browser_download_url + core.info(`Found ${tarGzArtifact.name} at ${url}`) + + return { + artifactName, + id: `ci-artifacts-${tarGzArtifact.updated_at}`, + download: async ( + outputDirectory: string, + verbose: number | boolean = false + ): Promise => { + return new Promise((resolve, reject) => { + const curl = spawn( + `${process.env.SYSTEMROOT}/system32/curl.exe`, + [ + ...(githubToken + ? ['-H', `Authorization: Bearer ${githubToken}`] + : []), + '-H', + 'Accept: application/octet-stream', + `-${verbose === true ? '' : 's'}fL`, + url + ], + { + stdio: ['ignore', 'pipe', process.stderr] + } + ) + curl.on('error', error => reject(error)) + + fs.mkdirSync(outputDirectory, {recursive: true}) + + const tar = spawn( + `${process.env.SYSTEMROOT}/system32/tar.exe`, + ['-C', outputDirectory, `-x${verbose === true ? 'v' : ''}f`, '-'], + {stdio: ['pipe', process.stdout, process.stderr]} + ) + tar.on('error', error => reject(error)) + tar.on('close', code => { + if (code === 0) resolve() + else reject(new Error(`tar exited with code ${code}`)) + }) + + curl.stdout.pipe(tar.stdin) + }) + } + } +}