Skip to content

Commit 2d12149

Browse files
authored
Merge pull request #440 from fo-code/delta-api-extension
Extended delta API
2 parents ecf8024 + 864bf4b commit 2d12149

File tree

5 files changed

+110
-70
lines changed

5 files changed

+110
-70
lines changed

plugin/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<font-awesome-api.version>6.0.0-1</font-awesome-api.version>
3030
<plugin-util-api.version>2.14.0</plugin-util-api.version>
3131
<data-tables-api.version>1.11.4-3</data-tables-api.version>
32-
<forensics-api-plugin.version>1.9.0</forensics-api-plugin.version>
32+
<forensics-api-plugin.version>1.12.0</forensics-api-plugin.version>
3333
<bootstrap5-api.version>5.1.3-6</bootstrap5-api.version>
3434
<streamex.version>0.8.1</streamex.version>
3535
</properties>

plugin/src/main/java/io/jenkins/plugins/forensics/git/delta/GitDeltaCalculator.java

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import java.util.Optional;
55

66
import edu.hm.hafner.util.FilteredLog;
7-
import edu.umd.cs.findbugs.annotations.NonNull;
87
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
98

109
import org.jenkinsci.plugins.gitclient.GitClient;
10+
import hudson.model.Run;
1111

1212
import io.jenkins.plugins.forensics.delta.DeltaCalculator;
1313
import io.jenkins.plugins.forensics.delta.model.Delta;
14+
import io.jenkins.plugins.forensics.git.reference.GitCommitsRecord;
1415
import io.jenkins.plugins.forensics.git.util.RemoteResultWrapper;
1516

