Compare commits

...

3 Commits

Author SHA1 Message Date
719fedec20 Use rev-list for tags 2023-05-30 19:07:40 +00:00
f095bcc56b Fix typos found by codespell (#1287) 2023-04-19 16:55:10 +02:00
SKi
47fbe2df0a 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>
2023-04-14 06:26:47 -04:00
7 changed files with 120 additions and 6 deletions

View File

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

View File

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

View File

@ -181,7 +181,7 @@ GITHUB_WORKSPACE=/home/runner/work/foo/foo
RUNNER_WORKSPACE=/home/runner/work/foo
```
V2 introduces a new contraint on the checkout path. The location must now be under `github.workspace`. Whereas the checkout@v1 constraint was one level up, under `runner.workspace`.
V2 introduces a new constraint on the checkout path. The location must now be under `github.workspace`. Whereas the checkout@v1 constraint was one level up, under `runner.workspace`.
V2 no longer changes `github.workspace` to follow wherever the self repo is checked-out.
@ -287,4 +287,4 @@ Note:
- Update samples to consume `actions/checkout@v2`
- Job containers now require git in the PATH for checkout, otherwise fallback to REST API
- Minimum git version 2.18
- Update problem matcher logic regarding source file verification (runner)
- Update problem matcher logic regarding source file verification (runner)

28
dist/index.js vendored
View File

@ -722,6 +722,18 @@ class GitCommandManager {
return output.stdout.trim();
});
}
/**
* Lists SHAs pointed to by a revision.
* @param {string} ref For example: 'refs/heads/main' or '/refs/tags/v1'
* @param {number} numberOfRefs
* @param value
*/
revList(ref, numberOfRefs) {
return __awaiter(this, void 0, void 0, function* () {
const output = yield this.execGit(['rev-list', ref, `-${numberOfRefs}`]);
return output.stdout.trim();
});
}
setEnvironmentVariable(name, value) {
this.gitEnv[name] = value;
}
@ -765,6 +777,13 @@ class GitCommandManager {
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) {
return __awaiter(this, void 0, void 0, function* () {
const output = yield this.execGit(['tag', '--list', pattern]);
@ -1023,11 +1042,16 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean, ref
}
}
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
if (clean) {
core.startGroup('Cleaning the repository');
if (!(yield git.tryClean())) {
core.debug(`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`);
core.debug(`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For further investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`);
remove = true;
}
else if (!(yield git.tryReset())) {
@ -1970,7 +1994,7 @@ function testRef(git, ref, commit) {
// refs/tags/
else if (upperRef.startsWith('REFS/TAGS/')) {
const tagName = ref.substring('refs/tags/'.length);
return ((yield git.tagExists(tagName)) && commit === (yield git.revParse(ref)));
return ((yield git.tagExists(tagName)) && commit === (yield git.revList(ref, 1)));
}
// Unexpected
else {

View File

@ -35,12 +35,14 @@ export interface IGitCommandManager {
log1(format?: string): Promise<string>
remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
removeEnvironmentVariable(name: string): void
revList(ref: string, numberOfRefs: number): Promise<string>
revParse(ref: string): Promise<string>
setEnvironmentVariable(name: string, value: string): void
shaExists(sha: string): Promise<boolean>
submoduleForeach(command: string, recursive: boolean): Promise<string>
submoduleSync(recursive: boolean): Promise<void>
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
submoduleStatus(): Promise<boolean>
tagExists(pattern: string): Promise<boolean>
tryClean(): Promise<boolean>
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
@ -313,6 +315,17 @@ class GitCommandManager {
return output.stdout.trim()
}
/**
* Lists SHAs pointed to by a revision.
* @param {string} ref For example: 'refs/heads/main' or '/refs/tags/v1'
* @param {number} numberOfRefs
* @param value
*/
async revList(ref: string, numberOfRefs: number): Promise<string> {
const output = await this.execGit(['rev-list', ref, `-${numberOfRefs}`])
return output.stdout.trim()
}
setEnvironmentVariable(name: string, value: string): void {
this.gitEnv[name] = value
}
@ -357,6 +370,12 @@ class GitCommandManager {
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> {
const output = await this.execGit(['tag', '--list', pattern])
return !!output.stdout.trim()

View File

@ -81,12 +81,18 @@ export async function prepareExistingDirectory(
}
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
if (clean) {
core.startGroup('Cleaning the repository')
if (!(await git.tryClean())) {
core.debug(
`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For further investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
)
remove = true
} else if (!(await git.tryReset())) {

View File

@ -167,7 +167,7 @@ export async function testRef(
else if (upperRef.startsWith('REFS/TAGS/')) {
const tagName = ref.substring('refs/tags/'.length)
return (
(await git.tagExists(tagName)) && commit === (await git.revParse(ref))
(await git.tagExists(tagName)) && commit === (await git.revList(ref, 1))
)
}
// Unexpected