1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.api;
44
45 import static org.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertNotNull;
47 import static org.junit.Assert.assertTrue;
48
49 import java.io.File;
50
51 import org.eclipse.jgit.api.ResetCommand.ResetType;
52 import org.eclipse.jgit.junit.JGitTestUtil;
53 import org.eclipse.jgit.junit.RepositoryTestCase;
54 import org.eclipse.jgit.lib.ConfigConstants;
55 import org.eclipse.jgit.lib.Constants;
56 import org.eclipse.jgit.lib.ObjectId;
57 import org.eclipse.jgit.lib.Repository;
58 import org.eclipse.jgit.lib.StoredConfig;
59 import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
60 import org.eclipse.jgit.revwalk.RevCommit;
61 import org.eclipse.jgit.submodule.SubmoduleStatus;
62 import org.eclipse.jgit.submodule.SubmoduleStatusType;
63 import org.eclipse.jgit.submodule.SubmoduleWalk;
64 import org.eclipse.jgit.transport.FetchResult;
65 import org.eclipse.jgit.transport.RefSpec;
66 import org.junit.Before;
67 import org.junit.experimental.theories.DataPoints;
68 import org.junit.experimental.theories.Theories;
69 import org.junit.experimental.theories.Theory;
70 import org.junit.runner.RunWith;
71
72 @RunWith(Theories.class)
73 public class FetchAndPullCommandsRecurseSubmodulesTest extends RepositoryTestCase {
74 @DataPoints
75 public static boolean[] useFetch = { true, false };
76
77 private Git git;
78
79 private Git git2;
80
81 private Git sub1Git;
82
83 private Git sub2Git;
84
85 private RevCommit commit1;
86
87 private RevCommit commit2;
88
89 private ObjectId submodule1Head;
90
91 private ObjectId submodule2Head;
92
93 private final RefSpec REFSPEC = new RefSpec("refs/heads/master");
94
95 private final String REMOTE = "origin";
96
97 private final String PATH = "sub";
98
99 @Before
100 public void setUpSubmodules() throws Exception {
101 git = new Git(db);
102
103
104 File submodule1 = createTempDirectory(
105 "testCloneRepositoryWithNestedSubmodules1");
106 sub1Git = Git.init().setDirectory(submodule1).call();
107 assertNotNull(sub1Git);
108 Repository sub1 = sub1Git.getRepository();
109 assertNotNull(sub1);
110 addRepoToClose(sub1);
111
112 String file = "file.txt";
113
114 write(new File(sub1.getWorkTree(), file), "content");
115 sub1Git.add().addFilepattern(file).call();
116 RevCommit commit = sub1Git.commit().setMessage("create file").call();
117 assertNotNull(commit);
118
119
120 File submodule2 = createTempDirectory(
121 "testCloneRepositoryWithNestedSubmodules2");
122 sub2Git = Git.init().setDirectory(submodule2).call();
123 assertNotNull(sub2Git);
124 Repository sub2 = sub2Git.getRepository();
125 assertNotNull(sub2);
126 addRepoToClose(sub2);
127
128 write(new File(sub2.getWorkTree(), file), "content");
129 sub2Git.add().addFilepattern(file).call();
130 RevCommit sub2Head = sub2Git.commit().setMessage("create file").call();
131 assertNotNull(sub2Head);
132
133
134 Repository r2 = sub1Git.submoduleAdd().setPath(PATH)
135 .setURI(sub2.getDirectory().toURI().toString()).call();
136 assertNotNull(r2);
137 addRepoToClose(r2);
138 RevCommit sub1Head = sub1Git.commit().setAll(true)
139 .setMessage("Adding submodule").call();
140 assertNotNull(sub1Head);
141
142
143 Repository r1 = git.submoduleAdd().setPath(PATH)
144 .setURI(sub1.getDirectory().toURI().toString()).call();
145 assertNotNull(r1);
146 addRepoToClose(r1);
147 assertNotNull(git.commit().setAll(true).setMessage("Adding submodule")
148 .call());
149
150
151 File directory = createTempDirectory(
152 "testCloneRepositoryWithNestedSubmodules");
153 CloneCommand clone = Git.cloneRepository();
154 clone.setDirectory(directory);
155 clone.setCloneSubmodules(true);
156 clone.setURI(git.getRepository().getDirectory().toURI().toString());
157 git2 = clone.call();
158 addRepoToClose(git2.getRepository());
159 assertNotNull(git2);
160
161
162 try (SubmoduleWalk walk = SubmoduleWalk
163 .forIndex(git2.getRepository())) {
164 assertTrue(walk.next());
165 Repository r = walk.getRepository();
166 submodule1Head = r.resolve(Constants.FETCH_HEAD);
167
168 try (SubmoduleWalk walk2 = SubmoduleWalk.forIndex(r)) {
169 assertTrue(walk2.next());
170 submodule2Head = walk2.getRepository()
171 .resolve(Constants.FETCH_HEAD);
172 }
173 }
174
175
176 JGitTestUtil.writeTrashFile(r1, "f1.txt", "test");
177 sub1Git.add().addFilepattern("f1.txt").call();
178 commit1 = sub1Git.commit().setMessage("new commit").call();
179
180
181 JGitTestUtil.writeTrashFile(r2, "f2.txt", "test");
182 sub2Git.add().addFilepattern("f2.txt").call();
183 commit2 = sub2Git.commit().setMessage("new commit").call();
184 }
185
186 @Theory
187 public void shouldNotFetchSubmodulesWhenNo(boolean fetch) throws Exception {
188 FetchResult result = execute(FetchRecurseSubmodulesMode.NO, fetch);
189 assertTrue(result.submoduleResults().isEmpty());
190 assertSubmoduleFetchHeads(submodule1Head, submodule2Head);
191 }
192
193 @Theory
194 public void shouldFetchSubmodulesWhenYes(boolean fetch) throws Exception {
195 FetchResult result = execute(FetchRecurseSubmodulesMode.YES, fetch);
196 assertTrue(result.submoduleResults().containsKey("sub"));
197 FetchResult subResult = result.submoduleResults().get("sub");
198 assertTrue(subResult.submoduleResults().containsKey("sub"));
199 assertSubmoduleFetchHeads(commit1, commit2);
200 }
201
202 @Theory
203 public void shouldFetchSubmodulesWhenOnDemandAndRevisionChanged(
204 boolean fetch) throws Exception {
205 RevCommit update = updateSubmoduleRevision();
206 FetchResult result = execute(FetchRecurseSubmodulesMode.ON_DEMAND,
207 fetch);
208
209
210 assertTrue(result.submoduleResults().containsKey("sub"));
211 FetchResult subResult = result.submoduleResults().get("sub");
212
213
214 assertTrue(subResult.submoduleResults().isEmpty());
215 assertSubmoduleFetchHeads(commit1, submodule2Head);
216
217
218
219 assertEquals(update,
220 git2.getRepository().resolve(Constants.FETCH_HEAD));
221 }
222
223 @Theory
224 public void shouldNotFetchSubmodulesWhenOnDemandAndRevisionNotChanged(
225 boolean fetch) throws Exception {
226 FetchResult result = execute(FetchRecurseSubmodulesMode.ON_DEMAND,
227 fetch);
228 assertTrue(result.submoduleResults().isEmpty());
229 assertSubmoduleFetchHeads(submodule1Head, submodule2Head);
230 }
231
232 @Theory
233 public void shouldNotFetchSubmodulesWhenSubmoduleConfigurationSetToNo(
234 boolean fetch) throws Exception {
235 StoredConfig config = git2.getRepository().getConfig();
236 config.setEnum(ConfigConstants.CONFIG_SUBMODULE_SECTION, PATH,
237 ConfigConstants.CONFIG_KEY_FETCH_RECURSE_SUBMODULES,
238 FetchRecurseSubmodulesMode.NO);
239 config.save();
240 updateSubmoduleRevision();
241 FetchResult result = execute(null, fetch);
242 assertTrue(result.submoduleResults().isEmpty());
243 assertSubmoduleFetchHeads(submodule1Head, submodule2Head);
244 }
245
246 @Theory
247 public void shouldFetchSubmodulesWhenSubmoduleConfigurationSetToYes(
248 boolean fetch) throws Exception {
249 StoredConfig config = git2.getRepository().getConfig();
250 config.setEnum(ConfigConstants.CONFIG_SUBMODULE_SECTION, PATH,
251 ConfigConstants.CONFIG_KEY_FETCH_RECURSE_SUBMODULES,
252 FetchRecurseSubmodulesMode.YES);
253 config.save();
254 FetchResult result = execute(null, fetch);
255 assertTrue(result.submoduleResults().containsKey("sub"));
256 FetchResult subResult = result.submoduleResults().get("sub");
257 assertTrue(subResult.submoduleResults().containsKey("sub"));
258 assertSubmoduleFetchHeads(commit1, commit2);
259 }
260
261 @Theory
262 public void shouldNotFetchSubmodulesWhenFetchConfigurationSetToNo(
263 boolean fetch) throws Exception {
264 StoredConfig config = git2.getRepository().getConfig();
265 config.setEnum(ConfigConstants.CONFIG_FETCH_SECTION, null,
266 ConfigConstants.CONFIG_KEY_RECURSE_SUBMODULES,
267 FetchRecurseSubmodulesMode.NO);
268 config.save();
269 updateSubmoduleRevision();
270 FetchResult result = execute(null, fetch);
271 assertTrue(result.submoduleResults().isEmpty());
272 assertSubmoduleFetchHeads(submodule1Head, submodule2Head);
273 }
274
275 @Theory
276 public void shouldFetchSubmodulesWhenFetchConfigurationSetToYes(
277 boolean fetch) throws Exception {
278 StoredConfig config = git2.getRepository().getConfig();
279 config.setEnum(ConfigConstants.CONFIG_FETCH_SECTION, null,
280 ConfigConstants.CONFIG_KEY_RECURSE_SUBMODULES,
281 FetchRecurseSubmodulesMode.YES);
282 config.save();
283 FetchResult result = execute(null, fetch);
284 assertTrue(result.submoduleResults().containsKey("sub"));
285 FetchResult subResult = result.submoduleResults().get("sub");
286 assertTrue(subResult.submoduleResults().containsKey("sub"));
287 assertSubmoduleFetchHeads(commit1, commit2);
288 }
289
290 private RevCommit updateSubmoduleRevision() throws Exception {
291
292
293 try (SubmoduleWalk w = SubmoduleWalk.forIndex(git.getRepository())) {
294 assertTrue(w.next());
295 try (Git g = new Git(w.getRepository())) {
296 g.fetch().setRemote(REMOTE).setRefSpecs(REFSPEC).call();
297 g.reset().setMode(ResetType.HARD).setRef(commit1.name()).call();
298 }
299 }
300
301
302
303 SubmoduleStatus subStatus = git.submoduleStatus().call().get("sub");
304 assertEquals(submodule1Head, subStatus.getIndexId());
305 assertEquals(commit1, subStatus.getHeadId());
306 assertEquals(SubmoduleStatusType.REV_CHECKED_OUT, subStatus.getType());
307
308
309 git.add().addFilepattern("sub").call();
310 RevCommit update = git.commit().setMessage("update sub").call();
311
312
313
314 subStatus = git.submoduleStatus().call().get("sub");
315 assertEquals(commit1, subStatus.getIndexId());
316 assertEquals(commit1, subStatus.getHeadId());
317 assertEquals(SubmoduleStatusType.INITIALIZED, subStatus.getType());
318
319 return update;
320 }
321
322 private FetchResult execute(FetchRecurseSubmodulesMode mode, boolean fetch)
323 throws Exception {
324 FetchResult result;
325
326 if (fetch) {
327 result = git2.fetch().setRemote(REMOTE).setRefSpecs(REFSPEC)
328 .setRecurseSubmodules(mode).call();
329 } else {
330
331
332
333
334
335
336
337 result = git2.pull().setRemote(REMOTE).setRebase(true)
338 .setRecurseSubmodules(mode).call().getFetchResult();
339 }
340 assertNotNull(result);
341 return result;
342 }
343
344 private void assertSubmoduleFetchHeads(ObjectId expectedHead1,
345 ObjectId expectedHead2) throws Exception {
346 try (SubmoduleWalk walk = SubmoduleWalk
347 .forIndex(git2.getRepository())) {
348 assertTrue(walk.next());
349 Repository r = walk.getRepository();
350 ObjectId newHead1 = r.resolve(Constants.FETCH_HEAD);
351 ObjectId newHead2;
352 try (SubmoduleWalk walk2 = SubmoduleWalk.forIndex(r)) {
353 assertTrue(walk2.next());
354 newHead2 = walk2.getRepository().resolve(Constants.FETCH_HEAD);
355 }
356
357 assertEquals(expectedHead1, newHead1);
358 assertEquals(expectedHead2, newHead2);
359 }
360 }
361 }