123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- import * as core from '@actions/core'
- import * as fs from 'fs'
- import * as gitDirectoryHelper from '../lib/git-directory-helper'
- import * as io from '@actions/io'
- import * as path from 'path'
- import {IGitCommandManager} from '../lib/git-command-manager'
- const testWorkspace = path.join(__dirname, '_temp', 'git-directory-helper')
- let repositoryPath: string
- let repositoryUrl: string
- let clean: boolean
- let ref: string
- let git: IGitCommandManager
- describe('git-directory-helper tests', () => {
- beforeAll(async () => {
- // Clear test workspace
- await io.rmRF(testWorkspace)
- })
- beforeEach(() => {
- // Mock error/warning/info/debug
- jest.spyOn(core, 'error').mockImplementation(jest.fn())
- jest.spyOn(core, 'warning').mockImplementation(jest.fn())
- jest.spyOn(core, 'info').mockImplementation(jest.fn())
- jest.spyOn(core, 'debug').mockImplementation(jest.fn())
- })
- afterEach(() => {
- // Unregister mocks
- jest.restoreAllMocks()
- })
- const cleansWhenCleanTrue = 'cleans when clean true'
- it(cleansWhenCleanTrue, async () => {
- // Arrange
- await setup(cleansWhenCleanTrue)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.tryClean).toHaveBeenCalled()
- expect(git.tryReset).toHaveBeenCalled()
- expect(core.warning).not.toHaveBeenCalled()
- })
- const checkoutDetachWhenNotDetached = 'checkout detach when not detached'
- it(checkoutDetachWhenNotDetached, async () => {
- // Arrange
- await setup(checkoutDetachWhenNotDetached)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.checkoutDetach).toHaveBeenCalled()
- })
- const doesNotCheckoutDetachWhenNotAlreadyDetached =
- 'does not checkout detach when already detached'
- it(doesNotCheckoutDetachWhenNotAlreadyDetached, async () => {
- // Arrange
- await setup(doesNotCheckoutDetachWhenNotAlreadyDetached)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- const mockIsDetached = git.isDetached as jest.Mock<any, any>
- mockIsDetached.mockImplementation(async () => {
- return true
- })
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.checkoutDetach).not.toHaveBeenCalled()
- })
- const doesNotCleanWhenCleanFalse = 'does not clean when clean false'
- it(doesNotCleanWhenCleanFalse, async () => {
- // Arrange
- await setup(doesNotCleanWhenCleanFalse)
- clean = false
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.isDetached).toHaveBeenCalled()
- expect(git.branchList).toHaveBeenCalled()
- expect(core.warning).not.toHaveBeenCalled()
- expect(git.tryClean).not.toHaveBeenCalled()
- expect(git.tryReset).not.toHaveBeenCalled()
- })
- const removesContentsWhenCleanFails = 'removes contents when clean fails'
- it(removesContentsWhenCleanFails, async () => {
- // Arrange
- await setup(removesContentsWhenCleanFails)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- let mockTryClean = git.tryClean as jest.Mock<any, any>
- mockTryClean.mockImplementation(async () => {
- return false
- })
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files).toHaveLength(0)
- expect(git.tryClean).toHaveBeenCalled()
- expect(core.warning).toHaveBeenCalled()
- expect(git.tryReset).not.toHaveBeenCalled()
- })
- const removesContentsWhenDifferentRepositoryUrl =
- 'removes contents when different repository url'
- it(removesContentsWhenDifferentRepositoryUrl, async () => {
- // Arrange
- await setup(removesContentsWhenDifferentRepositoryUrl)
- clean = false
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- const differentRepositoryUrl =
- 'https://github.com/my-different-org/my-different-repo'
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- differentRepositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files).toHaveLength(0)
- expect(core.warning).not.toHaveBeenCalled()
- expect(git.isDetached).not.toHaveBeenCalled()
- })
- const removesContentsWhenNoGitDirectory =
- 'removes contents when no git directory'
- it(removesContentsWhenNoGitDirectory, async () => {
- // Arrange
- await setup(removesContentsWhenNoGitDirectory)
- clean = false
- await io.rmRF(path.join(repositoryPath, '.git'))
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files).toHaveLength(0)
- expect(core.warning).not.toHaveBeenCalled()
- expect(git.isDetached).not.toHaveBeenCalled()
- })
- const removesContentsWhenResetFails = 'removes contents when reset fails'
- it(removesContentsWhenResetFails, async () => {
- // Arrange
- await setup(removesContentsWhenResetFails)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- let mockTryReset = git.tryReset as jest.Mock<any, any>
- mockTryReset.mockImplementation(async () => {
- return false
- })
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files).toHaveLength(0)
- expect(git.tryClean).toHaveBeenCalled()
- expect(git.tryReset).toHaveBeenCalled()
- expect(core.warning).toHaveBeenCalled()
- })
- const removesContentsWhenUndefinedGitCommandManager =
- 'removes contents when undefined git command manager'
- it(removesContentsWhenUndefinedGitCommandManager, async () => {
- // Arrange
- await setup(removesContentsWhenUndefinedGitCommandManager)
- clean = false
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- undefined,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files).toHaveLength(0)
- expect(core.warning).not.toHaveBeenCalled()
- })
- const removesLocalBranches = 'removes local branches'
- it(removesLocalBranches, async () => {
- // Arrange
- await setup(removesLocalBranches)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- const mockBranchList = git.branchList as jest.Mock<any, any>
- mockBranchList.mockImplementation(async (remote: boolean) => {
- return remote ? [] : ['local-branch-1', 'local-branch-2']
- })
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.branchDelete).toHaveBeenCalledWith(false, 'local-branch-1')
- expect(git.branchDelete).toHaveBeenCalledWith(false, 'local-branch-2')
- })
- const removesLockFiles = 'removes lock files'
- it(removesLockFiles, async () => {
- // Arrange
- await setup(removesLockFiles)
- clean = false
- await fs.promises.writeFile(
- path.join(repositoryPath, '.git', 'index.lock'),
- ''
- )
- await fs.promises.writeFile(
- path.join(repositoryPath, '.git', 'shallow.lock'),
- ''
- )
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- let files = await fs.promises.readdir(path.join(repositoryPath, '.git'))
- expect(files).toHaveLength(0)
- files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.isDetached).toHaveBeenCalled()
- expect(git.branchList).toHaveBeenCalled()
- expect(core.warning).not.toHaveBeenCalled()
- expect(git.tryClean).not.toHaveBeenCalled()
- expect(git.tryReset).not.toHaveBeenCalled()
- })
- const removesAncestorRemoteBranch = 'removes ancestor remote branch'
- it(removesAncestorRemoteBranch, async () => {
- // Arrange
- await setup(removesAncestorRemoteBranch)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- const mockBranchList = git.branchList as jest.Mock<any, any>
- mockBranchList.mockImplementation(async (remote: boolean) => {
- return remote ? ['origin/remote-branch-1', 'origin/remote-branch-2'] : []
- })
- ref = 'remote-branch-1/conflict'
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.branchDelete).toHaveBeenCalledTimes(1)
- expect(git.branchDelete).toHaveBeenCalledWith(
- true,
- 'origin/remote-branch-1'
- )
- })
- const removesDescendantRemoteBranches = 'removes descendant remote branch'
- it(removesDescendantRemoteBranches, async () => {
- // Arrange
- await setup(removesDescendantRemoteBranches)
- await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
- const mockBranchList = git.branchList as jest.Mock<any, any>
- mockBranchList.mockImplementation(async (remote: boolean) => {
- return remote
- ? ['origin/remote-branch-1/conflict', 'origin/remote-branch-2']
- : []
- })
- ref = 'remote-branch-1'
- // Act
- await gitDirectoryHelper.prepareExistingDirectory(
- git,
- repositoryPath,
- repositoryUrl,
- clean,
- ref
- )
- // Assert
- const files = await fs.promises.readdir(repositoryPath)
- expect(files.sort()).toEqual(['.git', 'my-file'])
- expect(git.branchDelete).toHaveBeenCalledTimes(1)
- expect(git.branchDelete).toHaveBeenCalledWith(
- true,
- 'origin/remote-branch-1/conflict'
- )
- })
- })
- async function setup(testName: string): Promise<void> {
- testName = testName.replace(/[^a-zA-Z0-9_]+/g, '-')
- // Repository directory
- repositoryPath = path.join(testWorkspace, testName)
- await fs.promises.mkdir(path.join(repositoryPath, '.git'), {recursive: true})
- // Repository URL
- repositoryUrl = 'https://github.com/my-org/my-repo'
- // Clean
- clean = true
- // Ref
- ref = ''
- // Git command manager
- git = {
- branchDelete: jest.fn(),
- branchExists: jest.fn(),
- branchList: jest.fn(async () => {
- return []
- }),
- checkout: jest.fn(),
- checkoutDetach: jest.fn(),
- config: jest.fn(),
- configExists: jest.fn(),
- fetch: jest.fn(),
- getDefaultBranch: jest.fn(),
- getWorkingDirectory: jest.fn(() => repositoryPath),
- init: jest.fn(),
- isDetached: jest.fn(),
- lfsFetch: jest.fn(),
- lfsInstall: jest.fn(),
- log1: jest.fn(),
- remoteAdd: jest.fn(),
- removeEnvironmentVariable: jest.fn(),
- revParse: jest.fn(),
- setEnvironmentVariable: jest.fn(),
- shaExists: jest.fn(),
- submoduleForeach: jest.fn(),
- submoduleSync: jest.fn(),
- submoduleUpdate: jest.fn(),
- tagExists: jest.fn(),
- tryClean: jest.fn(async () => {
- return true
- }),
- tryConfigUnset: jest.fn(),
- tryDisableAutomaticGarbageCollection: jest.fn(),
- tryGetFetchUrl: jest.fn(async () => {
- // Sanity check - this function shouldn't be called when the .git directory doesn't exist
- await fs.promises.stat(path.join(repositoryPath, '.git'))
- return repositoryUrl
- }),
- tryReset: jest.fn(async () => {
- return true
- })
- }
- }
|