Skip to content

Commit 86c7ba9

Browse files
committed
Confirm commit summary truncates with CLI git
JENKINS-29977 reports that command line git truncates on the first word boundary preceding character 73 in the commit summary. JGit does not truncate. This test is intended to confirm that the existing behavior is retained. New optional behavior is being prepared based on a global switch that will disable truncation of long commit summaries.
1 parent e91aa35 commit 86c7ba9

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package hudson.plugins.git;
2+
3+
import java.io.File;
4+
import java.io.FileNotFoundException;
5+
import java.io.PrintWriter;
6+
import java.io.StringWriter;
7+
import java.io.UnsupportedEncodingException;
8+
import java.util.ArrayList;
9+
import java.util.Arrays;
10+
import java.util.Collection;
11+
import java.util.Collections;
12+
import java.util.List;
13+
import java.util.Random;
14+
import java.util.UUID;
15+
16+
import org.eclipse.jgit.lib.Constants;
17+
import org.eclipse.jgit.lib.ObjectId;
18+
19+
import hudson.EnvVars;
20+
import hudson.model.TaskListener;
21+
import org.jenkinsci.plugins.gitclient.Git;
22+
import org.jenkinsci.plugins.gitclient.GitClient;
23+
24+
import static org.hamcrest.Matchers.*;
25+
import static org.junit.Assert.*;
26+
import org.junit.BeforeClass;
27+
import org.junit.ClassRule;
28+
import org.junit.Test;
29+
import org.junit.rules.TemporaryFolder;
30+
import org.junit.runner.RunWith;
31+
import org.junit.runners.Parameterized;
32+
import org.jvnet.hudson.test.Issue;
33+
34+
@RunWith(Parameterized.class)
35+
public class GitChangeSetTruncateTest {
36+
37+
@ClassRule
38+
public static TemporaryFolder tempFolder = new TemporaryFolder();
39+
40+
private static File repoRoot = null;
41+
42+
private static final Random random = new Random();
43+
44+
/* Arguments to the constructor */
45+
private final String gitImpl;
46+
private final String commitSummary;
47+
private final String expectedSummary;
48+
49+
/* Computed in the constructor, used in tests */
50+
private final GitChangeSet changeSet;
51+
52+
private static class TestData {
53+
54+
final public String testDataCommitSummary;
55+
final public String testDataExpectedSummary;
56+
57+
TestData(String commitSummary, String expectedSummary) {
58+
this.testDataCommitSummary = commitSummary;
59+
this.testDataExpectedSummary = expectedSummary;
60+
}
61+
}
62+
63+
// 1 2 3 4 5 6 7
64+
// 1234567890123456789012345678901234567890123456789012345678901234567890
65+
private final static String SEVENTY_CHARS = "[JENKINS-012345] 8901 34567 90 23456 8901 34567 9012 4567890 2345678 0";
66+
private final static String EIGHTY_CHARS = "12345678901234567890123456789012345678901234567890123456789012345678901234567890";
67+
68+
private final static TestData[] TEST_DATA = {
69+
new TestData(EIGHTY_CHARS, EIGHTY_CHARS), // surprising that longer than 72 is returned
70+
new TestData(SEVENTY_CHARS, SEVENTY_CHARS),
71+
new TestData(SEVENTY_CHARS + " 2", SEVENTY_CHARS + " 2"),
72+
new TestData(SEVENTY_CHARS + " 2 4", SEVENTY_CHARS + " 2"),
73+
new TestData(SEVENTY_CHARS + " 23", SEVENTY_CHARS),
74+
new TestData(SEVENTY_CHARS + " 2&4", SEVENTY_CHARS),
75+
new TestData(SEVENTY_CHARS + "1", SEVENTY_CHARS + "1"),
76+
new TestData(SEVENTY_CHARS + "1 3", SEVENTY_CHARS + "1"),
77+
new TestData(SEVENTY_CHARS + "1 <4", SEVENTY_CHARS + "1"),
78+
new TestData(SEVENTY_CHARS + "1 3 5", SEVENTY_CHARS + "1"),
79+
new TestData(SEVENTY_CHARS + "1;", SEVENTY_CHARS + "1;"),
80+
new TestData(SEVENTY_CHARS + "1; 4", SEVENTY_CHARS + "1;"),
81+
new TestData(SEVENTY_CHARS + " " + SEVENTY_CHARS, SEVENTY_CHARS),
82+
new TestData(SEVENTY_CHARS + " " + SEVENTY_CHARS, SEVENTY_CHARS + " ") // surprising that trailing space is preserved
83+
};
84+
85+
public GitChangeSetTruncateTest(String gitImpl, String commitSummary, String expectedSummary) throws Exception {
86+
this.gitImpl = gitImpl;
87+
this.commitSummary = commitSummary;
88+
this.expectedSummary = expectedSummary;
89+
GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()).in(repoRoot).using(gitImpl).getClient();
90+
final ObjectId head = commitOneFile(gitClient, commitSummary);
91+
StringWriter changelogStringWriter = new StringWriter();
92+
gitClient.changelog().includes(head).to(changelogStringWriter).execute();
93+
List<String> changeLogList = Arrays.asList(changelogStringWriter.toString().split("\n"));
94+
changeSet = new GitChangeSet(changeLogList, random.nextBoolean());
95+
}
96+
97+
@Parameterized.Parameters(name = "{0} \"{1}\" --->>> \"{2}\"")
98+
public static Collection gitObjects() {
99+
String[] implementations = {"git", "jgit"};
100+
List<Object[]> arguments = new ArrayList<>();
101+
for (String implementation : implementations) {
102+
for (TestData sample : TEST_DATA) {
103+
/* Expect truncated message from git, full message from JGit */
104+
String expected = implementation.equals("git") ? sample.testDataExpectedSummary : sample.testDataCommitSummary;
105+
Object[] item = {implementation, sample.testDataCommitSummary, expected};
106+
arguments.add(item);
107+
}
108+
}
109+
Collections.shuffle(arguments); // Execute in random order
110+
return arguments;
111+
}
112+
113+
@BeforeClass
114+
public static void createRepo() throws Exception {
115+
repoRoot = tempFolder.newFolder();
116+
String initialImpl = random.nextBoolean() ? "git" : "jgit";
117+
GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars()).in(repoRoot).using(initialImpl).getClient();
118+
gitClient.init_().workspace(repoRoot.getAbsolutePath()).execute();
119+
}
120+
121+
private ObjectId commitOneFile(GitClient gitClient, final String commitSummary) throws Exception {
122+
String path = "One-File.txt";
123+
String content = String.format("A random UUID: %s\n", UUID.randomUUID().toString());
124+
/* randomize whether commit message is single line or multi-line */
125+
String commitMessageBody = random.nextBoolean() ? "\n\n" + "committing " + path + " with content:\n\n" + content : "";
126+
String commitMessage = commitSummary + commitMessageBody;
127+
createFile(path, content);
128+
gitClient.add(path);
129+
gitClient.commit(commitMessage);
130+
List<ObjectId> headList = gitClient.revList(Constants.HEAD);
131+
assertThat(headList.size(), is(greaterThan(0)));
132+
return headList.get(0);
133+
}
134+
135+
private void createFile(String path, String content) throws Exception {
136+
File aFile = new File(repoRoot, path);
137+
File parentDir = aFile.getParentFile();
138+
if (parentDir != null) {
139+
parentDir.mkdirs();
140+
}
141+
try (PrintWriter writer = new PrintWriter(aFile, "UTF-8")) {
142+
writer.printf(content);
143+
} catch (FileNotFoundException | UnsupportedEncodingException ex) {
144+
throw new GitException(ex);
145+
}
146+
}
147+
148+
@Test
149+
@Issue("JENKINS-29977") // CLI git truncates first line of commit message in Changes page
150+
public void summaryTruncatedAtLastWord72CharactersOrLess() throws Exception {
151+
assertThat(changeSet.getMsg(), is(expectedSummary));
152+
}
153+
}

0 commit comments

Comments
 (0)