2019-12-12 21:16:16 +03:00
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'
2020-05-07 19:11:11 +03:00
import { Octokit } from '@octokit/rest'
2019-12-12 21:16:16 +03:00
const IS_WINDOWS = process . platform === 'win32'
export async function downloadRepository (
2019-12-12 21:49:26 +03:00
authToken : string ,
2019-12-12 21:16:16 +03:00
owner : string ,
repo : string ,
ref : string ,
commit : string ,
repositoryPath : string
) : Promise < void > {
2020-06-18 17:20:33 +03:00
// Determine the default branch
if ( ! ref && ! commit ) {
core . info ( 'Determining the default branch' )
ref = await getDefaultBranch ( authToken , owner , repo )
}
2019-12-12 21:16:16 +03:00
// Download the archive
let archiveData = await retryHelper . execute ( async ( ) = > {
core . info ( 'Downloading the archive' )
2019-12-12 21:49:26 +03:00
return await downloadArchive ( authToken , owner , repo , ref , commit )
2019-12-12 21:16:16 +03:00
} )
// 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 )
}
2020-06-16 20:41:01 +03:00
/ * *
* Looks up the default branch name
* /
export async function getDefaultBranch (
authToken : string ,
owner : string ,
repo : string
) : Promise < string > {
return await retryHelper . execute ( async ( ) = > {
core . info ( 'Retrieving the default branch name' )
const octokit = new github . GitHub ( authToken )
2020-06-18 17:20:33 +03:00
let result : string
try {
// Get the default branch from the repo info
const response = await octokit . repos . get ( { owner , repo } )
result = response . data . default_branch
assert . ok ( result , 'default_branch cannot be empty' )
} catch ( err ) {
// Handle .wiki repo
if ( err [ 'status' ] === 404 && repo . toUpperCase ( ) . endsWith ( '.WIKI' ) ) {
result = 'master'
}
// Otherwise error
else {
throw err
}
2020-06-16 20:41:01 +03:00
}
// Print the default branch
core . info ( ` Default branch ' ${ result } ' ` )
// Prefix with 'refs/heads'
if ( ! result . startsWith ( 'refs/' ) ) {
result = ` refs/heads/ ${ result } `
}
return result
} )
}
2019-12-12 21:16:16 +03:00
async function downloadArchive (
2019-12-12 21:49:26 +03:00
authToken : string ,
2019-12-12 21:16:16 +03:00
owner : string ,
repo : string ,
ref : string ,
commit : string
) : Promise < Buffer > {
2020-05-07 19:11:11 +03:00
const octokit = new github . GitHub ( authToken )
const params : Octokit.ReposGetArchiveLinkParams = {
2019-12-12 21:16:16 +03:00
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
}