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