diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cde9f06..cf1d782 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -154,6 +154,17 @@ jobs: submodules: true - name: Verify submodules true run: __test__/verify-submodules-true.sh + + # Submodules limited + - name: Checkout submodules limited + uses: ./ + with: + ref: test-data/v2/submodule-ssh-url + path: submodules-true + submodules: true + submodule-directories: submodule-level-1 + - name: Verify submodules true + run: __test__/verify-submodules-true.sh # Submodules recursive - name: Checkout submodules recursive diff --git a/README.md b/README.md index e1ea032..6ede173 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/ # Default: false submodules: '' + # A list of submodules to checkout. + # Default: null + submodule-directories: '' + # Add repository path as safe.directory for Git global config by running `git # config --global --add safe.directory ` # Default: true diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index 7633704..6666dca 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -813,6 +813,7 @@ async function setup(testName: string): Promise { lfs: false, submodules: false, nestedSubmodules: false, + submoduleDirectories: [], persistCredentials: true, ref: 'refs/heads/main', repositoryName: 'my-repo', diff --git a/__test__/input-helper.test.ts b/__test__/input-helper.test.ts index 9514cb4..75eb546 100644 --- a/__test__/input-helper.test.ts +++ b/__test__/input-helper.test.ts @@ -21,6 +21,13 @@ describe('input-helper tests', () => { jest.spyOn(core, 'getInput').mockImplementation((name: string) => { return inputs[name] }) + // Mock getMultilineInput + jest.spyOn(core, 'getMultilineInput').mockImplementation((name: string) => { + const input: string[] = (inputs[name] || '') + .split('\n') + .filter(x => x !== '') + return input.map(inp => inp.trim()) + }) // Mock error/warning/info/debug jest.spyOn(core, 'error').mockImplementation(jest.fn()) @@ -87,6 +94,7 @@ describe('input-helper tests', () => { expect(settings.showProgress).toBe(true) expect(settings.lfs).toBe(false) expect(settings.ref).toBe('refs/heads/some-ref') + expect(settings.submoduleDirectories).toStrictEqual([]) expect(settings.repositoryName).toBe('some-repo') expect(settings.repositoryOwner).toBe('some-owner') expect(settings.repositoryPath).toBe(gitHubWorkspace) @@ -144,4 +152,13 @@ describe('input-helper tests', () => { const settings: IGitSourceSettings = await inputHelper.getInputs() expect(settings.workflowOrganizationId).toBe(123456) }) + it('sets submoduleDirectories', async () => { + inputs['submodule-directories'] = 'submodule1\nsubmodule2' + const settings: IGitSourceSettings = await inputHelper.getInputs() + expect(settings.submoduleDirectories).toStrictEqual([ + 'submodule1', + 'submodule2' + ]) + expect(settings.submodules).toBe(true) + }) }) diff --git a/action.yml b/action.yml index 6842eb8..081e0d1 100644 --- a/action.yml +++ b/action.yml @@ -92,6 +92,10 @@ inputs: When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are converted to HTTPS. default: false + submodule-directories: + description: > + A list of submodules to checkout. + default: null set-safe-directory: description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory ` default: true diff --git a/dist/index.js b/dist/index.js index 2b7dd09..b6fff79 100644 --- a/dist/index.js +++ b/dist/index.js @@ -793,10 +793,10 @@ class GitCommandManager { yield this.execGit(args); }); } - submoduleUpdate(fetchDepth, recursive) { + submoduleUpdate(fetchDepth, recursive, submoduleDirectories) { return __awaiter(this, void 0, void 0, function* () { const args = ['-c', 'protocol.version=2']; - args.push('submodule', 'update', '--init', '--force'); + args.push('submodule', 'update', '--init', '--force', ...submoduleDirectories); if (fetchDepth > 0) { args.push(`--depth=${fetchDepth}`); } @@ -1340,7 +1340,7 @@ function getSource(settings) { // Checkout submodules core.startGroup('Fetching submodules'); yield git.submoduleSync(settings.nestedSubmodules); - yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules); + yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules, settings.submoduleDirectories); yield git.submoduleForeach('git config --local gc.auto 0', settings.nestedSubmodules); core.endGroup(); // Persist credentials @@ -1801,6 +1801,7 @@ function getInputs() { // Submodules result.submodules = false; result.nestedSubmodules = false; + result.submoduleDirectories = []; const submodulesString = (core.getInput('submodules') || '').toUpperCase(); if (submodulesString == 'RECURSIVE') { result.submodules = true; @@ -1809,8 +1810,15 @@ function getInputs() { else if (submodulesString == 'TRUE') { result.submodules = true; } + const submoduleDirectories = core.getMultilineInput('submodule-directories'); + if (submoduleDirectories.length > 0) { + result.submoduleDirectories = submoduleDirectories; + if (!result.submodules) + result.submodules = true; + } core.debug(`submodules = ${result.submodules}`); core.debug(`recursive submodules = ${result.nestedSubmodules}`); + core.debug(`submodule directories = ${result.submoduleDirectories}`); // Auth token result.authToken = core.getInput('token', { required: true }); // SSH diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts index 8e42a38..bc73118 100644 --- a/src/git-command-manager.ts +++ b/src/git-command-manager.ts @@ -54,7 +54,11 @@ export interface IGitCommandManager { shaExists(sha: string): Promise submoduleForeach(command: string, recursive: boolean): Promise submoduleSync(recursive: boolean): Promise - submoduleUpdate(fetchDepth: number, recursive: boolean): Promise + submoduleUpdate( + fetchDepth: number, + recursive: boolean, + submoduleDirectories: string[] + ): Promise submoduleStatus(): Promise tagExists(pattern: string): Promise tryClean(): Promise @@ -409,9 +413,19 @@ class GitCommandManager { await this.execGit(args) } - async submoduleUpdate(fetchDepth: number, recursive: boolean): Promise { + async submoduleUpdate( + fetchDepth: number, + recursive: boolean, + submoduleDirectories: string[] + ): Promise { const args = ['-c', 'protocol.version=2'] - args.push('submodule', 'update', '--init', '--force') + args.push( + 'submodule', + 'update', + '--init', + '--force', + ...submoduleDirectories + ) if (fetchDepth > 0) { args.push(`--depth=${fetchDepth}`) } diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts index 2d35138..ebbf9fc 100644 --- a/src/git-source-provider.ts +++ b/src/git-source-provider.ts @@ -242,7 +242,11 @@ export async function getSource(settings: IGitSourceSettings): Promise { // Checkout submodules core.startGroup('Fetching submodules') await git.submoduleSync(settings.nestedSubmodules) - await git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules) + await git.submoduleUpdate( + settings.fetchDepth, + settings.nestedSubmodules, + settings.submoduleDirectories + ) await git.submoduleForeach( 'git config --local gc.auto 0', settings.nestedSubmodules diff --git a/src/git-source-settings.ts b/src/git-source-settings.ts index 4e41ac3..518e0bf 100644 --- a/src/git-source-settings.ts +++ b/src/git-source-settings.ts @@ -74,6 +74,11 @@ export interface IGitSourceSettings { */ nestedSubmodules: boolean + /** + * Indicates which submodule paths to checkout + */ + submoduleDirectories: string[] + /** * The auth token to use when fetching the repository */ diff --git a/src/input-helper.ts b/src/input-helper.ts index 059232f..5b2ff6c 100644 --- a/src/input-helper.ts +++ b/src/input-helper.ts @@ -125,6 +125,7 @@ export async function getInputs(): Promise { // Submodules result.submodules = false result.nestedSubmodules = false + result.submoduleDirectories = [] const submodulesString = (core.getInput('submodules') || '').toUpperCase() if (submodulesString == 'RECURSIVE') { result.submodules = true @@ -132,9 +133,16 @@ export async function getInputs(): Promise { } else if (submodulesString == 'TRUE') { result.submodules = true } + + const submoduleDirectories = core.getMultilineInput('submodule-directories') + if (submoduleDirectories.length > 0) { + result.submoduleDirectories = submoduleDirectories + if (!result.submodules) result.submodules = true + } + core.debug(`submodules = ${result.submodules}`) core.debug(`recursive submodules = ${result.nestedSubmodules}`) - + core.debug(`submodule directories = ${result.submoduleDirectories}`) // Auth token result.authToken = core.getInput('token', {required: true})