Fix: Checkout fail in self-hosted runners when faulty submodule are checked-in (#1196)

* Fix Self hosted runner issue wrt bad submodules - solution cleanup working space.

* Fix format with npm run format output

* Add mock implementation for new function submoduleStatus

* Add 2  test cases for submodule status.

* Codeql-Action Analyse revert v1 to v2

---------

Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com>
Co-authored-by: sminnie <minnie@sankhe.com>
This commit is contained in:
SKi 2023-04-14 03:26:47 -07:00 committed by GitHub
parent 8e5e7e5ab8
commit 47fbe2df0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 0 deletions

@ -770,6 +770,9 @@ async function setup(testName: string): Promise<void> {
return '' return ''
}), }),
submoduleSync: jest.fn(), submoduleSync: jest.fn(),
submoduleStatus: jest.fn(async () => {
return true
}),
submoduleUpdate: jest.fn(), submoduleUpdate: jest.fn(),
tagExists: jest.fn(), tagExists: jest.fn(),
tryClean: jest.fn(), tryClean: jest.fn(),

@ -281,6 +281,65 @@ describe('git-directory-helper tests', () => {
expect(git.branchDelete).toHaveBeenCalledWith(false, 'local-branch-2') expect(git.branchDelete).toHaveBeenCalledWith(false, 'local-branch-2')
}) })
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()
})
const removesLockFiles = 'removes lock files' const removesLockFiles = 'removes lock files'
it(removesLockFiles, async () => { it(removesLockFiles, async () => {
// Arrange // Arrange
@ -423,6 +482,9 @@ async function setup(testName: string): Promise<void> {
submoduleForeach: jest.fn(), submoduleForeach: jest.fn(),
submoduleSync: jest.fn(), submoduleSync: jest.fn(),
submoduleUpdate: jest.fn(), submoduleUpdate: jest.fn(),
submoduleStatus: jest.fn(async () => {
return true
}),
tagExists: jest.fn(), tagExists: jest.fn(),
tryClean: jest.fn(async () => { tryClean: jest.fn(async () => {
return true return true

12
dist/index.js vendored

@ -765,6 +765,13 @@ class GitCommandManager {
yield this.execGit(args); yield this.execGit(args);
}); });
} }
submoduleStatus() {
return __awaiter(this, void 0, void 0, function* () {
const output = yield this.execGit(['submodule', 'status'], true);
core.debug(output.stdout);
return output.exitCode === 0;
});
}
tagExists(pattern) { tagExists(pattern) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const output = yield this.execGit(['tag', '--list', pattern]); const output = yield this.execGit(['tag', '--list', pattern]);
@ -1023,6 +1030,11 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean, ref
} }
} }
core.endGroup(); core.endGroup();
// Check for submodules and delete any existing files if submodules are present
if (!(yield git.submoduleStatus())) {
remove = true;
core.info('Bad Submodules found, removing existing files');
}
// Clean // Clean
if (clean) { if (clean) {
core.startGroup('Cleaning the repository'); core.startGroup('Cleaning the repository');

@ -41,6 +41,7 @@ export interface IGitCommandManager {
submoduleForeach(command: string, recursive: boolean): Promise<string> submoduleForeach(command: string, recursive: boolean): Promise<string>
submoduleSync(recursive: boolean): Promise<void> submoduleSync(recursive: boolean): Promise<void>
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void> submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
submoduleStatus(): Promise<boolean>
tagExists(pattern: string): Promise<boolean> tagExists(pattern: string): Promise<boolean>
tryClean(): Promise<boolean> tryClean(): Promise<boolean>
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean> tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
@ -357,6 +358,12 @@ class GitCommandManager {
await this.execGit(args) await this.execGit(args)
} }
async submoduleStatus(): Promise<boolean> {
const output = await this.execGit(['submodule', 'status'], true)
core.debug(output.stdout)
return output.exitCode === 0
}
async tagExists(pattern: string): Promise<boolean> { async tagExists(pattern: string): Promise<boolean> {
const output = await this.execGit(['tag', '--list', pattern]) const output = await this.execGit(['tag', '--list', pattern])
return !!output.stdout.trim() return !!output.stdout.trim()

@ -81,6 +81,12 @@ export async function prepareExistingDirectory(
} }
core.endGroup() core.endGroup()
// Check for submodules and delete any existing files if submodules are present
if (!(await git.submoduleStatus())) {
remove = true
core.info('Bad Submodules found, removing existing files')
}
// Clean // Clean
if (clean) { if (clean) {
core.startGroup('Cleaning the repository') core.startGroup('Cleaning the repository')