1617
/**
@@ -22,6 +23,7 @@
2223
public class GitDeltaCalculator extends DeltaCalculator {
2324

2425
static final String DELTA_ERROR = "Computing delta information failed with an exception:";
26+
static final String EMPTY_COMMIT_ERROR = "Calculating the Git code delta is not possible due to an unknown commit ID";
2527

2628
private static final long serialVersionUID = -7303579046266608368L;
2729

@@ -39,25 +41,30 @@ public GitDeltaCalculator(final GitClient git) {
3941
}
4042

4143
@Override
42-
public Optional<Delta> calculateDelta(@NonNull final String currentCommit, @NonNull final String referenceCommit,
43-
@NonNull final FilteredLog log) {
44-
try {
45-
log.logInfo(
46-
"Invoking Git delta calculator for determining the made changes between the commits with the IDs %s and %s",
47-
currentCommit, referenceCommit);
48-
44+
public Optional<Delta> calculateDelta(final Run<?, ?> build, final Run<?, ?> referenceBuild,
45+
final String scmKeyFilter, final FilteredLog log) {
46+
Optional<GitCommitsRecord> buildCommits = GitCommitsRecord.findRecordForScm(build, scmKeyFilter);
47+
Optional<GitCommitsRecord> referenceCommits = GitCommitsRecord.findRecordForScm(referenceBuild, scmKeyFilter);
48+
if (buildCommits.isPresent() && referenceCommits.isPresent()) {
49+
String currentCommit = buildCommits.get().getLatestCommit();
50+
String referenceCommit = referenceCommits.get().getLatestCommit();
4951
if (!currentCommit.isEmpty() && !referenceCommit.isEmpty()) {
50-
RemoteResultWrapper<Delta> wrapped = git.withRepository(
51-
new DeltaRepositoryCallback(currentCommit, referenceCommit));
52-
wrapped.getInfoMessages().forEach(log::logInfo);
53-
54-
return Optional.of(wrapped.getResult());
52+
log.logInfo(
53+
"Invoking Git delta calculator for determining the made changes between the commits with the IDs %s and %s",
54+
currentCommit, referenceCommit);
55+
try {
56+
RemoteResultWrapper<Delta> wrapped = git.withRepository(
57+
new DeltaRepositoryCallback(currentCommit, referenceCommit));
58+
wrapped.getInfoMessages().forEach(log::logInfo);
59+
return Optional.of(wrapped.getResult());
60+
}
61+
catch (IOException | InterruptedException exception) {
62+
log.logException(exception, DELTA_ERROR);
63+
return Optional.empty();
64+
}
5565
}
5666
}
57-
catch (IOException | InterruptedException exception) {
58-
log.logException(exception, DELTA_ERROR);
59-
}
60-
67+
log.logError(EMPTY_COMMIT_ERROR);
6168
return Optional.empty();
6269
}
6370
}

plugin/src/test/java/io/jenkins/plugins/forensics/git/delta/GitDeltaCalculatorITest.java

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.jenkins.plugins.forensics.git.delta;
22

3+
import java.io.IOException;
34
import java.util.Collection;
45
import java.util.Optional;
56
import java.util.Set;
@@ -10,15 +11,21 @@
1011
import edu.hm.hafner.util.FilteredLog;
1112
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
1213

14+
import hudson.model.FreeStyleProject;
15+
import hudson.model.Run;
16+
import hudson.plugins.git.GitSCM;
17+
1318
import io.jenkins.plugins.forensics.delta.model.Change;
1419
import io.jenkins.plugins.forensics.delta.model.ChangeEditType;
1520
import io.jenkins.plugins.forensics.delta.model.Delta;
1621
import io.jenkins.plugins.forensics.delta.model.FileChanges;
1722
import io.jenkins.plugins.forensics.delta.model.FileEditType;
1823
import io.jenkins.plugins.forensics.git.delta.model.GitDelta;
24+
import io.jenkins.plugins.forensics.git.reference.GitReferenceRecorder;
1925
import io.jenkins.plugins.forensics.git.util.GitITest;
2026

2127
import static io.jenkins.plugins.forensics.assertions.Assertions.*;
28+
import static org.mockito.Mockito.*;
2229

2330
/**
2431
* Integration test for the class {@link GitDeltaCalculator}.
@@ -27,6 +34,8 @@
2734
*/
2835
public class GitDeltaCalculatorITest extends GitITest {
2936

37+
private static final String EMPTY_SCM_KEY = "";
38+
3039
/**
3140
* The delta result should be empty if there are invalid commits.
3241
*/
@@ -35,9 +44,7 @@ public void shouldCreateEmptyDeltaIfCommitsAreInvalid() {
3544
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
3645

3746
FilteredLog log = createLog();
38-
Optional<Delta> delta = deltaCalculator.calculateDelta("", "", log);
39-
40-
assertThat(delta).isEmpty();
47+
assertThat(deltaCalculator.calculateDelta(mock(Run.class), mock(Run.class), EMPTY_SCM_KEY, log)).isEmpty();
4148
}
4249

4350
/**
@@ -46,18 +53,22 @@ public void shouldCreateEmptyDeltaIfCommitsAreInvalid() {
4653
@Test
4754
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "The cast is confirmed via an assertion")
4855
public void shouldCreateDiffFile() {
56+
FreeStyleProject job = createJobWithReferenceRecorder();
57+
4958
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
5059
FilteredLog log = createLog();
5160

52-
final String referenceCommit = getHead();
53-
final String fileName = "newFile";
54-
final String content = "content";
61+
Run<?, ?> referenceBuild = buildSuccessfully(job);
62+
String referenceCommit = getHead();
63+
String fileName = "newFile";
64+
String content = "content";
5565
writeFile(fileName, content);
5666
addFile(fileName);
5767
commit("test");
58-
final String currentCommit = getHead();
68+
Run<?, ?> build = buildSuccessfully(job);
69+
String currentCommit = getHead();
5970

60-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
71+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
6172
assertThat(result).isNotEmpty();
6273

6374
Delta delta = result.get();
@@ -80,19 +91,20 @@ public void shouldCreateDiffFile() {
8091
*/
8192
@Test
8293
public void shouldDetermineAddedFile() {
94+
FreeStyleProject job = createJobWithReferenceRecorder();
8395
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
8496
FilteredLog log = createLog();
8597

86-
final String referenceCommit = getHead();
98+
Run<?, ?> referenceBuild = buildSuccessfully(job);
8799

88-
final String newFileName = "newFile";
89-
final String content = "added";
100+
String newFileName = "newFile";
101+
String content = "added";
90102
writeFile(newFileName, content);
91103
addFile(newFileName);
92104
commit("test");
93-
final String currentCommit = getHead();
105+
Run<?, ?> build = buildSuccessfully(job);
94106

95-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
107+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
96108
assertThat(result).isNotEmpty();
97109

98110
Delta delta = result.get();
@@ -107,16 +119,17 @@ public void shouldDetermineAddedFile() {
107119
*/
108120
@Test
109121
public void shouldDetermineModifiedFile() {
122+
FreeStyleProject job = createJobWithReferenceRecorder();
110123
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
111124
FilteredLog log = createLog();
112125

113-
final String content = "modified";
126+
String content = "modified";
114127
commitFile("test");
115-
final String referenceCommit = getHead();
128+
Run<?, ?> referenceBuild = buildSuccessfully(job);
116129
commitFile(content);
117-
final String currentCommit = getHead();
130+
Run<?, ?> build = buildSuccessfully(job);
118131

119-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
132+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
120133
assertThat(result).isNotEmpty();
121134

122135
Delta delta = result.get();
@@ -131,17 +144,18 @@ public void shouldDetermineModifiedFile() {
131144
*/
132145
@Test
133146
public void shouldDetermineDeletedFile() {
147+
FreeStyleProject job = createJobWithReferenceRecorder();
134148
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
135149
FilteredLog log = createLog();
136150

137-
final String content = "content";
151+
String content = "content";
138152
commitFile(content);
139-
final String referenceCommit = getHead();
153+
Run<?, ?> referenceBuild = buildSuccessfully(job);
140154
git("rm", GitITest.INITIAL_FILE);
141155
commit("test");
142-
final String currentCommit = getHead();
156+
Run<?, ?> build = buildSuccessfully(job);
143157

144-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
158+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
145159
assertThat(result).isNotEmpty();
146160

147161
Delta delta = result.get();
@@ -156,17 +170,18 @@ public void shouldDetermineDeletedFile() {
156170
*/
157171
@Test
158172
public void shouldDetermineAddedLines() {
173+
FreeStyleProject job = createJobWithReferenceRecorder();
159174
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
160175
FilteredLog log = createLog();
161176

162-
final String content = "Test\nTest\n";
163-
final String insertedContent = "Test\nInsert1\nInsert2\nTest\n";
177+
String content = "Test\nTest\n";
178+
String insertedContent = "Test\nInsert1\nInsert2\nTest\n";
164179
commitFile(content);
165-
final String referenceCommit = getHead();
180+
Run<?, ?> referenceBuild = buildSuccessfully(job);
166181
commitFile(insertedContent);
167-
final String currentCommit = getHead();
182+
Run<?, ?> build = buildSuccessfully(job);
168183

169-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
184+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
170185
assertThat(result).isNotEmpty();
171186

172187
Delta delta = result.get();
@@ -184,17 +199,18 @@ public void shouldDetermineAddedLines() {
184199
*/
185200
@Test
186201
public void shouldDetermineModifiedLines() {
202+
FreeStyleProject job = createJobWithReferenceRecorder();
187203
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
188204
FilteredLog log = createLog();
189205

190-
final String content = "Test\nTest\nTest\nTest";
191-
final String modified = "Test\nModified\nModified2\nTest";
206+
String content = "Test\nTest\nTest\nTest";
207+
String modified = "Test\nModified\nModified2\nTest";
192208
commitFile(content);
193-
final String referenceCommit = getHead();
209+
Run<?, ?> referenceBuild = buildSuccessfully(job);
194210
commitFile(modified);
195-
final String currentCommit = getHead();
211+
Run<?, ?> build = buildSuccessfully(job);
196212

197-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
213+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
198214
assertThat(result).isNotEmpty();
199215

200216
Delta delta = result.get();
@@ -212,17 +228,18 @@ public void shouldDetermineModifiedLines() {
212228
*/
213229
@Test
214230
public void shouldDetermineDeletedLines() {
231+
FreeStyleProject job = createJobWithReferenceRecorder();
215232
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
216233
FilteredLog log = createLog();
217234

218-
final String content = "Test\nTest3\nTest";
219-
final String modified = "Test\nTest";
235+
String content = "Test\nTest3\nTest";
236+
String modified = "Test\nTest";
220237
commitFile(content);
221-
final String referenceCommit = getHead();
238+
Run<?, ?> referenceBuild = buildSuccessfully(job);
222239
commitFile(modified);
223-
final String currentCommit = getHead();
240+
Run<?, ?> build = buildSuccessfully(job);
224241

225-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
242+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
226243
assertThat(result).isNotEmpty();
227244

228245
Delta delta = result.get();
@@ -240,17 +257,18 @@ public void shouldDetermineDeletedLines() {
240257
*/
241258
@Test
242259
public void shouldDetermineAllChangeTypesTogether() {
260+
FreeStyleProject job = createJobWithReferenceRecorder();
243261
GitDeltaCalculator deltaCalculator = createDeltaCalculator();
244262
FilteredLog log = createLog();
245263

246-
final String content = "Test1\nTest2\nTest3\nTest4";
247-
final String newContent = "Modified\nTest2\nInserted\nTest3";
264+
String content = "Test1\nTest2\nTest3\nTest4";
265+
String newContent = "Modified\nTest2\nInserted\nTest3";
248266
commitFile(content);
249-
final String referenceCommit = getHead();
267+
Run<?, ?> referenceBuild = buildSuccessfully(job);
250268
commitFile(newContent);
251-
final String currentCommit = getHead();
269+
Run<?, ?> build = buildSuccessfully(job);
252270

253-
Optional<Delta> result = deltaCalculator.calculateDelta(currentCommit, referenceCommit, log);
271+
Optional<Delta> result = deltaCalculator.calculateDelta(build, referenceBuild, EMPTY_SCM_KEY, log);
254272
assertThat(result).isNotEmpty();
255273

256274
Delta delta = result.get();
@@ -344,4 +362,21 @@ private FilteredLog createLog() {
344362
private GitDeltaCalculator createDeltaCalculator() {
345363
return new GitDeltaCalculator(createGitClient());
346364
}
365+
366+
/**
367+
* Creates a {@link FreeStyleProject} which contains a {@link GitReferenceRecorder} within the publishers list.
368+
*
369+
* @return the created project
370+
*/
371+
private FreeStyleProject createJobWithReferenceRecorder() {
372+
try {
373+
FreeStyleProject job = createFreeStyleProject();
374+
job.setScm(new GitSCM(getRepositoryRoot()));
375+
job.getPublishersList().add(new GitReferenceRecorder());
376+
return job;
377+
}
378+
catch (IOException exception) {
379+
throw new AssertionError(exception);
380+
}
381+
}
347382
}
Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.jenkins.plugins.forensics.git.delta;
22

3-
import java.io.IOException;
43
import java.util.Optional;
54

65
import org.apache.commons.lang3.StringUtils;
@@ -9,9 +8,11 @@
98
import edu.hm.hafner.util.FilteredLog;
109

1110
import org.jenkinsci.plugins.gitclient.GitClient;
11+
import hudson.model.Run;
1212

1313
import io.jenkins.plugins.forensics.delta.model.Delta;
1414

15+
import static io.jenkins.plugins.forensics.git.delta.GitDeltaCalculator.*;
1516
import static org.assertj.core.api.Assertions.*;
1617
import static org.mockito.Mockito.*;
1718

@@ -22,21 +23,17 @@
2223
*/
2324
class GitDeltaCalculatorTest {
2425

26+
private static final String EMPTY_SCM_KEY = "";
27+
2528
@Test
26-
void shouldAbortIfWithRepositoryThrowsException() throws IOException, InterruptedException {
27-
GitClient gitClient = createGitClientWithException(new IOException());
29+
void shouldAbortIfCommitsAreEmpty() {
30+
GitClient gitClient = mock(GitClient.class);
2831
GitDeltaCalculator deltaCalculator = new GitDeltaCalculator(gitClient);
2932
FilteredLog log = new FilteredLog(StringUtils.EMPTY);
3033

31-
Optional<Delta> result = deltaCalculator.calculateDelta("x", "x", log);
34+
Optional<Delta> result = deltaCalculator.calculateDelta(mock(Run.class), mock(Run.class), EMPTY_SCM_KEY, log);
3235

3336
assertThat(result).isEmpty();
34-
assertThat(log.getErrorMessages()).contains(GitDeltaCalculator.DELTA_ERROR);
35-
}
36-
37-
private GitClient createGitClientWithException(final Exception exception) throws InterruptedException, IOException {
38-
GitClient gitClient = mock(GitClient.class);
39-
when(gitClient.withRepository(any())).thenThrow(exception);
40-
return gitClient;
37+
assertThat(log.getErrorMessages()).contains(EMPTY_COMMIT_ERROR);
4138
}
4239
}

0 commit comments

Comments
 (0)