2021-06-16 08:52:44 +02:00
import * as core from '@actions/core' ;
2022-03-31 21:10:37 +02:00
import * as cache from '@actions/cache' ;
2021-06-16 08:52:44 +02:00
import path from 'path' ;
import * as utils from '../src/cache-utils' ;
2023-06-21 17:52:17 +02:00
import {
PackageManagerInfo ,
isCacheFeatureAvailable ,
supportedPackageManagers ,
2024-10-21 18:41:32 +02:00
isGhes ,
2023-06-27 13:07:43 +02:00
resetProjectDirectoriesMemoized
2023-06-21 17:52:17 +02:00
} from '../src/cache-utils' ;
import fs from 'fs' ;
import * as cacheUtils from '../src/cache-utils' ;
import * as glob from '@actions/glob' ;
import { Globber } from '@actions/glob' ;
import { MockGlobber } from './mock/glob-mock' ;
2021-06-16 08:52:44 +02:00
describe ( 'cache-utils' , ( ) = > {
const versionYarn1 = '1.2.3' ;
let debugSpy : jest.SpyInstance ;
let getCommandOutputSpy : jest.SpyInstance ;
2022-03-31 21:10:37 +02:00
let isFeatureAvailable : jest.SpyInstance ;
let info : jest.SpyInstance ;
let warningSpy : jest.SpyInstance ;
2023-07-13 14:06:23 +02:00
let fsRealPathSyncSpy : jest.SpyInstance ;
2021-06-16 08:52:44 +02:00
beforeEach ( ( ) = > {
2023-07-13 14:06:23 +02:00
console . log ( '::stop-commands::stoptoken' ) ;
2021-06-16 08:52:44 +02:00
process . env [ 'GITHUB_WORKSPACE' ] = path . join ( __dirname , 'data' ) ;
debugSpy = jest . spyOn ( core , 'debug' ) ;
debugSpy . mockImplementation ( msg = > { } ) ;
2022-03-31 21:10:37 +02:00
info = jest . spyOn ( core , 'info' ) ;
warningSpy = jest . spyOn ( core , 'warning' ) ;
isFeatureAvailable = jest . spyOn ( cache , 'isFeatureAvailable' ) ;
2021-06-16 08:52:44 +02:00
getCommandOutputSpy = jest . spyOn ( utils , 'getCommandOutput' ) ;
2023-07-13 14:06:23 +02:00
fsRealPathSyncSpy = jest . spyOn ( fs , 'realpathSync' ) ;
fsRealPathSyncSpy . mockImplementation ( dirName = > {
return dirName ;
} ) ;
} ) ;
afterEach ( ( ) = > {
jest . resetAllMocks ( ) ;
jest . clearAllMocks ( ) ;
//jest.restoreAllMocks();
2021-06-16 08:52:44 +02:00
} ) ;
2023-07-13 14:06:23 +02:00
afterAll ( async ( ) = > {
console . log ( '::stoptoken::' ) ;
jest . restoreAllMocks ( ) ;
} , 100000 ) ;
2021-06-16 08:52:44 +02:00
describe ( 'getPackageManagerInfo' , ( ) = > {
2021-06-29 12:34:35 +02:00
it . each < [ string , PackageManagerInfo | null ] > ( [
2021-06-16 08:52:44 +02:00
[ 'npm' , utils . supportedPackageManagers . npm ] ,
2021-06-30 17:44:51 +02:00
[ 'pnpm' , utils . supportedPackageManagers . pnpm ] ,
2023-06-21 17:52:17 +02:00
[ 'yarn' , utils . supportedPackageManagers . yarn ] ,
2021-06-16 08:52:44 +02:00
[ 'yarn1' , null ] ,
[ 'yarn2' , null ] ,
[ 'npm7' , null ]
] ) ( 'getPackageManagerInfo for %s is %o' , async ( packageManager , result ) = > {
getCommandOutputSpy . mockImplementationOnce ( ( ) = > versionYarn1 ) ;
await expect ( utils . getPackageManagerInfo ( packageManager ) ) . resolves . toBe (
result
) ;
} ) ;
} ) ;
2022-03-31 21:10:37 +02:00
it ( 'isCacheFeatureAvailable for GHES is false' , ( ) = > {
isFeatureAvailable . mockImplementation ( ( ) = > false ) ;
process . env [ 'GITHUB_SERVER_URL' ] = 'https://www.test.com' ;
2022-12-09 12:05:59 +01:00
expect ( isCacheFeatureAvailable ( ) ) . toBeFalsy ( ) ;
expect ( warningSpy ) . toHaveBeenCalledWith (
2022-03-31 21:10:37 +02:00
'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.'
) ;
} ) ;
it ( 'isCacheFeatureAvailable for GHES has an interhal error' , ( ) = > {
isFeatureAvailable . mockImplementation ( ( ) = > false ) ;
process . env [ 'GITHUB_SERVER_URL' ] = '' ;
isCacheFeatureAvailable ( ) ;
expect ( warningSpy ) . toHaveBeenCalledWith (
'The runner was not able to contact the cache service. Caching will be skipped'
) ;
} ) ;
it ( 'isCacheFeatureAvailable for GHES is available' , ( ) = > {
isFeatureAvailable . mockImplementation ( ( ) = > true ) ;
expect ( isCacheFeatureAvailable ( ) ) . toStrictEqual ( true ) ;
} ) ;
2021-06-16 08:52:44 +02:00
afterEach ( ( ) = > {
2022-03-31 21:10:37 +02:00
process . env [ 'GITHUB_SERVER_URL' ] = '' ;
2021-06-16 08:52:44 +02:00
jest . resetAllMocks ( ) ;
jest . clearAllMocks ( ) ;
} ) ;
2023-06-21 17:52:17 +02:00
describe ( 'getCacheDirectoriesPaths' , ( ) = > {
let existsSpy : jest.SpyInstance ;
let lstatSpy : jest.SpyInstance ;
let globCreateSpy : jest.SpyInstance ;
beforeEach ( ( ) = > {
existsSpy = jest . spyOn ( fs , 'existsSync' ) ;
existsSpy . mockImplementation ( ( ) = > true ) ;
lstatSpy = jest . spyOn ( fs , 'lstatSync' ) ;
lstatSpy . mockImplementation ( arg = > ( {
isDirectory : ( ) = > true
} ) ) ;
globCreateSpy = jest . spyOn ( glob , 'create' ) ;
globCreateSpy . mockImplementation (
( pattern : string ) : Promise < Globber > = >
MockGlobber . create ( [ '/foo' , '/bar' ] )
) ;
2023-06-27 13:07:43 +02:00
resetProjectDirectoriesMemoized ( ) ;
2023-06-21 17:52:17 +02:00
} ) ;
afterEach ( ( ) = > {
existsSpy . mockRestore ( ) ;
lstatSpy . mockRestore ( ) ;
globCreateSpy . mockRestore ( ) ;
} ) ;
it . each ( [
[ supportedPackageManagers . npm , '' ] ,
[ supportedPackageManagers . npm , '/dir/file.lock' ] ,
[ supportedPackageManagers . npm , '/**/file.lock' ] ,
[ supportedPackageManagers . pnpm , '' ] ,
[ supportedPackageManagers . pnpm , '/dir/file.lock' ] ,
[ supportedPackageManagers . pnpm , '/**/file.lock' ]
] ) (
'getCacheDirectoriesPaths should return one dir for non yarn' ,
async ( packageManagerInfo , cacheDependency ) = > {
getCommandOutputSpy . mockImplementation ( ( ) = > 'foo' ) ;
const dirs = await cacheUtils . getCacheDirectories (
packageManagerInfo ,
cacheDependency
) ;
expect ( dirs ) . toEqual ( [ 'foo' ] ) ;
// to do not call for a version
// call once for get cache folder
expect ( getCommandOutputSpy ) . toHaveBeenCalledTimes ( 1 ) ;
}
) ;
it ( 'getCacheDirectoriesPaths should return one dir for yarn without cacheDependency' , async ( ) = > {
getCommandOutputSpy . mockImplementation ( ( ) = > 'foo' ) ;
const dirs = await cacheUtils . getCacheDirectories (
supportedPackageManagers . yarn ,
''
) ;
expect ( dirs ) . toEqual ( [ 'foo' ] ) ;
} ) ;
it . each ( [
[ supportedPackageManagers . npm , '' ] ,
[ supportedPackageManagers . npm , '/dir/file.lock' ] ,
[ supportedPackageManagers . npm , '/**/file.lock' ] ,
[ supportedPackageManagers . pnpm , '' ] ,
[ supportedPackageManagers . pnpm , '/dir/file.lock' ] ,
[ supportedPackageManagers . pnpm , '/**/file.lock' ] ,
[ supportedPackageManagers . yarn , '' ] ,
[ supportedPackageManagers . yarn , '/dir/file.lock' ] ,
[ supportedPackageManagers . yarn , '/**/file.lock' ]
] ) (
'getCacheDirectoriesPaths should throw for getCommandOutput returning empty' ,
async ( packageManagerInfo , cacheDependency ) = > {
getCommandOutputSpy . mockImplementation ( ( command : string ) = >
// return empty string to indicate getCacheFolderPath failed
// --version still works
command . includes ( 'version' ) ? '1.' : ''
) ;
await expect (
cacheUtils . getCacheDirectories ( packageManagerInfo , cacheDependency )
) . rejects . toThrow ( ) ; //'Could not get cache folder path for /dir');
}
) ;
it . each ( [
[ supportedPackageManagers . yarn , '/dir/file.lock' ] ,
[ supportedPackageManagers . yarn , '/**/file.lock' ]
] ) (
'getCacheDirectoriesPaths should nothrow in case of having not directories' ,
async ( packageManagerInfo , cacheDependency ) = > {
lstatSpy . mockImplementation ( arg = > ( {
isDirectory : ( ) = > false
} ) ) ;
await cacheUtils . getCacheDirectories (
packageManagerInfo ,
cacheDependency
) ;
expect ( warningSpy ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( warningSpy ) . toHaveBeenCalledWith (
` No existing directories found containing cache-dependency-path=" ${ cacheDependency } " `
) ;
}
) ;
it . each ( [ '1.1.1' , '2.2.2' ] ) (
'getCacheDirectoriesPaths yarn v%s should return one dir without cacheDependency' ,
async version = > {
getCommandOutputSpy . mockImplementationOnce ( ( ) = > version ) ;
getCommandOutputSpy . mockImplementationOnce ( ( ) = > ` foo ${ version } ` ) ;
const dirs = await cacheUtils . getCacheDirectories (
supportedPackageManagers . yarn ,
''
) ;
expect ( dirs ) . toEqual ( [ ` foo ${ version } ` ] ) ;
}
) ;
it . each ( [ '1.1.1' , '2.2.2' ] ) (
'getCacheDirectoriesPaths yarn v%s should return 2 dirs with globbed cacheDependency' ,
async version = > {
let dirNo = 1 ;
getCommandOutputSpy . mockImplementation ( ( command : string ) = >
command . includes ( 'version' ) ? version : ` file_ ${ version } _ ${ dirNo ++ } `
) ;
globCreateSpy . mockImplementation (
( pattern : string ) : Promise < Globber > = >
MockGlobber . create ( [ '/tmp/dir1/file' , '/tmp/dir2/file' ] )
) ;
const dirs = await cacheUtils . getCacheDirectories (
supportedPackageManagers . yarn ,
'/tmp/**/file'
) ;
expect ( dirs ) . toEqual ( [ ` file_ ${ version } _1 ` , ` file_ ${ version } _2 ` ] ) ;
}
) ;
it . each ( [ '1.1.1' , '2.2.2' ] ) (
'getCacheDirectoriesPaths yarn v%s should return 2 dirs with globbed cacheDependency expanding to duplicates' ,
async version = > {
let dirNo = 1 ;
getCommandOutputSpy . mockImplementation ( ( command : string ) = >
command . includes ( 'version' ) ? version : ` file_ ${ version } _ ${ dirNo ++ } `
) ;
globCreateSpy . mockImplementation (
( pattern : string ) : Promise < Globber > = >
MockGlobber . create ( [
'/tmp/dir1/file' ,
'/tmp/dir2/file' ,
'/tmp/dir1/file'
] )
) ;
const dirs = await cacheUtils . getCacheDirectories (
supportedPackageManagers . yarn ,
'/tmp/**/file'
) ;
expect ( dirs ) . toEqual ( [ ` file_ ${ version } _1 ` , ` file_ ${ version } _2 ` ] ) ;
}
) ;
it . each ( [ '1.1.1' , '2.2.2' ] ) (
'getCacheDirectoriesPaths yarn v%s should return 2 uniq dirs despite duplicate cache directories' ,
async version = > {
let dirNo = 1 ;
getCommandOutputSpy . mockImplementation ( ( command : string ) = >
command . includes ( 'version' )
? version
: ` file_ ${ version } _ ${ dirNo ++ % 2 } `
) ;
globCreateSpy . mockImplementation (
( pattern : string ) : Promise < Globber > = >
MockGlobber . create ( [
'/tmp/dir1/file' ,
'/tmp/dir2/file' ,
'/tmp/dir3/file'
] )
) ;
const dirs = await cacheUtils . getCacheDirectories (
supportedPackageManagers . yarn ,
'/tmp/**/file'
) ;
expect ( dirs ) . toEqual ( [ ` file_ ${ version } _1 ` , ` file_ ${ version } _0 ` ] ) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledTimes ( 6 ) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledWith (
'yarn --version' ,
'/tmp/dir1'
) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledWith (
'yarn --version' ,
'/tmp/dir2'
) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledWith (
'yarn --version' ,
'/tmp/dir3'
) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledWith (
version . startsWith ( '1.' )
? 'yarn cache dir'
: 'yarn config get cacheFolder' ,
'/tmp/dir1'
) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledWith (
version . startsWith ( '1.' )
? 'yarn cache dir'
: 'yarn config get cacheFolder' ,
'/tmp/dir2'
) ;
expect ( getCommandOutputSpy ) . toHaveBeenCalledWith (
version . startsWith ( '1.' )
? 'yarn cache dir'
: 'yarn config get cacheFolder' ,
'/tmp/dir3'
) ;
}
) ;
it . each ( [ '1.1.1' , '2.2.2' ] ) (
'getCacheDirectoriesPaths yarn v%s should return 4 dirs with multiple globs' ,
async version = > {
// simulate wrong indents
const cacheDependencyPath = ` /tmp/dir1/file
/ t m p / d i r 2 / f i l e
/tmp/ * * / f i l e
` ;
globCreateSpy . mockImplementation (
( pattern : string ) : Promise < Globber > = >
MockGlobber . create ( [
'/tmp/dir1/file' ,
'/tmp/dir2/file' ,
'/tmp/dir3/file' ,
'/tmp/dir4/file'
] )
) ;
let dirNo = 1 ;
getCommandOutputSpy . mockImplementation ( ( command : string ) = >
command . includes ( 'version' ) ? version : ` file_ ${ version } _ ${ dirNo ++ } `
) ;
const dirs = await cacheUtils . getCacheDirectories (
supportedPackageManagers . yarn ,
cacheDependencyPath
) ;
expect ( dirs ) . toEqual ( [
` file_ ${ version } _1 ` ,
` file_ ${ version } _2 ` ,
` file_ ${ version } _3 ` ,
` file_ ${ version } _4 `
] ) ;
}
) ;
} ) ;
2021-06-16 08:52:44 +02:00
} ) ;
2024-10-21 18:41:32 +02:00
describe ( 'isGhes' , ( ) = > {
const pristineEnv = process . env ;
beforeEach ( ( ) = > {
jest . resetModules ( ) ;
process . env = { . . . pristineEnv } ;
} ) ;
afterAll ( ( ) = > {
process . env = pristineEnv ;
} ) ;
it ( 'returns false when the GITHUB_SERVER_URL environment variable is not defined' , ( ) = > {
delete process . env [ 'GITHUB_SERVER_URL' ] ;
expect ( isGhes ( ) ) . toBeFalsy ( ) ;
} ) ;
it ( 'returns false when the GITHUB_SERVER_URL environment variable is set to github.com' , ( ) = > {
process . env [ 'GITHUB_SERVER_URL' ] = 'https://github.com' ;
expect ( isGhes ( ) ) . toBeFalsy ( ) ;
} ) ;
it ( 'returns false when the GITHUB_SERVER_URL environment variable is set to a GitHub Enterprise Cloud-style URL' , ( ) = > {
process . env [ 'GITHUB_SERVER_URL' ] = 'https://contoso.ghe.com' ;
expect ( isGhes ( ) ) . toBeFalsy ( ) ;
} ) ;
it ( 'returns false when the GITHUB_SERVER_URL environment variable has a .localhost suffix' , ( ) = > {
process . env [ 'GITHUB_SERVER_URL' ] = 'https://mock-github.localhost' ;
expect ( isGhes ( ) ) . toBeFalsy ( ) ;
} ) ;
it ( 'returns true when the GITHUB_SERVER_URL environment variable is set to some other URL' , ( ) = > {
process . env [ 'GITHUB_SERVER_URL' ] = 'https://src.onpremise.fabrikam.com' ;
expect ( isGhes ( ) ) . toBeTruthy ( ) ;
} ) ;
} ) ;