mirror of
https://github.com/actions/checkout.git
synced 2026-03-15 10:43:28 +08:00
update reference cache even when .git already exists
This commit is contained in:
parent
9be4f3c9fd
commit
090955f4b7
182
__test__/git-source-provider-reference-cache.test.ts
Normal file
182
__test__/git-source-provider-reference-cache.test.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
const mockStartGroup = jest.fn()
|
||||||
|
const mockEndGroup = jest.fn()
|
||||||
|
const mockInfo = jest.fn()
|
||||||
|
const mockWarning = jest.fn()
|
||||||
|
const mockSetOutput = jest.fn()
|
||||||
|
const mockSetSecret = jest.fn()
|
||||||
|
|
||||||
|
const mockCreateCommandManager = jest.fn()
|
||||||
|
const mockCreateAuthHelper = jest.fn()
|
||||||
|
const mockPrepareExistingDirectory = jest.fn()
|
||||||
|
const mockGetFetchUrl = jest.fn()
|
||||||
|
const mockGetRefSpec = jest.fn()
|
||||||
|
const mockTestRef = jest.fn()
|
||||||
|
const mockGetCheckoutInfo = jest.fn()
|
||||||
|
const mockCheckCommitInfo = jest.fn()
|
||||||
|
const mockSetRepositoryPath = jest.fn()
|
||||||
|
const mockSetupCache = jest.fn()
|
||||||
|
const mockDirectoryExistsSync = jest.fn()
|
||||||
|
const mockFileExistsSync = jest.fn()
|
||||||
|
|
||||||
|
jest.mock('@actions/core', () => ({
|
||||||
|
startGroup: mockStartGroup,
|
||||||
|
endGroup: mockEndGroup,
|
||||||
|
info: mockInfo,
|
||||||
|
warning: mockWarning,
|
||||||
|
setOutput: mockSetOutput,
|
||||||
|
setSecret: mockSetSecret
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('@actions/io', () => ({
|
||||||
|
rmRF: jest.fn(),
|
||||||
|
mkdirP: jest.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/fs-helper', () => ({
|
||||||
|
directoryExistsSync: mockDirectoryExistsSync,
|
||||||
|
fileExistsSync: mockFileExistsSync
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/git-command-manager', () => ({
|
||||||
|
MinimumGitSparseCheckoutVersion: {},
|
||||||
|
createCommandManager: mockCreateCommandManager
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/git-auth-helper', () => ({
|
||||||
|
createAuthHelper: mockCreateAuthHelper
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/git-directory-helper', () => ({
|
||||||
|
prepareExistingDirectory: mockPrepareExistingDirectory
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/github-api-helper', () => ({
|
||||||
|
downloadRepository: jest.fn(),
|
||||||
|
getDefaultBranch: jest.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/ref-helper', () => ({
|
||||||
|
getRefSpec: mockGetRefSpec,
|
||||||
|
getCheckoutInfo: mockGetCheckoutInfo,
|
||||||
|
testRef: mockTestRef,
|
||||||
|
checkCommitInfo: mockCheckCommitInfo
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/state-helper', () => ({
|
||||||
|
setRepositoryPath: mockSetRepositoryPath
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/url-helper', () => ({
|
||||||
|
getFetchUrl: mockGetFetchUrl
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../src/git-cache-helper', () => ({
|
||||||
|
GitCacheHelper: jest.fn().mockImplementation(() => ({
|
||||||
|
setupCache: mockSetupCache
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
|
||||||
|
import {getSource} from '../src/git-source-provider'
|
||||||
|
|
||||||
|
describe('getSource reference cache regression', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates the reference cache and reconfigures alternates for existing repositories', async () => {
|
||||||
|
const repositoryPath = '/tmp/work/repo'
|
||||||
|
const repositoryUrl = 'https://github.com/actions/checkout'
|
||||||
|
const cachePath = '/tmp/reference-cache/actions-checkout.git'
|
||||||
|
|
||||||
|
const mockGit = {
|
||||||
|
init: jest.fn(),
|
||||||
|
remoteAdd: jest.fn(),
|
||||||
|
referenceAdd: jest.fn().mockResolvedValue(undefined),
|
||||||
|
tryDisableAutomaticGarbageCollection: jest.fn().mockResolvedValue(true),
|
||||||
|
fetch: jest.fn().mockResolvedValue(undefined),
|
||||||
|
version: jest.fn().mockResolvedValue({
|
||||||
|
checkMinimum: jest.fn().mockReturnValue(true)
|
||||||
|
}),
|
||||||
|
disableSparseCheckout: jest.fn().mockResolvedValue(undefined),
|
||||||
|
checkout: jest.fn().mockResolvedValue(undefined),
|
||||||
|
log1: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce('commit info')
|
||||||
|
.mockResolvedValueOnce('0123456789abcdef'),
|
||||||
|
lfsInstall: jest.fn(),
|
||||||
|
submoduleSync: jest.fn(),
|
||||||
|
submoduleUpdate: jest.fn(),
|
||||||
|
submoduleForeach: jest.fn(),
|
||||||
|
config: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockAuthHelper = {
|
||||||
|
configureAuth: jest.fn().mockResolvedValue(undefined),
|
||||||
|
configureGlobalAuth: jest.fn().mockResolvedValue(undefined),
|
||||||
|
configureSubmoduleAuth: jest.fn().mockResolvedValue(undefined),
|
||||||
|
configureTempGlobalConfig: jest.fn().mockResolvedValue('/tmp/gitconfig'),
|
||||||
|
removeAuth: jest.fn().mockResolvedValue(undefined),
|
||||||
|
removeGlobalAuth: jest.fn().mockResolvedValue(undefined),
|
||||||
|
removeGlobalConfig: jest.fn().mockResolvedValue(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
mockCreateCommandManager.mockResolvedValue(mockGit)
|
||||||
|
mockCreateAuthHelper.mockReturnValue(mockAuthHelper)
|
||||||
|
mockPrepareExistingDirectory.mockResolvedValue(undefined)
|
||||||
|
mockGetFetchUrl.mockReturnValue(repositoryUrl)
|
||||||
|
mockGetRefSpec.mockReturnValue(['+refs/heads/main:refs/remotes/origin/main'])
|
||||||
|
mockTestRef.mockResolvedValue(true)
|
||||||
|
mockGetCheckoutInfo.mockResolvedValue({
|
||||||
|
ref: 'refs/heads/main',
|
||||||
|
startPoint: 'refs/remotes/origin/main'
|
||||||
|
})
|
||||||
|
mockCheckCommitInfo.mockResolvedValue(undefined)
|
||||||
|
mockSetupCache.mockResolvedValue(cachePath)
|
||||||
|
mockFileExistsSync.mockReturnValue(false)
|
||||||
|
mockDirectoryExistsSync.mockImplementation((targetPath: string) => {
|
||||||
|
return (
|
||||||
|
targetPath === repositoryPath ||
|
||||||
|
targetPath === path.join(repositoryPath, '.git') ||
|
||||||
|
targetPath === path.join(cachePath, 'objects')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
await getSource({
|
||||||
|
repositoryPath,
|
||||||
|
repositoryOwner: 'actions',
|
||||||
|
repositoryName: 'checkout',
|
||||||
|
ref: 'refs/heads/main',
|
||||||
|
commit: '0123456789abcdef',
|
||||||
|
clean: false,
|
||||||
|
filter: undefined,
|
||||||
|
sparseCheckout: undefined as any,
|
||||||
|
sparseCheckoutConeMode: false,
|
||||||
|
fetchDepth: 1,
|
||||||
|
fetchDepthExplicit: true,
|
||||||
|
fetchTags: false,
|
||||||
|
showProgress: false,
|
||||||
|
referenceCache: '/tmp/reference-cache',
|
||||||
|
lfs: false,
|
||||||
|
submodules: false,
|
||||||
|
nestedSubmodules: false,
|
||||||
|
authToken: 'token',
|
||||||
|
sshKey: '',
|
||||||
|
sshKnownHosts: '',
|
||||||
|
sshStrict: true,
|
||||||
|
sshUser: 'git',
|
||||||
|
persistCredentials: false,
|
||||||
|
workflowOrganizationId: undefined,
|
||||||
|
githubServerUrl: 'https://github.com',
|
||||||
|
setSafeDirectory: false
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
expect(mockGit.init).not.toHaveBeenCalled()
|
||||||
|
expect(mockGit.remoteAdd).not.toHaveBeenCalled()
|
||||||
|
expect(mockSetupCache).toHaveBeenCalledWith(mockGit, repositoryUrl)
|
||||||
|
expect(mockGit.referenceAdd).toHaveBeenCalledWith(
|
||||||
|
path.join(cachePath, 'objects')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,5 +1,10 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {adjustFetchDepthForCache} from '../src/git-source-provider'
|
import * as fsHelper from '../src/fs-helper'
|
||||||
|
import {GitCacheHelper} from '../src/git-cache-helper'
|
||||||
|
import {
|
||||||
|
adjustFetchDepthForCache,
|
||||||
|
setupReferenceCache
|
||||||
|
} from '../src/git-source-provider'
|
||||||
|
|
||||||
// Mock @actions/core
|
// Mock @actions/core
|
||||||
jest.mock('@actions/core')
|
jest.mock('@actions/core')
|
||||||
@ -86,3 +91,73 @@ describe('adjustFetchDepthForCache', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('setupReferenceCache', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does nothing when referenceCache is not set', async () => {
|
||||||
|
const git = {
|
||||||
|
referenceAdd: jest.fn()
|
||||||
|
} as any
|
||||||
|
|
||||||
|
await setupReferenceCache(git, '', 'https://github.com/actions/checkout.git')
|
||||||
|
|
||||||
|
expect(git.referenceAdd).not.toHaveBeenCalled()
|
||||||
|
expect(core.startGroup).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates the cache and configures alternates when cache objects exist', async () => {
|
||||||
|
const git = {
|
||||||
|
referenceAdd: jest.fn().mockResolvedValue(undefined)
|
||||||
|
} as any
|
||||||
|
const setupCacheSpy = jest
|
||||||
|
.spyOn(GitCacheHelper.prototype, 'setupCache')
|
||||||
|
.mockResolvedValue('/tmp/reference-cache/repo.git')
|
||||||
|
jest
|
||||||
|
.spyOn(fsHelper, 'directoryExistsSync')
|
||||||
|
.mockReturnValue(true)
|
||||||
|
|
||||||
|
await setupReferenceCache(
|
||||||
|
git,
|
||||||
|
'/tmp/reference-cache',
|
||||||
|
'https://github.com/actions/checkout.git'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(setupCacheSpy).toHaveBeenCalledWith(
|
||||||
|
git,
|
||||||
|
'https://github.com/actions/checkout.git'
|
||||||
|
)
|
||||||
|
expect(git.referenceAdd).toHaveBeenCalledWith(
|
||||||
|
'/tmp/reference-cache/repo.git/objects'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('warns when the cache objects directory is missing', async () => {
|
||||||
|
const git = {
|
||||||
|
referenceAdd: jest.fn().mockResolvedValue(undefined)
|
||||||
|
} as any
|
||||||
|
jest
|
||||||
|
.spyOn(GitCacheHelper.prototype, 'setupCache')
|
||||||
|
.mockResolvedValue('/tmp/reference-cache/repo.git')
|
||||||
|
jest
|
||||||
|
.spyOn(fsHelper, 'directoryExistsSync')
|
||||||
|
.mockReturnValue(false)
|
||||||
|
|
||||||
|
await setupReferenceCache(
|
||||||
|
git,
|
||||||
|
'/tmp/reference-cache',
|
||||||
|
'https://github.com/actions/checkout.git'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(git.referenceAdd).not.toHaveBeenCalled()
|
||||||
|
expect(core.warning).toHaveBeenCalledWith(
|
||||||
|
'Reference repository cache objects directory /tmp/reference-cache/repo.git/objects does not exist'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@ -23,6 +23,32 @@ interface SubmoduleInfo {
|
|||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function setupReferenceCache(
|
||||||
|
git: IGitCommandManager,
|
||||||
|
referenceCache: string,
|
||||||
|
repositoryUrl: string
|
||||||
|
): Promise<void> {
|
||||||
|
if (!referenceCache) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.startGroup('Setting up reference repository cache')
|
||||||
|
try {
|
||||||
|
const cacheHelper = new GitCacheHelper(referenceCache)
|
||||||
|
const cachePath = await cacheHelper.setupCache(git, repositoryUrl)
|
||||||
|
const cacheObjects = path.join(cachePath, 'objects')
|
||||||
|
if (fsHelper.directoryExistsSync(cacheObjects, false)) {
|
||||||
|
await git.referenceAdd(cacheObjects)
|
||||||
|
} else {
|
||||||
|
core.warning(
|
||||||
|
`Reference repository cache objects directory ${cacheObjects} does not exist`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
core.endGroup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function iterativeSubmoduleUpdate(
|
async function iterativeSubmoduleUpdate(
|
||||||
git: IGitCommandManager,
|
git: IGitCommandManager,
|
||||||
cacheHelper: GitCacheHelper,
|
cacheHelper: GitCacheHelper,
|
||||||
@ -276,22 +302,10 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
|||||||
await git.init()
|
await git.init()
|
||||||
await git.remoteAdd('origin', repositoryUrl)
|
await git.remoteAdd('origin', repositoryUrl)
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
|
|
||||||
// Setup reference cache if requested
|
|
||||||
if (settings.referenceCache) {
|
|
||||||
core.startGroup('Setting up reference repository cache')
|
|
||||||
const cacheHelper = new GitCacheHelper(settings.referenceCache)
|
|
||||||
const cachePath = await cacheHelper.setupCache(git, repositoryUrl)
|
|
||||||
const cacheObjects = path.join(cachePath, 'objects')
|
|
||||||
if (fsHelper.directoryExistsSync(cacheObjects, false)) {
|
|
||||||
await git.referenceAdd(cacheObjects)
|
|
||||||
} else {
|
|
||||||
core.warning(`Reference repository cache objects directory ${cacheObjects} does not exist`)
|
|
||||||
}
|
|
||||||
core.endGroup()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await setupReferenceCache(git, settings.referenceCache, repositoryUrl)
|
||||||
|
|
||||||
// Remove global auth if it was set for reference cache,
|
// Remove global auth if it was set for reference cache,
|
||||||
// to avoid duplicate AUTHORIZATION headers during fetch
|
// to avoid duplicate AUTHORIZATION headers during fetch
|
||||||
if (settings.referenceCache) {
|
if (settings.referenceCache) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user