1
0
Fork 0
mirror of https://code.forgejo.org/actions/checkout.git synced 2025-04-27 14:29:54 +02:00

more unit tests and corresponding refactoring (#174)

This commit is contained in:
eric sciple 2020-03-02 11:33:30 -05:00 committed by GitHub
parent 096e927750
commit f219062370
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1049 additions and 305 deletions

View file

@ -1,36 +1,24 @@
import * as core from '@actions/core'
import * as fs from 'fs'
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 {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
const serverUrl = 'https://github.com/'
const authConfigKey = `http.${serverUrl}.extraheader`
const hostname = 'github.com'
export interface ISourceSettings {
repositoryPath: string
repositoryOwner: string
repositoryName: string
ref: string
commit: string
clean: boolean
fetchDepth: number
lfs: boolean
authToken: string
persistCredentials: boolean
}
export async function getSource(settings: ISourceSettings): Promise<void> {
export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Repository URL
core.info(
`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
)
const repositoryUrl = `https://github.com/${encodeURIComponent(
const repositoryUrl = `https://${hostname}/${encodeURIComponent(
settings.repositoryOwner
)}/${encodeURIComponent(settings.repositoryName)}`
@ -51,7 +39,7 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
// Prepare existing directory, otherwise recreate
if (isExisting) {
await prepareExistingDirectory(
await gitDirectoryHelper.prepareExistingDirectory(
git,
settings.repositoryPath,
repositoryUrl,
@ -92,12 +80,10 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
)
}
// Remove possible previous extraheader
await removeGitConfig(git, authConfigKey)
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
try {
// Config extraheader
await configureAuthToken(git, settings.authToken)
// Configure auth
await authHelper.configureAuth()
// LFS install
if (settings.lfs) {
@ -128,8 +114,9 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
// Dump some info about the checked out commit
await git.log1()
} finally {
// Remove auth
if (!settings.persistCredentials) {
await removeGitConfig(git, authConfigKey)
await authHelper.removeAuth()
}
}
}
@ -146,22 +133,22 @@ export async function cleanup(repositoryPath: string): Promise<void> {
let git: IGitCommandManager
try {
git = await gitCommandManager.CreateCommandManager(repositoryPath, false)
git = await gitCommandManager.createCommandManager(repositoryPath, false)
} catch {
return
}
// Remove extraheader
await removeGitConfig(git, authConfigKey)
// Remove auth
const authHelper = gitAuthHelper.createAuthHelper(git)
await authHelper.removeAuth()
}
async function getGitCommandManager(
settings: ISourceSettings
): Promise<IGitCommandManager> {
settings: IGitSourceSettings
): Promise<IGitCommandManager | undefined> {
core.info(`Working directory is '${settings.repositoryPath}'`)
let git = (null as unknown) as IGitCommandManager
try {
return await gitCommandManager.CreateCommandManager(
return await gitCommandManager.createCommandManager(
settings.repositoryPath,
settings.lfs
)
@ -172,138 +159,6 @@ async function getGitCommandManager(
}
// Otherwise fallback to REST API
return (null as unknown) as IGitCommandManager
}
}
async function prepareExistingDirectory(
git: IGitCommandManager,
repositoryPath: string,
repositoryUrl: string,
clean: boolean
): Promise<void> {
let remove = false
// Check whether using git or REST API
if (!git) {
remove = true
}
// Fetch URL does not match
else if (
!fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) ||
repositoryUrl !== (await git.tryGetFetchUrl())
) {
remove = true
} else {
// Delete any index.lock and shallow.lock left by a previously canceled run or crashed git process
const lockPaths = [
path.join(repositoryPath, '.git', 'index.lock'),
path.join(repositoryPath, '.git', 'shallow.lock')
]
for (const lockPath of lockPaths) {
try {
await io.rmRF(lockPath)
} catch (error) {
core.debug(`Unable to delete '${lockPath}'. ${error.message}`)
}
}
try {
// Checkout detached HEAD
if (!(await git.isDetached())) {
await git.checkoutDetach()
}
// Remove all refs/heads/*
let branches = await git.branchList(false)
for (const branch of branches) {
await git.branchDelete(false, branch)
}
// Remove all refs/remotes/origin/* to avoid conflicts
branches = await git.branchList(true)
for (const branch of branches) {
await git.branchDelete(true, branch)
}
// Clean
if (clean) {
if (!(await git.tryClean())) {
core.debug(
`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
)
remove = true
} else if (!(await git.tryReset())) {
remove = true
}
if (remove) {
core.warning(
`Unable to clean or reset the repository. The repository will be recreated instead.`
)
}
}
} catch (error) {
core.warning(
`Unable to prepare the existing repository. The repository will be recreated instead.`
)
remove = true
}
}
if (remove) {
// Delete the contents of the directory. Don't delete the directory itself
// since it might be the current working directory.
core.info(`Deleting the contents of '${repositoryPath}'`)
for (const file of await fs.promises.readdir(repositoryPath)) {
await io.rmRF(path.join(repositoryPath, file))
}
}
}
async function configureAuthToken(
git: IGitCommandManager,
authToken: string
): Promise<void> {
// Configure a placeholder value. This approach avoids the credential being captured
// by process creation audit events, which are commonly logged. For more information,
// refer to https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
const placeholder = `AUTHORIZATION: basic ***`
await git.config(authConfigKey, placeholder)
// Determine the basic credential value
const basicCredential = Buffer.from(
`x-access-token:${authToken}`,
'utf8'
).toString('base64')
core.setSecret(basicCredential)
// Replace the value in the config file
const configPath = path.join(git.getWorkingDirectory(), '.git', 'config')
let content = (await fs.promises.readFile(configPath)).toString()
const placeholderIndex = content.indexOf(placeholder)
if (
placeholderIndex < 0 ||
placeholderIndex != content.lastIndexOf(placeholder)
) {
throw new Error('Unable to replace auth placeholder in .git/config')
}
content = content.replace(
placeholder,
`AUTHORIZATION: basic ${basicCredential}`
)
await fs.promises.writeFile(configPath, content)
}
async function removeGitConfig(
git: IGitCommandManager,
configKey: string
): Promise<void> {
if (
(await git.configExists(configKey)) &&
!(await git.tryConfigUnset(configKey))
) {
// Load the config contents
core.warning(`Failed to remove '${configKey}' from the git config`)
return undefined
}
}