3
0
Fork 0
mirror of https://code.forgejo.org/actions/checkout.git synced 2025-04-23 20:05:33 +00:00

fallback to REST API to download repo

This commit is contained in:
eric sciple 2019-12-09 16:54:42 -05:00
parent 5881116d18
commit ad6dd29a96
6 changed files with 666 additions and 729 deletions

View file

@ -6,6 +6,7 @@ import * as gitCommandManager from './git-command-manager'
import * as io from '@actions/io'
import * as path from 'path'
import * as refHelper from './ref-helper'
import * as repositoryApiHelper from './repository-api-helper'
import {IGitCommandManager} from './git-command-manager'
const authConfigKey = `http.https://github.com/.extraheader`
@ -23,6 +24,7 @@ export interface ISourceSettings {
}
export async function getSource(settings: ISourceSettings): Promise<void> {
// Repository URL
core.info(
`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
)
@ -30,6 +32,13 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
settings.repositoryOwner
)}/${encodeURIComponent(settings.repositoryName)}`
// Set intra-task state for cleanup
coreCommand.issueCommand(
'save-state',
{name: 'repositoryPath'},
settings.repositoryPath
)
// Remove conflicting file path
if (fsHelper.fileExistsSync(settings.repositoryPath)) {
await io.rmRF(settings.repositoryPath)
@ -44,91 +53,96 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
// Git command manager
core.info(`Working directory is '${settings.repositoryPath}'`)
const git = await gitCommandManager.CreateCommandManager(
settings.repositoryPath,
settings.lfs
)
let git = (null as unknown) as IGitCommandManager
try {
git = await gitCommandManager.CreateCommandManager(
settings.repositoryPath,
settings.lfs
)
} catch (err) {
// Git is required for LFS
if (settings.lfs) {
throw err
}
// Try prepare existing directory, otherwise recreate
if (
isExisting &&
!(await tryPrepareExistingDirectory(
// Otherwise fallback to REST API
}
// Prepare existing directory, otherwise recreate
if (isExisting) {
await prepareExistingDirectory(
git,
settings.repositoryPath,
repositoryUrl,
settings.clean
))
) {
// Delete the contents of the directory. Don't delete the directory itself
// since it may be the current working directory.
core.info(`Deleting the contents of '${settings.repositoryPath}'`)
for (const file of await fs.promises.readdir(settings.repositoryPath)) {
await io.rmRF(path.join(settings.repositoryPath, file))
}
}
// Initialize the repository
if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) {
await git.init()
await git.remoteAdd('origin', repositoryUrl)
}
// 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.`
)
}
// Remove possible previous extraheader
await removeGitConfig(git, authConfigKey)
if (!git || `${1}` == '1') {
await repositoryApiHelper.download(
settings.accessToken,
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
settings.repositoryPath
)
} else {
// Initialize the repository
if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) {
await git.init()
await git.remoteAdd('origin', repositoryUrl)
}
// Add extraheader (auth)
const base64Credentials = Buffer.from(
`x-access-token:${settings.accessToken}`,
'utf8'
).toString('base64')
core.setSecret(base64Credentials)
const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`
await git.config(authConfigKey, authConfigValue)
// 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.`
)
}
// LFS install
if (settings.lfs) {
await git.lfsInstall()
// Remove possible previous extraheader
await removeGitConfig(git, authConfigKey)
// Add extraheader (auth)
const base64Credentials = Buffer.from(
`x-access-token:${settings.accessToken}`,
'utf8'
).toString('base64')
core.setSecret(base64Credentials)
const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`
await git.config(authConfigKey, authConfigValue)
// 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)
}
// Checkout
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
// Dump some info about the checked out commit
await git.log1()
}
// 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)
}
// Checkout
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
// Dump some info about the checked out commit
await git.log1()
// Set intra-task state for cleanup
coreCommand.issueCommand(
'save-state',
{name: 'repositoryPath'},
settings.repositoryPath
)
}
export async function cleanup(repositoryPath: string): Promise<void> {
@ -146,79 +160,89 @@ export async function cleanup(repositoryPath: string): Promise<void> {
await removeGitConfig(git, authConfigKey)
}
async function tryPrepareExistingDirectory(
async function prepareExistingDirectory(
git: IGitCommandManager,
repositoryPath: string,
repositoryUrl: string,
clean: boolean
): Promise<boolean> {
): Promise<void> {
let remove = false
// Check whether using git or REST API
if (!git) {
remove = true
}
// Fetch URL does not match
if (
else if (
!fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) ||
repositoryUrl !== (await git.tryGetFetchUrl())
) {
return false
}
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}`)
}
}
// 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)
// 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.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)
}
} catch (error) {
core.warning(
`Unable to prepare the existing repository. The repository will be recreated instead.`
)
return false
}
// Clean
if (clean) {
let succeeded = true
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}'.`
)
succeeded = false
} else if (!(await git.tryReset())) {
succeeded = false
}
if (!succeeded) {
core.warning(
`Unable to clean or reset the repository. The repository will be recreated instead.`
`Unable to prepare the existing repository. The repository will be recreated instead.`
)
remove = true
}
return succeeded
}
return 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 removeGitConfig(

View file

@ -0,0 +1,24 @@
import * as github from '@actions/github'
import {ReposGetArchiveLinkParams} from '@octokit/rest'
const IS_WINDOWS = process.platform === 'win32'
export async function download(
accessToken: string,
owner: string,
repo: string,
ref: string,
repositoryPath: string
): Promise<void> {
const octokit = new github.GitHub(accessToken)
const params: ReposGetArchiveLinkParams = {
archive_format: IS_WINDOWS ? 'zipball' : 'tarball',
owner: owner,
repo: repo,
ref: ref
}
const response = await octokit.repos.getArchiveLink(params)
console.log(`status=${response.status}`)
console.log(`headers=${JSON.stringify(response.headers)}`)
console.log(`data=${JSON.stringify(response.data)}`)
}