2019-12-03 17:28:59 +02:00
import * as core from '@actions/core'
import * as fsHelper from './fs-helper'
2020-03-02 18:33:30 +02:00
import * as gitAuthHelper from './git-auth-helper'
2019-12-03 17:28:59 +02:00
import * as gitCommandManager from './git-command-manager'
2020-03-02 18:33:30 +02:00
import * as gitDirectoryHelper from './git-directory-helper'
2019-12-12 20:16:16 +02:00
import * as githubApiHelper from './github-api-helper'
2019-12-03 17:28:59 +02:00
import * as io from '@actions/io'
import * as path from 'path'
import * as refHelper from './ref-helper'
2019-12-12 20:16:16 +02:00
import * as stateHelper from './state-helper'
2019-12-03 17:28:59 +02:00
import { IGitCommandManager } from './git-command-manager'
2020-03-02 18:33:30 +02:00
import { IGitSourceSettings } from './git-source-settings'
2019-12-03 17:28:59 +02:00
2020-03-02 18:33:30 +02:00
const hostname = 'github.com'
2019-12-03 17:28:59 +02:00
2020-03-02 18:33:30 +02:00
export async function getSource ( settings : IGitSourceSettings ) : Promise < void > {
2019-12-12 20:16:16 +02:00
// Repository URL
2019-12-03 17:28:59 +02:00
core . info (
` Syncing repository: ${ settings . repositoryOwner } / ${ settings . repositoryName } `
)
2020-03-11 21:55:17 +02:00
const repositoryUrl = settings . sshKey
? ` git@ ${ hostname } : ${ encodeURIComponent (
settings . repositoryOwner
) } / $ { encodeURIComponent ( settings . repositoryName ) } . git `
: ` https:// ${ hostname } / ${ encodeURIComponent (
settings . repositoryOwner
) } / $ { encodeURIComponent ( settings . repositoryName ) } `
2019-12-03 17:28:59 +02:00
// Remove conflicting file path
if ( fsHelper . fileExistsSync ( settings . repositoryPath ) ) {
await io . rmRF ( settings . repositoryPath )
}
// Create directory
let isExisting = true
if ( ! fsHelper . directoryExistsSync ( settings . repositoryPath ) ) {
isExisting = false
await io . mkdirP ( settings . repositoryPath )
}
// Git command manager
2019-12-12 20:16:16 +02:00
const git = await getGitCommandManager ( settings )
2019-12-03 17:28:59 +02:00
2019-12-12 20:16:16 +02:00
// Prepare existing directory, otherwise recreate
if ( isExisting ) {
2020-03-02 18:33:30 +02:00
await gitDirectoryHelper . prepareExistingDirectory (
2019-12-03 17:28:59 +02:00
git ,
settings . repositoryPath ,
repositoryUrl ,
settings . clean
)
}
2019-12-12 20:16:16 +02:00
if ( ! git ) {
// Downloading using REST API
core . info ( ` The repository will be downloaded using the GitHub REST API ` )
core . info (
` To create a local Git repository instead, add Git ${ gitCommandManager . MinimumGitVersion } or higher to the PATH `
)
2020-03-12 17:42:38 +02:00
if ( settings . submodules ) {
throw new Error (
` Input 'submodules' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${ gitCommandManager . MinimumGitVersion } or higher to the PATH. `
)
} else if ( settings . sshKey ) {
throw new Error (
` Input 'ssh-key' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${ gitCommandManager . MinimumGitVersion } or higher to the PATH. `
)
}
2019-12-12 20:16:16 +02:00
await githubApiHelper . downloadRepository (
2019-12-12 20:49:26 +02:00
settings . authToken ,
2019-12-12 20:16:16 +02:00
settings . repositoryOwner ,
settings . repositoryName ,
settings . ref ,
settings . commit ,
settings . repositoryPath
)
2020-03-05 21:21:59 +02:00
return
}
2019-12-03 17:28:59 +02:00
2020-03-05 21:21:59 +02:00
// Save state for POST action
stateHelper . setRepositoryPath ( settings . repositoryPath )
2019-12-03 17:28:59 +02:00
2020-03-05 21:21:59 +02:00
// Initialize the repository
if (
! fsHelper . directoryExistsSync ( path . join ( settings . repositoryPath , '.git' ) )
) {
await git . init ( )
await git . remoteAdd ( 'origin' , repositoryUrl )
}
2019-12-12 20:16:16 +02:00
2020-03-05 21:21:59 +02:00
// Disable automatic garbage collection
if ( ! ( await git . tryDisableAutomaticGarbageCollection ( ) ) ) {
core . warning (
` Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay. `
)
}
2019-12-03 17:28:59 +02:00
2020-03-05 21:21:59 +02:00
const authHelper = gitAuthHelper . createAuthHelper ( git , settings )
try {
// Configure auth
await authHelper . configureAuth ( )
2019-12-03 17:28:59 +02:00
2020-03-05 21:21:59 +02:00
// LFS install
if ( settings . lfs ) {
await git . lfsInstall ( )
}
// Fetch
const refSpec = refHelper . getRefSpec ( settings . ref , settings . commit )
await git . fetch ( settings . fetchDepth , refSpec )
// Checkout info
const checkoutInfo = await refHelper . getCheckoutInfo (
git ,
settings . ref ,
settings . commit
)
// LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel.
if ( settings . lfs ) {
await git . lfsFetch ( checkoutInfo . startPoint || checkoutInfo . ref )
}
2019-12-03 17:28:59 +02:00
2020-03-05 21:21:59 +02:00
// Checkout
await git . checkout ( checkoutInfo . ref , checkoutInfo . startPoint )
// Submodules
if ( settings . submodules ) {
try {
// Temporarily override global config
await authHelper . configureGlobalAuth ( )
// Checkout submodules
await git . submoduleSync ( settings . nestedSubmodules )
await git . submoduleUpdate (
settings . fetchDepth ,
settings . nestedSubmodules
)
await git . submoduleForeach (
'git config --local gc.auto 0' ,
settings . nestedSubmodules
)
// Persist credentials
if ( settings . persistCredentials ) {
await authHelper . configureSubmoduleAuth ( )
}
} finally {
// Remove temporary global config override
await authHelper . removeGlobalAuth ( )
2019-12-12 20:49:26 +02:00
}
}
2020-03-05 21:21:59 +02:00
// Dump some info about the checked out commit
await git . log1 ( )
} finally {
// Remove auth
if ( ! settings . persistCredentials ) {
await authHelper . removeAuth ( )
}
2019-12-12 20:16:16 +02:00
}
2019-12-03 17:28:59 +02:00
}
export async function cleanup ( repositoryPath : string ) : Promise < void > {
// Repo exists?
2020-01-27 17:21:50 +02:00
if (
! repositoryPath ||
! fsHelper . fileExistsSync ( path . join ( repositoryPath , '.git' , 'config' ) )
) {
2019-12-03 17:28:59 +02:00
return
}
2020-01-27 17:21:50 +02:00
let git : IGitCommandManager
try {
2020-03-02 18:33:30 +02:00
git = await gitCommandManager . createCommandManager ( repositoryPath , false )
2020-01-27 17:21:50 +02:00
} catch {
return
}
2020-03-02 18:33:30 +02:00
// Remove auth
const authHelper = gitAuthHelper . createAuthHelper ( git )
await authHelper . removeAuth ( )
2019-12-03 17:28:59 +02:00
}
2019-12-12 20:16:16 +02:00
async function getGitCommandManager (
2020-03-02 18:33:30 +02:00
settings : IGitSourceSettings
) : Promise < IGitCommandManager | undefined > {
2019-12-12 20:16:16 +02:00
core . info ( ` Working directory is ' ${ settings . repositoryPath } ' ` )
try {
2020-03-02 18:33:30 +02:00
return await gitCommandManager . createCommandManager (
2019-12-12 20:16:16 +02:00
settings . repositoryPath ,
settings . lfs
)
} catch ( err ) {
// Git is required for LFS
if ( settings . lfs ) {
throw err
}
// Otherwise fallback to REST API
2020-03-02 18:33:30 +02:00
return undefined
2019-12-03 17:28:59 +02:00
}
}