checkout/src/git-source-provider.ts

251 lines
7.4 KiB
TypeScript
Raw Normal View History

import * as core from '@actions/core'
import * as fsHelper from './fs-helper'
import * as gitAuthHelper from './git-auth-helper'
import * as gitCommandManager from './git-command-manager'
import * as gitDirectoryHelper from './git-directory-helper'
import * as githubApiHelper from './github-api-helper'
import * as io from '@actions/io'
import * as path from 'path'
import * as refHelper from './ref-helper'
import * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Repository URL
core.info(
`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
)
const repositoryUrl = urlHelper.getFetchUrl(settings)
// 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
2020-03-28 01:12:15 +08:00
core.startGroup('Getting Git version info')
const git = await getGitCommandManager(settings)
2020-03-28 01:12:15 +08:00
core.endGroup()
// Prepare existing directory, otherwise recreate
if (isExisting) {
await gitDirectoryHelper.prepareExistingDirectory(
git,
settings.repositoryPath,
repositoryUrl,
settings.clean,
settings.ref
)
}
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`
)
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.`
)
}
await githubApiHelper.downloadRepository(
2019-12-13 02:49:26 +08:00
settings.authToken,
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
settings.commit,
settings.repositoryPath
)
2020-03-06 03:21:59 +08:00
return
}
2020-03-06 03:21:59 +08:00
// Save state for POST action
stateHelper.setRepositoryPath(settings.repositoryPath)
2020-03-06 03:21:59 +08:00
// Initialize the repository
if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) {
2020-03-28 01:12:15 +08:00
core.startGroup('Initializing the repository')
2020-03-06 03:21:59 +08:00
await git.init()
await git.remoteAdd('origin', repositoryUrl)
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
}
2020-03-06 03:21:59 +08:00
// Disable automatic garbage collection
2020-03-28 01:12:15 +08:00
core.startGroup('Disabling automatic garbage collection')
2020-03-06 03:21:59 +08:00
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.`
)
}
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
try {
// Configure auth
2020-03-28 01:12:15 +08:00
core.startGroup('Setting up auth')
2020-03-06 03:21:59 +08:00
await authHelper.configureAuth()
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
// LFS install
if (settings.lfs) {
await git.lfsInstall()
}
// Fetch
2020-03-28 01:12:15 +08:00
core.startGroup('Fetching the repository')
if (settings.fetchDepth <= 0) {
// Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory(
settings.ref,
settings.commit
)
await git.fetch(refSpec)
// When all history is fetched, the ref we're interested in may have moved to a different
// commit (push or force push). If so, fetch again with a targeted refspec.
if (!(await refHelper.testRef(git, settings.ref, settings.commit))) {
refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(refSpec)
}
} else {
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(refSpec, settings.fetchDepth)
}
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
// Checkout info
2020-03-28 01:12:15 +08:00
core.startGroup('Determining the checkout info')
2020-03-06 03:21:59 +08:00
const checkoutInfo = await refHelper.getCheckoutInfo(
git,
settings.ref,
settings.commit
)
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
// 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) {
2020-03-28 01:12:15 +08:00
core.startGroup('Fetching LFS objects')
2020-03-06 03:21:59 +08:00
await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
}
2020-03-06 03:21:59 +08:00
// Checkout
2020-03-28 01:12:15 +08:00
core.startGroup('Checking out the ref')
2020-03-06 03:21:59 +08:00
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
// Submodules
if (settings.submodules) {
try {
// Temporarily override global config
2020-03-28 01:12:15 +08:00
core.startGroup('Setting up auth for fetching submodules')
2020-03-06 03:21:59 +08:00
await authHelper.configureGlobalAuth()
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
// Checkout submodules
2020-03-28 01:12:15 +08:00
core.startGroup('Fetching submodules')
2020-03-06 03:21:59 +08:00
await git.submoduleSync(settings.nestedSubmodules)
await git.submoduleUpdate(
settings.fetchDepth,
settings.nestedSubmodules
)
await git.submoduleForeach(
'git config --local gc.auto 0',
settings.nestedSubmodules
)
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
// Persist credentials
if (settings.persistCredentials) {
2020-03-28 01:12:15 +08:00
core.startGroup('Persisting credentials for submodules')
2020-03-06 03:21:59 +08:00
await authHelper.configureSubmoduleAuth()
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
}
} finally {
// Remove temporary global config override
await authHelper.removeGlobalAuth()
2019-12-13 02:49:26 +08:00
}
}
2020-03-06 03:21:59 +08:00
// Dump some info about the checked out commit
const commitInfo = await git.log1()
// Check for incorrect pull request merge commit
await refHelper.checkCommitInfo(
settings.authToken,
commitInfo,
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
settings.commit
)
2020-03-06 03:21:59 +08:00
} finally {
// Remove auth
if (!settings.persistCredentials) {
2020-03-28 01:12:15 +08:00
core.startGroup('Removing auth')
2020-03-06 03:21:59 +08:00
await authHelper.removeAuth()
2020-03-28 01:12:15 +08:00
core.endGroup()
2020-03-06 03:21:59 +08:00
}
}
}
export async function cleanup(repositoryPath: string): Promise<void> {
// Repo exists?
2020-01-27 23:21:50 +08:00
if (
!repositoryPath ||
!fsHelper.fileExistsSync(path.join(repositoryPath, '.git', 'config'))
) {
return
}
2020-01-27 23:21:50 +08:00
let git: IGitCommandManager
try {
git = await gitCommandManager.createCommandManager(repositoryPath, false)
2020-01-27 23:21:50 +08:00
} catch {
return
}
// Remove auth
const authHelper = gitAuthHelper.createAuthHelper(git)
await authHelper.removeAuth()
}
async function getGitCommandManager(
settings: IGitSourceSettings
): Promise<IGitCommandManager | undefined> {
core.info(`Working directory is '${settings.repositoryPath}'`)
try {
return await gitCommandManager.createCommandManager(
settings.repositoryPath,
settings.lfs
)
} catch (err) {
// Git is required for LFS
if (settings.lfs) {
throw err
}
// Otherwise fallback to REST API
return undefined
}
}