You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DescribeCommandTest.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * Copyright (C) 2013, CloudBees, Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.api;
  11. import static java.nio.charset.StandardCharsets.UTF_8;
  12. import static org.junit.Assert.assertEquals;
  13. import static org.junit.Assert.assertNull;
  14. import static org.junit.Assert.assertNotNull;
  15. import static org.junit.Assert.assertTrue;
  16. import java.io.BufferedWriter;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.nio.file.Files;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import org.eclipse.jgit.api.errors.GitAPIException;
  23. import org.eclipse.jgit.api.errors.RefNotFoundException;
  24. import org.eclipse.jgit.junit.RepositoryTestCase;
  25. import org.eclipse.jgit.lib.ObjectId;
  26. import org.junit.Test;
  27. import org.junit.runner.RunWith;
  28. import org.junit.runners.Parameterized;
  29. import org.junit.runners.Parameterized.Parameter;
  30. import org.junit.runners.Parameterized.Parameters;
  31. @RunWith(Parameterized.class)
  32. public class DescribeCommandTest extends RepositoryTestCase {
  33. private Git git;
  34. @Parameter(0)
  35. public boolean useAnnotatedTags;
  36. @Parameter(1)
  37. public boolean describeUseAllTags;
  38. @Parameters(name = "git tag -a {0}?-a: with git describe {1}?--tags:")
  39. public static Collection<Boolean[]> getUseAnnotatedTagsValues() {
  40. return Arrays.asList(new Boolean[][] { { Boolean.TRUE, Boolean.FALSE },
  41. { Boolean.FALSE, Boolean.FALSE },
  42. { Boolean.TRUE, Boolean.TRUE },
  43. { Boolean.FALSE, Boolean.TRUE } });
  44. }
  45. @Override
  46. public void setUp() throws Exception {
  47. super.setUp();
  48. git = new Git(db);
  49. }
  50. @Test(expected = RefNotFoundException.class)
  51. public void noTargetSet() throws Exception {
  52. git.describe().call();
  53. }
  54. @Test
  55. public void testDescribe() throws Exception {
  56. ObjectId c1 = modify("aaa");
  57. ObjectId c2 = modify("bbb");
  58. tag("alice-t1");
  59. ObjectId c3 = modify("ccc");
  60. tag("bob-t2");
  61. ObjectId c4 = modify("ddd");
  62. assertNameStartsWith(c4, "3e563c5");
  63. assertNull(describe(c1));
  64. assertNull(describe(c1, true, false));
  65. assertNull(describe(c1, "a*", "b*", "c*"));
  66. assertNull(describe(c2, "bob*"));
  67. assertNull(describe(c2, "?ob*"));
  68. if (useAnnotatedTags || describeUseAllTags) {
  69. assertEquals("alice-t1", describe(c2));
  70. assertEquals("alice-t1", describe(c2, "alice*"));
  71. assertEquals("alice-t1", describe(c2, "a*", "b*", "c*"));
  72. assertEquals("bob-t2", describe(c3));
  73. assertEquals("bob-t2-0-g44579eb", describe(c3, true, false));
  74. assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*"));
  75. assertEquals("alice-t1-1-g44579eb", describe(c3, "a??c?-t*"));
  76. assertEquals("bob-t2", describe(c3, "bob*"));
  77. assertEquals("bob-t2", describe(c3, "?ob*"));
  78. assertEquals("bob-t2", describe(c3, "a*", "b*", "c*"));
  79. // the value verified with git-describe(1)
  80. assertEquals("bob-t2-1-g3e563c5", describe(c4));
  81. assertEquals("bob-t2-1-g3e563c5", describe(c4, true, false));
  82. assertEquals("alice-t1-2-g3e563c5", describe(c4, "alice*"));
  83. assertEquals("bob-t2-1-g3e563c5", describe(c4, "bob*"));
  84. assertEquals("bob-t2-1-g3e563c5", describe(c4, "a*", "b*", "c*"));
  85. } else {
  86. assertEquals(null, describe(c2));
  87. assertEquals(null, describe(c3));
  88. assertEquals(null, describe(c4));
  89. assertEquals("3747db3", describe(c2, false, true));
  90. assertEquals("44579eb", describe(c3, false, true));
  91. assertEquals("3e563c5", describe(c4, false, true));
  92. }
  93. // test default target
  94. if (useAnnotatedTags) {
  95. assertEquals("bob-t2-1-g3e563c5", git.describe().call());
  96. assertEquals("bob-t2-1-g3e563c5",
  97. git.describe().setTags(false).call());
  98. assertEquals("bob-t2-1-g3e563c5",
  99. git.describe().setTags(true).call());
  100. } else {
  101. assertEquals(null, git.describe().call());
  102. assertEquals(null, git.describe().setTags(false).call());
  103. assertEquals("bob-t2-1-g3e563c5",
  104. git.describe().setTags(true).call());
  105. }
  106. }
  107. @Test
  108. public void testDescribeMultiMatch() throws Exception {
  109. ObjectId c1 = modify("aaa");
  110. tag("v1.0.0");
  111. tick();
  112. tag("v1.0.1");
  113. tick();
  114. tag("v1.1.0");
  115. tick();
  116. tag("v1.1.1");
  117. ObjectId c2 = modify("bbb");
  118. if (!useAnnotatedTags && !describeUseAllTags) {
  119. assertEquals(null, describe(c1));
  120. assertEquals(null, describe(c2));
  121. assertEquals("fd70040", describe(c1, false, true));
  122. assertEquals("b89dead", describe(c2, false, true));
  123. return;
  124. }
  125. // Ensure that if we're interested in any tags, we get the most recent tag
  126. // as per Git behaviour since 1.7.1.1
  127. if (useAnnotatedTags) {
  128. assertEquals("v1.1.1", describe(c1));
  129. assertEquals("v1.1.1-1-gb89dead", describe(c2));
  130. // Ensure that if we're only interested in one of multiple tags, we get the right match
  131. assertEquals("v1.0.1", describe(c1, "v1.0*"));
  132. assertEquals("v1.1.1", describe(c1, "v1.1*"));
  133. assertEquals("v1.0.1-1-gb89dead", describe(c2, "v1.0*"));
  134. assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.1*"));
  135. // Ensure that ordering of match precedence is preserved as per Git behaviour
  136. assertEquals("v1.1.1", describe(c1, "v1.0*", "v1.1*"));
  137. assertEquals("v1.1.1", describe(c1, "v1.1*", "v1.0*"));
  138. assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.0*", "v1.1*"));
  139. assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.1*", "v1.0*"));
  140. } else {
  141. // no timestamps so no guarantees on which tag is chosen
  142. assertNotNull(describe(c1));
  143. assertNotNull(describe(c2));
  144. assertNotNull(describe(c1, "v1.0*"));
  145. assertNotNull(describe(c1, "v1.1*"));
  146. assertNotNull(describe(c2, "v1.0*"));
  147. assertNotNull(describe(c2, "v1.1*"));
  148. // Ensure that ordering of match precedence is preserved as per Git behaviour
  149. assertNotNull(describe(c1, "v1.0*", "v1.1*"));
  150. assertNotNull(describe(c1, "v1.1*", "v1.0*"));
  151. assertNotNull(describe(c2, "v1.0*", "v1.1*"));
  152. assertNotNull(describe(c2, "v1.1*", "v1.0*"));
  153. }
  154. }
  155. /**
  156. * Make sure it finds a tag when not all ancestries include a tag.
  157. *
  158. * <pre>
  159. * c1 -+-&gt; T -
  160. * | |
  161. * +-&gt; c3 -+-&gt; c4
  162. * </pre>
  163. *
  164. * @throws Exception
  165. */
  166. @Test
  167. public void testDescribeBranch() throws Exception {
  168. ObjectId c1 = modify("aaa");
  169. ObjectId c2 = modify("bbb");
  170. tag("t");
  171. branch("b", c1);
  172. ObjectId c3 = modify("ccc");
  173. ObjectId c4 = merge(c2);
  174. assertNameStartsWith(c4, "119892b");
  175. if (useAnnotatedTags || describeUseAllTags) {
  176. assertEquals("2 commits: c4 and c3", "t-2-g119892b", describe(c4));
  177. } else {
  178. assertEquals(null, describe(c4));
  179. assertEquals("119892b", describe(c4, false, true));
  180. }
  181. assertNull(describe(c3));
  182. assertNull(describe(c3, true, false));
  183. }
  184. private void branch(String name, ObjectId base) throws GitAPIException {
  185. git.checkout().setCreateBranch(true).setName(name)
  186. .setStartPoint(base.name()).call();
  187. }
  188. /**
  189. * When t2 dominates t1, it's clearly preferable to describe by using t2.
  190. *
  191. * <pre>
  192. * t1 -+-&gt; t2 -
  193. * | |
  194. * +-&gt; c3 -+-&gt; c4
  195. * </pre>
  196. *
  197. * @throws Exception
  198. */
  199. @Test
  200. public void t1DominatesT2() throws Exception {
  201. ObjectId c1 = modify("aaa");
  202. tag("t1");
  203. ObjectId c2 = modify("bbb");
  204. tag("t2");
  205. branch("b", c1);
  206. ObjectId c3 = modify("ccc");
  207. assertNameStartsWith(c3, "0244e7f");
  208. ObjectId c4 = merge(c2);
  209. assertNameStartsWith(c4, "119892b");
  210. if (useAnnotatedTags || describeUseAllTags) {
  211. assertEquals("t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
  212. assertEquals("t1-1-g0244e7f", describe(c3));
  213. } else {
  214. assertEquals(null, describe(c4));
  215. assertEquals(null, describe(c3));
  216. assertEquals("119892b", describe(c4, false, true));
  217. assertEquals("0244e7f", describe(c3, false, true));
  218. }
  219. }
  220. /**
  221. * When t1 annotated dominates t2 lightweight tag
  222. *
  223. * <pre>
  224. * t1 -+-> t2 -
  225. * | |
  226. * +-> c3 -+-> c4
  227. * </pre>
  228. *
  229. * @throws Exception
  230. */
  231. @Test
  232. public void t1AnnotatedDominatesT2lightweight() throws Exception {
  233. ObjectId c1 = modify("aaa");
  234. tag("t1", useAnnotatedTags);
  235. ObjectId c2 = modify("bbb");
  236. tag("t2", false);
  237. assertNameStartsWith(c2, "3747db3");
  238. if (useAnnotatedTags && !describeUseAllTags) {
  239. assertEquals(
  240. "only annotated tag t1 expected to be used for describe",
  241. "t1-1-g3747db3", describe(c2)); // 1 commits: t2 overridden
  242. // by t1
  243. } else if (!useAnnotatedTags && !describeUseAllTags) {
  244. assertEquals("no commits to describe expected", null, describe(c2));
  245. } else {
  246. assertEquals("lightweight tag t2 expected in describe", "t2",
  247. describe(c2));
  248. }
  249. branch("b", c1);
  250. ObjectId c3 = modify("ccc");
  251. assertNameStartsWith(c3, "0244e7f");
  252. if (useAnnotatedTags || describeUseAllTags) {
  253. assertEquals("t1-1-g0244e7f", describe(c3));
  254. }
  255. ObjectId c4 = merge(c2);
  256. assertNameStartsWith(c4, "119892b");
  257. if (describeUseAllTags) {
  258. assertEquals(
  259. "2 commits for describe commit increment expected since lightweight tag: c4 and c3",
  260. "t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
  261. } else if (!useAnnotatedTags && !describeUseAllTags) {
  262. assertEquals("no matching commits expected", null, describe(c4));
  263. } else {
  264. assertEquals(
  265. "3 commits for describe commit increment expected since annotated tag: c4 and c3 and c2",
  266. "t1-3-g119892b", describe(c4)); //
  267. }
  268. }
  269. /**
  270. * When t1 is nearer than t2, t2 should be found
  271. *
  272. * <pre>
  273. * c1 -+-&gt; c2 -&gt; t1 -+
  274. * | |
  275. * +-&gt; t2 -&gt; c3 -+-&gt; c4
  276. * </pre>
  277. *
  278. * @throws Exception
  279. */
  280. @Test
  281. public void t1nearerT2() throws Exception {
  282. ObjectId c1 = modify("aaa");
  283. modify("bbb");
  284. ObjectId t1 = modify("ccc");
  285. tag("t1");
  286. branch("b", c1);
  287. modify("ddd");
  288. tag("t2");
  289. modify("eee");
  290. ObjectId c4 = merge(t1);
  291. assertNameStartsWith(c4, "bb389a4");
  292. if (useAnnotatedTags || describeUseAllTags) {
  293. assertEquals("t1-3-gbb389a4", describe(c4));
  294. } else {
  295. assertEquals(null, describe(c4));
  296. assertEquals("bb389a4", describe(c4, false, true));
  297. }
  298. }
  299. /**
  300. * When t1 and t2 have same depth native git seems to add the depths of both
  301. * paths
  302. *
  303. * <pre>
  304. * c1 -+-&gt; t1 -&gt; c2 -+
  305. * | |
  306. * +-&gt; t2 -&gt; c3 -+-&gt; c4
  307. * </pre>
  308. *
  309. * @throws Exception
  310. */
  311. @Test
  312. public void t1sameDepthT2() throws Exception {
  313. ObjectId c1 = modify("aaa");
  314. modify("bbb");
  315. tag("t1");
  316. ObjectId c2 = modify("ccc");
  317. branch("b", c1);
  318. modify("ddd");
  319. tag("t2");
  320. modify("eee");
  321. ObjectId c4 = merge(c2);
  322. assertNameStartsWith(c4, "bb389a4");
  323. if (useAnnotatedTags || describeUseAllTags) {
  324. assertEquals("t2-4-gbb389a4", describe(c4));
  325. } else {
  326. assertEquals(null, describe(c4));
  327. assertEquals("bb389a4", describe(c4, false, true));
  328. }
  329. }
  330. @Test
  331. public void globMatchWithSlashes() throws Exception {
  332. ObjectId c1 = modify("aaa");
  333. tag("a/b/version");
  334. ObjectId c2 = modify("bbb");
  335. tag("a/b/version2");
  336. if (useAnnotatedTags || describeUseAllTags) {
  337. assertEquals("a/b/version", describe(c1, "*/version*"));
  338. assertEquals("a/b/version2", describe(c2, "*/version*"));
  339. } else {
  340. assertNull(describe(c1));
  341. assertNull(describe(c1, "*/version*"));
  342. assertNull(describe(c2));
  343. assertNull(describe(c2, "*/version*"));
  344. }
  345. }
  346. private ObjectId merge(ObjectId c2) throws GitAPIException {
  347. return git.merge().include(c2).call().getNewHead();
  348. }
  349. private ObjectId modify(String content) throws Exception {
  350. File a = new File(db.getWorkTree(), "a.txt");
  351. touch(a, content);
  352. return git.commit().setAll(true).setMessage(content).call().getId();
  353. }
  354. private void tag(String tag) throws GitAPIException {
  355. tag(tag, this.useAnnotatedTags);
  356. }
  357. private void tag(String tag, boolean annotatedTag) throws GitAPIException {
  358. TagCommand tagCommand = git.tag().setName(tag)
  359. .setAnnotated(annotatedTag);
  360. if (annotatedTag) {
  361. tagCommand.setMessage(tag);
  362. }
  363. tagCommand.call();
  364. }
  365. private static void touch(File f, String contents) throws Exception {
  366. try (BufferedWriter w = Files.newBufferedWriter(f.toPath(), UTF_8)) {
  367. w.write(contents);
  368. }
  369. }
  370. private String describe(ObjectId c1, boolean longDesc, boolean always)
  371. throws GitAPIException, IOException {
  372. return git.describe().setTarget(c1).setTags(describeUseAllTags)
  373. .setLong(longDesc).setAlways(always).call();
  374. }
  375. private String describe(ObjectId c1) throws GitAPIException, IOException {
  376. return describe(c1, false, false);
  377. }
  378. private String describe(ObjectId c1, String... patterns) throws Exception {
  379. return git.describe().setTarget(c1).setTags(describeUseAllTags)
  380. .setMatch(patterns).call();
  381. }
  382. private static void assertNameStartsWith(ObjectId c4, String prefix) {
  383. assertTrue(c4.name(), c4.name().startsWith(prefix));
  384. }
  385. }