2020-03-02 19:33:30 +03:00
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
2020-05-27 16:54:28 +03:00
let ref : string
2020-03-02 19:33:30 +03:00
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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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' )
} )
2023-04-14 13:26:47 +03:00
const cleanWhenSubmoduleStatusIsFalse =
'cleans when submodule status is false'
it ( cleanWhenSubmoduleStatusIsFalse , async ( ) = > {
// Arrange
await setup ( cleanWhenSubmoduleStatusIsFalse )
await fs . promises . writeFile ( path . join ( repositoryPath , 'my-file' ) , '' )
//mock bad submodule
const submoduleStatus = git . submoduleStatus as jest . Mock < any , any >
submoduleStatus . mockImplementation ( async ( remote : boolean ) = > {
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 ( )
} )
const doesNotCleanWhenSubmoduleStatusIsTrue =
'does not clean when submodule status is true'
it ( doesNotCleanWhenSubmoduleStatusIsTrue , async ( ) = > {
// Arrange
await setup ( doesNotCleanWhenSubmoduleStatusIsTrue )
await fs . promises . writeFile ( path . join ( repositoryPath , 'my-file' ) , '' )
const submoduleStatus = git . submoduleStatus as jest . Mock < any , any >
submoduleStatus . mockImplementation ( async ( remote : boolean ) = > {
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 . tryClean ) . toHaveBeenCalled ( )
} )
2020-03-02 19:33:30 +03:00
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 ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// 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 ( )
} )
2020-05-27 16:54:28 +03:00
const removesAncestorRemoteBranch = 'removes ancestor remote branch'
it ( removesAncestorRemoteBranch , async ( ) = > {
2020-03-02 19:33:30 +03:00
// Arrange
2020-05-27 16:54:28 +03:00
await setup ( removesAncestorRemoteBranch )
2020-03-02 19:33:30 +03:00
await fs . promises . writeFile ( path . join ( repositoryPath , 'my-file' ) , '' )
const mockBranchList = git . branchList as jest . Mock < any , any >
mockBranchList . mockImplementation ( async ( remote : boolean ) = > {
2020-05-27 16:54:28 +03:00
return remote ? [ 'origin/remote-branch-1' , 'origin/remote-branch-2' ] : [ ]
2020-03-02 19:33:30 +03:00
} )
2020-05-27 16:54:28 +03:00
ref = 'remote-branch-1/conflict'
2020-03-02 19:33:30 +03:00
// Act
await gitDirectoryHelper . prepareExistingDirectory (
git ,
repositoryPath ,
repositoryUrl ,
2020-05-27 16:54:28 +03:00
clean ,
ref
2020-03-02 19:33:30 +03:00
)
// Assert
const files = await fs . promises . readdir ( repositoryPath )
expect ( files . sort ( ) ) . toEqual ( [ '.git' , 'my-file' ] )
2020-05-27 16:54:28 +03:00
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'
)
2020-03-02 19:33:30 +03:00
} )
} )
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
2020-05-27 16:54:28 +03:00
// Ref
ref = ''
2020-03-02 19:33:30 +03:00
// Git command manager
git = {
branchDelete : jest.fn ( ) ,
branchExists : jest.fn ( ) ,
branchList : jest.fn ( async ( ) = > {
return [ ]
} ) ,
2024-02-21 15:56:19 +03:00
disableSparseCheckout : jest.fn ( ) ,
2023-06-09 16:08:21 +03:00
sparseCheckout : jest.fn ( ) ,
sparseCheckoutNonConeMode : jest.fn ( ) ,
2020-03-02 19:33:30 +03:00
checkout : jest.fn ( ) ,
checkoutDetach : jest.fn ( ) ,
config : jest.fn ( ) ,
configExists : jest.fn ( ) ,
fetch : jest.fn ( ) ,
2020-06-18 17:20:33 +03:00
getDefaultBranch : jest.fn ( ) ,
2020-03-02 19:33:30 +03:00
getWorkingDirectory : jest.fn ( ( ) = > repositoryPath ) ,
init : jest.fn ( ) ,
isDetached : jest.fn ( ) ,
lfsFetch : jest.fn ( ) ,
lfsInstall : jest.fn ( ) ,
log1 : jest.fn ( ) ,
remoteAdd : jest.fn ( ) ,
2020-03-05 22:21:59 +03:00
removeEnvironmentVariable : jest.fn ( ) ,
2020-05-27 16:54:28 +03:00
revParse : jest.fn ( ) ,
2020-03-02 19:33:30 +03:00
setEnvironmentVariable : jest.fn ( ) ,
2020-05-27 16:54:28 +03:00
shaExists : jest.fn ( ) ,
2020-03-05 22:21:59 +03:00
submoduleForeach : jest.fn ( ) ,
submoduleSync : jest.fn ( ) ,
submoduleUpdate : jest.fn ( ) ,
2023-04-14 13:26:47 +03:00
submoduleStatus : jest.fn ( async ( ) = > {
return true
} ) ,
2020-03-02 19:33:30 +03:00
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
2024-03-14 17:40:14 +03:00
} ) ,
version : jest.fn ( )
2020-03-02 19:33:30 +03:00
}
}