Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added its/scm-repo/dummy-hg-with-subrepo.zip
Binary file not shown.
21 changes: 21 additions & 0 deletions its/src/test/java/com/sonarsource/it/scm/MercurialTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,27 @@ public void testBlame() throws Exception {
MapEntry.entry(3, new LineData("f553ba9f524c", "2012-07-18T18:26:11+0200", "[email protected]")));
}

@Test
public void testBlameSubrepo() throws Exception {
File projectDir = temp.newFolder();
ZipUtils.unzip(new File("scm-repo/dummy-hg-with-subrepo.zip"), projectDir);
File fileInRepo = new File(projectDir, "dummy-hg-with-subrepo/fileinrepo.txt");
File fileInSubRepo = new File(projectDir, "dummy-hg-with-subrepo/subrepo/fileinsubrepo.txt");
MavenBuild sonar = MavenBuild.create(fileInRepo)
.setGoals("verify sonar:sonar")
.setProperty("sonar.scm.disabled", "false");
orchestrator.executeBuilds(sonar);
assertThat(getScmData("dummy-hg-with-subrepo:dummy:fileinrepo.txt"))
.contains(
MapEntry.entry(0, new LineData("6db77db9dbc4", "2021-10-02 13:45:42+0200", "koenpoppe")),
MapEntry.entry(2, new LineData("1c43854ced78", "2021-10-02 13:46:33+0200", "koenpoppe")));
assertThat(getScmData("dummy-hg-with-subrepo:dummy:subrepo/fileinsubrepo.txt"))
.contains(
MapEntry.entry(0, new LineData("ba3299cdfa0e", "2021-10-02 13:40:29+0200", "koenpoppe")),
MapEntry.entry(1, new LineData("73172c209d54", "2021-10-02 13:40:42+0200", "koenpoppe")),
MapEntry.entry(2, new LineData("f5825590563b", "2021-10-02 13:41:07+0200", "koenpoppe")));
}

private static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

private class LineData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.sonar.plugins.scm.mercurial;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -112,8 +113,21 @@ private int execute(Command cl, StreamConsumer consumer, StreamConsumer stderr)
}

private Command createCommandLine(File workingDirectory, String filename) {
// Determine root repo, i.e., where the .hg directory is
Path workingPath = workingDirectory.toPath();
Path filePath = new File(workingDirectory, filename).toPath();
Path repoRootPath = filePath.getParent();
while (!repoRootPath.equals(workingPath)) {
File hgDir = new File(repoRootPath.toFile(), ".hg");
if (hgDir.exists()) {
break;
}
repoRootPath = repoRootPath.getParent();
}
String filePathInRepo = repoRootPath.relativize(filePath).toString();

Command cl = Command.create("hg");
cl.setDirectory(workingDirectory);
cl.setDirectory(repoRootPath.toFile());
cl.addArgument("blame");
// Hack to support Mercurial prior to 2.1
if (!settings.getBoolean("sonar.mercurial.considerWhitespaces")) {
Expand All @@ -131,7 +145,7 @@ private Command createCommandLine(File workingDirectory, String filename) {
// Make filename safe for usage with the "hg" command
// See Guideline 10 at https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
cl.addArgument("--");
cl.addArgument(filename);
cl.addArgument(filePathInRepo);
return cl;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ public void shouldProcessMaliciousFileBlockingAttack() throws IOException {
new MercurialBlameCommand(commandExecutor, new MapSettings())
.blame(input, result);

assertThat(commandCaptor.getValue().getDirectory()).isEqualTo(baseDir);
assertThat(commandCaptor.getValue().getArguments())
.containsExactly("blame", "-w", "-v", "--user", "--date", "--changeset", "--", MALICIOUS_FILENAME);

Expand All @@ -199,4 +200,80 @@ public void shouldProcessMaliciousFileBlockingAttack() throws IOException {
.author("[email protected]")));
}

@Test
public void takeHgDirFromSubrepository() throws IOException {
// In main repository
{
File mainrepoSource = new File(baseDir, "src/mainrepoSource.xoo");
FileUtils.write(mainrepoSource, "sample content");
InputFile inputFile = new TestInputFileBuilder("mainrepoSource", "src/mainrepoSource.xoo")
.setModuleBaseDir(baseDir.toPath())
.build();
fs.add(inputFile);

BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);

ArgumentCaptor<Command> commandCaptor = ArgumentCaptor.forClass(Command.class);
when(commandExecutor.execute(commandCaptor.capture(), any(), any(), anyLong())).thenAnswer((Answer<Integer>) invocation -> {
StreamConsumer outConsumer = (StreamConsumer) invocation.getArguments()[1];
outConsumer.consumeLine("John Something <[email protected]> 447af27e2bc1 Tue Nov 04 11:01:10 2020 +0100: foo");
return 0;
});

when(input.filesToBlame()).thenReturn(singletonList(inputFile));
new MercurialBlameCommand(commandExecutor, new MapSettings())
.blame(input, result);

assertThat(commandCaptor.getValue().getDirectory()).isEqualTo(baseDir);
assertThat(commandCaptor.getValue().getArguments())
.containsExactly("blame", "-w", "-v", "--user", "--date", "--changeset", "--", "src/mainrepoSource.xoo");

verify(result).blameResult(inputFile,
singletonList(new BlameLine()
.date(DateUtils.parseDateTime("2020-11-04T11:01:10+0100"))
.revision("447af27e2bc1")
.author("[email protected]")));
}

// In sub repository
{
File subrepoDir = new File(baseDir, "subrepo");
assertThat(subrepoDir.mkdir()).isTrue();
File subrepoHgDir = new File(subrepoDir, ".hg");
assertThat(subrepoHgDir.mkdir()).isTrue();
File subrepoSource = new File(subrepoDir, "src/subrepoSource.xoo");
FileUtils.write(subrepoSource, "sample content");
InputFile inputFile = new TestInputFileBuilder("bar", "subrepo/src/subrepoSource.xoo")
.setModuleBaseDir(baseDir.toPath())
.build();
fs.add(inputFile);

BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);

ArgumentCaptor<Command> commandCaptor = ArgumentCaptor.forClass(Command.class);
when(commandExecutor.execute(commandCaptor.capture(), any(), any(), anyLong())).thenAnswer((Answer<Integer>) invocation -> {
StreamConsumer outConsumer = (StreamConsumer) invocation.getArguments()[1];
outConsumer.consumeLine("John Something <[email protected]> 447af27e2bc1 Tue Nov 04 11:01:10 2020 +0100: foo");
return 0;
});

when(input.filesToBlame()).thenReturn(singletonList(inputFile));

new MercurialBlameCommand(commandExecutor, new MapSettings())
.blame(input, result);

assertThat(commandCaptor.getValue().getDirectory()).isEqualTo(subrepoDir);
assertThat(commandCaptor.getValue().getArguments())
.containsExactly("blame", "-w", "-v", "--user", "--date", "--changeset", "--", "src/subrepoSource.xoo");

verify(result).blameResult(inputFile,
singletonList(new BlameLine()
.date(DateUtils.parseDateTime("2020-11-04T11:01:10+0100"))
.revision("447af27e2bc1")
.author("[email protected]")));
}
}

}