-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SLCORE-1142 Improve Git blaming for the analysis #1247
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,8 @@ static NewCodeDefinition withNumberOfDaysWithDate(int days, long thresholdDate) | |
return new NewCodeNumberOfDaysWithDate(days, thresholdDate); | ||
} | ||
|
||
long getThresholdDate(); | ||
|
||
static NewCodeDefinition withPreviousVersion(long thresholdDate, @Nullable String version) { | ||
return new NewCodePreviousVersion(thresholdDate, version); | ||
} | ||
|
@@ -116,6 +118,11 @@ public boolean isSupported() { | |
return true; | ||
} | ||
|
||
@Override | ||
public long getThresholdDate() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this method also be implemented in |
||
return Instant.now().minus(days, ChronoUnit.DAYS).toEpochMilli(); | ||
} | ||
|
||
// Text used by IDEs in the UI. Communicate changes to IDE squad prior to changing the wording. | ||
@Override | ||
public String toString() { | ||
|
@@ -216,6 +223,12 @@ public String getBranchName() { | |
return branchName; | ||
} | ||
|
||
@Override | ||
public long getThresholdDate() { | ||
// instead of Long.MAX_VALUE it's set for Instant.now() in case it will be used for git blame limit | ||
return Instant.now().toEpochMilli(); | ||
} | ||
|
||
// Text used by IDEs in the UI. Communicate changes to IDE squad prior to changing the wording. | ||
@Override | ||
public String toString() { | ||
|
@@ -239,6 +252,12 @@ public boolean isOnNewCode(long creationDate) { | |
return true; | ||
} | ||
|
||
@Override | ||
public long getThresholdDate() { | ||
// instead of 0L it's set for Instant.now() in case it will be used for git blame limit (which shouldn't normally happen) | ||
return Instant.now().toEpochMilli(); | ||
} | ||
|
||
@Override | ||
public boolean isSupported() { | ||
return true; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
import java.io.InputStream; | ||
import java.net.URI; | ||
import java.nio.file.Path; | ||
import java.time.Instant; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
@@ -97,15 +98,16 @@ public static List<URI> getVSCChangedFiles(@Nullable Path baseDir) { | |
} | ||
} | ||
|
||
public static SonarLintBlameResult getBlameResult(Path projectBaseDir, Set<Path> projectBaseRelativeFilePaths, @Nullable UnaryOperator<String> fileContentProvider) { | ||
return getBlameResult(projectBaseDir, projectBaseRelativeFilePaths, fileContentProvider, GitUtils::checkIfEnabled); | ||
public static SonarLintBlameResult getBlameResult(Path projectBaseDir, Set<Path> projectBaseRelativeFilePaths, | ||
@Nullable UnaryOperator<String> fileContentProvider, long thresholdDate) { | ||
return getBlameResult(projectBaseDir, projectBaseRelativeFilePaths, fileContentProvider, GitUtils::checkIfEnabled, thresholdDate); | ||
} | ||
|
||
public static SonarLintBlameResult getBlameResult(Path projectBaseDir, Set<Path> projectBaseRelativeFilePaths, @Nullable UnaryOperator<String> fileContentProvider, | ||
Predicate<Path> isEnabled) { | ||
static SonarLintBlameResult getBlameResult(Path projectBaseDir, Set<Path> projectBaseRelativeFilePaths, @Nullable UnaryOperator<String> fileContentProvider, | ||
Predicate<Path> isEnabled, long thresholdDate) { | ||
if (isEnabled.test(projectBaseDir)) { | ||
LOG.debug("Using native git blame"); | ||
return blameFromNativeCommand(projectBaseDir, projectBaseRelativeFilePaths); | ||
return blameFromNativeCommand(projectBaseDir, projectBaseRelativeFilePaths, thresholdDate); | ||
} else { | ||
LOG.debug("Falling back to JGit git blame"); | ||
return blameWithFilesGitCommand(projectBaseDir, projectBaseRelativeFilePaths, fileContentProvider); | ||
|
@@ -173,13 +175,14 @@ private static String executeGitCommand(Path workingDir, String... command) thro | |
return String.join(System.lineSeparator(), commandResult); | ||
} | ||
|
||
public static SonarLintBlameResult blameFromNativeCommand(Path projectBaseDir, Set<Path> projectBaseRelativeFilePaths) { | ||
public static SonarLintBlameResult blameFromNativeCommand(Path projectBaseDir, Set<Path> projectBaseRelativeFilePaths, long thresholdDate) { | ||
var nativeExecutable = getNativeGitExecutable(); | ||
if (nativeExecutable != null) { | ||
for (var relativeFilePath : projectBaseRelativeFilePaths) { | ||
try { | ||
var blameHistoryWindow = getBlameHistoryWindow(thresholdDate); | ||
return parseBlameOutput(executeGitCommand(projectBaseDir, | ||
nativeExecutable, "blame", projectBaseDir.resolve(relativeFilePath).toString(), "--line-porcelain", "--encoding=UTF-8"), | ||
nativeExecutable, "blame", blameHistoryWindow, projectBaseDir.resolve(relativeFilePath).toString(), "--line-porcelain", "--encoding=UTF-8"), | ||
projectBaseDir.resolve(relativeFilePath).toString().replace("\\", "/"), projectBaseDir); | ||
} catch (IOException e) { | ||
throw new IllegalStateException("Failed to blame repository files", e); | ||
|
@@ -189,6 +192,11 @@ public static SonarLintBlameResult blameFromNativeCommand(Path projectBaseDir, S | |
throw new IllegalStateException("There is no native Git available"); | ||
} | ||
|
||
private static String getBlameHistoryWindow(long thresholdDate) { | ||
var blameLimit = Instant.ofEpochMilli(thresholdDate); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to what I said earlier, we create Instants that we convert to a timestamp, then back to an Instant |
||
return "--since='" + blameLimit + "'"; | ||
} | ||
|
||
public static boolean checkIfEnabled(Path projectBaseDir) { | ||
var nativeExecutable = getNativeGitExecutable(); | ||
if (nativeExecutable == null) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not returning an Instant from here? You can make the conversion later when you use it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think threshold date is maybe not precise enough. I am bad at naming, but what about something like "period start date"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: I would move the method somewhere else, to not be in the middle of
with*
methods.