Skip to content

Commit b6625bb

Browse files
committed
Add string[] option to submodules
Allows checking out only specific submodules instead of all
1 parent 9a9194f commit b6625bb

10 files changed

+128
-22
lines changed

.github/workflows/test.yml

+11
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ jobs:
154154
submodules: true
155155
- name: Verify submodules true
156156
run: __test__/verify-submodules-true.sh
157+
158+
# Submodules limited
159+
- name: Checkout submodules limited
160+
uses: ./
161+
with:
162+
ref: test-data/v2/submodule-ssh-url
163+
path: submodules-true
164+
submodules: true
165+
submodule-directories: submodule-level-1
166+
- name: Verify submodules true
167+
run: __test__/verify-submodules-true.sh
157168

158169
# Submodules recursive
159170
- name: Checkout submodules recursive

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
116116
# Default: false
117117
submodules: ''
118118

119+
# A list of submodules to use when `submodules` is `true`.
120+
# Default: null
121+
submodule-directories: ''
122+
119123
# Add repository path as safe.directory for Git global config by running `git
120124
# config --global --add safe.directory <path>`
121125
# Default: true

__test__/git-auth-helper.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,7 @@ async function setup(testName: string): Promise<void> {
813813
lfs: false,
814814
submodules: false,
815815
nestedSubmodules: false,
816+
submoduleDirectories: null,
816817
persistCredentials: true,
817818
ref: 'refs/heads/main',
818819
repositoryName: 'my-repo',

__test__/input-helper.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ describe('input-helper tests', () => {
2121
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
2222
return inputs[name]
2323
})
24+
// Mock getMultilineInput
25+
jest.spyOn(core, 'getMultilineInput').mockImplementation((name: string) => {
26+
const input: string[] = (inputs[name] || '')
27+
.split('\n')
28+
.filter(x => x !== '')
29+
return input.map(inp => inp.trim())
30+
})
2431

2532
// Mock error/warning/info/debug
2633
jest.spyOn(core, 'error').mockImplementation(jest.fn())
@@ -87,6 +94,7 @@ describe('input-helper tests', () => {
8794
expect(settings.showProgress).toBe(true)
8895
expect(settings.lfs).toBe(false)
8996
expect(settings.ref).toBe('refs/heads/some-ref')
97+
expect(settings.submoduleDirectories).toBe(null)
9098
expect(settings.repositoryName).toBe('some-repo')
9199
expect(settings.repositoryOwner).toBe('some-owner')
92100
expect(settings.repositoryPath).toBe(gitHubWorkspace)
@@ -144,4 +152,13 @@ describe('input-helper tests', () => {
144152
const settings: IGitSourceSettings = await inputHelper.getInputs()
145153
expect(settings.workflowOrganizationId).toBe(123456)
146154
})
155+
it('sets submoduleDirectories', async () => {
156+
inputs['submodule-directories'] = 'submodule1\nsubmodule2'
157+
const settings: IGitSourceSettings = await inputHelper.getInputs()
158+
expect(settings.submoduleDirectories).toStrictEqual([
159+
'submodule1',
160+
'submodule2'
161+
])
162+
expect(settings.submodules).toBe(true)
163+
})
147164
})

action.yml

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ inputs:
9292
When the `ssh-key` input is not provided, SSH URLs beginning with `[email protected]:` are
9393
converted to HTTPS.
9494
default: false
95+
submodule-directories:
96+
description: >
97+
A list of submodules to use when `submodules` is `true`.
98+
default: null
9599
set-safe-directory:
96100
description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory <path>`
97101
default: true

dist/index.js

+35-9
Original file line numberDiff line numberDiff line change
@@ -795,17 +795,32 @@ class GitCommandManager {
795795
yield this.execGit(args);
796796
});
797797
}
798-
submoduleUpdate(fetchDepth, recursive) {
798+
submoduleUpdate(fetchDepth, recursive, submoduleDirectories) {
799799
return __awaiter(this, void 0, void 0, function* () {
800-
const args = ['-c', 'protocol.version=2'];
801-
args.push('submodule', 'update', '--init', '--force');
802-
if (fetchDepth > 0) {
803-
args.push(`--depth=${fetchDepth}`);
800+
if (submoduleDirectories) {
801+
for (const submodule of submoduleDirectories) {
802+
const args = ['-c', 'protocol.version=2'];
803+
args.push('submodule', 'update', '--init', '--force', submodule);
804+
if (fetchDepth > 0) {
805+
args.push(`--depth=${fetchDepth}`);
806+
}
807+
if (recursive) {
808+
args.push('--recursive');
809+
}
810+
yield this.execGit(args);
811+
}
804812
}
805-
if (recursive) {
806-
args.push('--recursive');
813+
else {
814+
const args = ['-c', 'protocol.version=2'];
815+
args.push('submodule', 'update', '--init', '--force');
816+
if (fetchDepth > 0) {
817+
args.push(`--depth=${fetchDepth}`);
818+
}
819+
if (recursive) {
820+
args.push('--recursive');
821+
}
822+
yield this.execGit(args);
807823
}
808-
yield this.execGit(args);
809824
});
810825
}
811826
submoduleStatus() {
@@ -1342,7 +1357,7 @@ function getSource(settings) {
13421357
// Checkout submodules
13431358
core.startGroup('Fetching submodules');
13441359
yield git.submoduleSync(settings.nestedSubmodules);
1345-
yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules);
1360+
yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules, settings.submoduleDirectories);
13461361
yield git.submoduleForeach('git config --local gc.auto 0', settings.nestedSubmodules);
13471362
core.endGroup();
13481363
// Persist credentials
@@ -1805,6 +1820,7 @@ function getInputs() {
18051820
// Submodules
18061821
result.submodules = false;
18071822
result.nestedSubmodules = false;
1823+
result.submoduleDirectories = null;
18081824
const submodulesString = (core.getInput('submodules') || '').toUpperCase();
18091825
if (submodulesString == 'RECURSIVE') {
18101826
result.submodules = true;
@@ -1813,8 +1829,18 @@ function getInputs() {
18131829
else if (submodulesString == 'TRUE') {
18141830
result.submodules = true;
18151831
}
1832+
const submoduleDirectories = core.getMultilineInput('submodule-directories');
1833+
if (submoduleDirectories.length > 0) {
1834+
result.submoduleDirectories = submoduleDirectories;
1835+
if (!result.submodules)
1836+
result.submodules = true;
1837+
}
1838+
else {
1839+
result.submoduleDirectories = null;
1840+
}
18161841
core.debug(`submodules = ${result.submodules}`);
18171842
core.debug(`recursive submodules = ${result.nestedSubmodules}`);
1843+
core.debug(`submodule directories = ${result.submoduleDirectories}`);
18181844
// Auth token
18191845
result.authToken = core.getInput('token', { required: true });
18201846
// SSH

src/git-command-manager.ts

+35-11
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ export interface IGitCommandManager {
5454
shaExists(sha: string): Promise<boolean>
5555
submoduleForeach(command: string, recursive: boolean): Promise<string>
5656
submoduleSync(recursive: boolean): Promise<void>
57-
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
57+
submoduleUpdate(
58+
fetchDepth: number,
59+
recursive: boolean,
60+
submoduleDirectories: string[] | null
61+
): Promise<void>
5862
submoduleStatus(): Promise<boolean>
5963
tagExists(pattern: string): Promise<boolean>
6064
tryClean(): Promise<boolean>
@@ -409,18 +413,38 @@ class GitCommandManager {
409413
await this.execGit(args)
410414
}
411415

412-
async submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void> {
413-
const args = ['-c', 'protocol.version=2']
414-
args.push('submodule', 'update', '--init', '--force')
415-
if (fetchDepth > 0) {
416-
args.push(`--depth=${fetchDepth}`)
417-
}
416+
async submoduleUpdate(
417+
fetchDepth: number,
418+
recursive: boolean,
419+
submoduleDirectories: string[] | null
420+
): Promise<void> {
421+
if (submoduleDirectories) {
422+
for (const submodule of submoduleDirectories) {
423+
const args = ['-c', 'protocol.version=2']
424+
args.push('submodule', 'update', '--init', '--force', submodule)
425+
if (fetchDepth > 0) {
426+
args.push(`--depth=${fetchDepth}`)
427+
}
418428

419-
if (recursive) {
420-
args.push('--recursive')
421-
}
429+
if (recursive) {
430+
args.push('--recursive')
431+
}
422432

423-
await this.execGit(args)
433+
await this.execGit(args)
434+
}
435+
} else {
436+
const args = ['-c', 'protocol.version=2']
437+
args.push('submodule', 'update', '--init', '--force')
438+
if (fetchDepth > 0) {
439+
args.push(`--depth=${fetchDepth}`)
440+
}
441+
442+
if (recursive) {
443+
args.push('--recursive')
444+
}
445+
446+
await this.execGit(args)
447+
}
424448
}
425449

426450
async submoduleStatus(): Promise<boolean> {

src/git-source-provider.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,11 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
242242
// Checkout submodules
243243
core.startGroup('Fetching submodules')
244244
await git.submoduleSync(settings.nestedSubmodules)
245-
await git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules)
245+
await git.submoduleUpdate(
246+
settings.fetchDepth,
247+
settings.nestedSubmodules,
248+
settings.submoduleDirectories
249+
)
246250
await git.submoduleForeach(
247251
'git config --local gc.auto 0',
248252
settings.nestedSubmodules

src/git-source-settings.ts

+5
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ export interface IGitSourceSettings {
7474
*/
7575
nestedSubmodules: boolean
7676

77+
/**
78+
* Indicates which submodule paths to checkout
79+
*/
80+
submoduleDirectories: string[] | null
81+
7782
/**
7883
* The auth token to use when fetching the repository
7984
*/

src/input-helper.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,26 @@ export async function getInputs(): Promise<IGitSourceSettings> {
125125
// Submodules
126126
result.submodules = false
127127
result.nestedSubmodules = false
128+
result.submoduleDirectories = null
128129
const submodulesString = (core.getInput('submodules') || '').toUpperCase()
129130
if (submodulesString == 'RECURSIVE') {
130131
result.submodules = true
131132
result.nestedSubmodules = true
132133
} else if (submodulesString == 'TRUE') {
133134
result.submodules = true
134135
}
136+
137+
const submoduleDirectories = core.getMultilineInput('submodule-directories')
138+
if (submoduleDirectories.length > 0) {
139+
result.submoduleDirectories = submoduleDirectories
140+
if (!result.submodules) result.submodules = true
141+
} else {
142+
result.submoduleDirectories = null
143+
}
144+
135145
core.debug(`submodules = ${result.submodules}`)
136146
core.debug(`recursive submodules = ${result.nestedSubmodules}`)
137-
147+
core.debug(`submodule directories = ${result.submoduleDirectories}`)
138148
// Auth token
139149
result.authToken = core.getInput('token', {required: true})
140150

0 commit comments

Comments
 (0)