mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
GitLogParser refactoring & optimization
1. GitLogParser.parseOneRecord: reimplemented via regexp; throw a RuntimeException if format doesn't match. 2. Use GitLogStatusInfo instead of List<List<String>> to save information about a single status line for the further parsing in GitLogRecord.parseChanges().
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.history;
|
||||
|
||||
import git4idea.GitFormatException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
enum GitChangeType {
|
||||
MODIFIED('M'),
|
||||
ADDED('A'),
|
||||
COPIED('C'),
|
||||
DELETED('D'),
|
||||
RENAMED('R'),
|
||||
UNRESOLVED('U'),
|
||||
TYPE_CHANGED('T')
|
||||
;
|
||||
|
||||
private char myChar;
|
||||
|
||||
GitChangeType(char c) {
|
||||
myChar = c;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static GitChangeType fromString(@NotNull String statusString) {
|
||||
assert statusString.length() > 0;
|
||||
char c = statusString.charAt(0);
|
||||
for (GitChangeType changeType : values()) {
|
||||
if (changeType.myChar == c) {
|
||||
return changeType;
|
||||
}
|
||||
}
|
||||
throw new GitFormatException("Unexpected status [" + statusString + "]");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class GitHistoryUtils {
|
||||
return null;
|
||||
}
|
||||
GitLogRecord record = parser.parseOneRecord(result);
|
||||
final List<Change> changes = record.coolChangesParser(project, root);
|
||||
final List<Change> changes = record.parseChanges(project, root);
|
||||
boolean exists = ! FileStatus.DELETED.equals(changes.get(0).getFileStatus());
|
||||
record.setUsedHandler(h);
|
||||
return new ItemLatestState(new GitRevisionNumber(record.getHash(), record.getDate()), exists, false);
|
||||
@@ -402,7 +402,7 @@ public class GitHistoryUtils {
|
||||
|
||||
if (records.isEmpty()) return null;
|
||||
// we have information about all changed files of the commit. Extracting information about the file we need.
|
||||
final List<Change> changes = records.get(0).coolChangesParser(project, root);
|
||||
final List<Change> changes = records.get(0).parseChanges(project, root);
|
||||
for (Change change : changes) {
|
||||
if ((change.isMoved() || change.isRenamed()) && filePath.equals(change.getAfterRevision().getFile())) {
|
||||
return change.getBeforeRevision().getFile();
|
||||
@@ -646,7 +646,7 @@ public class GitHistoryUtils {
|
||||
new HashSet<String>(Arrays.asList(record.getParentsShortHashes())), record.getFilePaths(root),
|
||||
record.getAuthorEmail(),
|
||||
record.getCommitterEmail(), tags, locals, remotes,
|
||||
record.coolChangesParser(project, root), record.getAuthorTimeStamp() * 1000
|
||||
record.parseChanges(project, root), record.getAuthorTimeStamp() * 1000
|
||||
);
|
||||
gitCommit.setCurrentBranch(s);
|
||||
/*final String current = refs.getCurrent().getName();
|
||||
|
||||
@@ -18,12 +18,17 @@ package git4idea.history;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import git4idea.GitFormatException;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.config.GitVersionSpecialty;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p>Parses the 'git log' output basing on the given number of options.
|
||||
@@ -53,12 +58,11 @@ import java.util.*;
|
||||
class GitLogParser {
|
||||
// Single records begin with %x01, end with %03. Items of commit information (hash, committer, subject, etc.) are separated by %x02.
|
||||
// each character is declared twice - for Git pattern format and for actual character in the output.
|
||||
// separators are declared as String instead of char, because String#split() is heavily used in parsing.
|
||||
public static final String RECORD_START = "\u0001";
|
||||
public static final String RECORD_START_GIT = "%x01";
|
||||
public static final String ITEMS_SEPARATOR = "\u0002";
|
||||
private static final String ITEMS_SEPARATOR_GIT = "%x02";
|
||||
public static final String RECORD_END = "\u0003";
|
||||
private static final String RECORD_START_GIT = "%x01";
|
||||
private static final String ITEMS_SEPARATOR_GIT = "%x02";
|
||||
private static final String RECORD_END_GIT = "%x03";
|
||||
|
||||
private final String myFormat; // pretty custom format generated in the constructor
|
||||
@@ -66,6 +70,30 @@ class GitLogParser {
|
||||
private final boolean mySupportsRawBody;
|
||||
private final NameStatus myNameStatusOption;
|
||||
|
||||
/**
|
||||
* Record format:
|
||||
*
|
||||
* One git log record.
|
||||
* RECORD_START - optional: it is split out when calling parse() but it is not when calling parseOneRecord() directly.
|
||||
* commit information separated by ITEMS_SEPARATOR.
|
||||
* RECORD_END
|
||||
* Optionally: changed paths or paths with statuses (if --name-only or --name-status options are given).
|
||||
*
|
||||
* Example:
|
||||
* 2c815939f45fbcfda9583f84b14fe9d393ada790<ITEM_SEPARATOR>sample commit<RECORD_END>
|
||||
* D a.txt
|
||||
*/
|
||||
private static final Pattern ONE_RECORD = Pattern.compile(RECORD_START + "?(.*)" + RECORD_END + "\n*(.*)", Pattern.DOTALL);
|
||||
private static final String SINGLE_PATH = "([^\t\r\n]+)"; // something not empty, not a tab or newline.
|
||||
private static final String EOL = "\\s*(?:\r|\n|\r\n)";
|
||||
private static final String PATHS =
|
||||
SINGLE_PATH + // First path - required.
|
||||
"(?:\t" + SINGLE_PATH + ")?" + // Second path - optional. Paths are separated by tab.
|
||||
EOL; // Path(s) information ends with a line terminator.
|
||||
|
||||
private static Pattern NAME_ONLY = Pattern.compile(PATHS);
|
||||
private static Pattern NAME_STATUS = Pattern.compile("([\\S]+)\t" + PATHS);
|
||||
|
||||
// --name-only, --name-status or no flag
|
||||
enum NameStatus {
|
||||
/** No flag. */
|
||||
@@ -151,72 +179,67 @@ class GitLogParser {
|
||||
* flags --name-only or name-status were provided).
|
||||
* @param line record to be parsed.
|
||||
* @return GitLogRecord with information about the revision or {@code null} if the given line is empty.
|
||||
* @throws GitFormatException if the line is given in unexpected format.
|
||||
*/
|
||||
@Nullable
|
||||
@NotNull
|
||||
GitLogRecord parseOneRecord(@NotNull String line) {
|
||||
// record format:
|
||||
//
|
||||
// <record start> - this may be splitted out in parse(). But if one calls this method directly, the char will be in place.
|
||||
// <commit info, possibly multilined - if body is multilined>
|
||||
// <record end mark>
|
||||
// <blank line (optional)>
|
||||
// <name status (optional)>\t<path (optional)>\t<second path (optional)> - status is output in the case of NameStatus.STATUS,
|
||||
// paths are output if NameStatus.NAME or NameStatus.STATUS. Two paths is the rename case.
|
||||
//
|
||||
// Blank line before name-status usually appears, but it also can absent (e.g. in --pretty=oneline format), so we shouldn't rely on this.
|
||||
// Example:
|
||||
// 2c815939f45fbcfda9583f84b14fe9d393ada790<ITEM_SEPARATOR>sample commit<RECORD_END>
|
||||
//
|
||||
// D a.txt
|
||||
|
||||
if (line.isEmpty()) { return null; }
|
||||
line = removeRecordStartIndicator(line);
|
||||
|
||||
Matcher matcher = ONE_RECORD.matcher(line);
|
||||
if (!matcher.matches()) {
|
||||
throwGFE("ONE_RECORD didn't match", line);
|
||||
}
|
||||
String commitInfo = matcher.group(1);
|
||||
if (commitInfo == null) {
|
||||
throwGFE("No match for group#1 in", line);
|
||||
}
|
||||
|
||||
final Map<GitLogOption, String> res = parseCommitInfo(commitInfo);
|
||||
|
||||
// parsing status and path (if given)
|
||||
final List<String> paths = new ArrayList<String>(1);
|
||||
final boolean includeStatus = myNameStatusOption == NameStatus.STATUS;
|
||||
final List<List<String>> parts = includeStatus ? new ArrayList<List<String>>() : null;
|
||||
|
||||
final List<GitLogStatusInfo> statuses = new ArrayList<GitLogStatusInfo>();
|
||||
|
||||
if (myNameStatusOption != NameStatus.NONE) {
|
||||
final String[] infoAndPath = line.split(RECORD_END);
|
||||
line = infoAndPath[0];
|
||||
if (infoAndPath.length > 1) {
|
||||
// separator is \n for paths, space for paths and status
|
||||
final List<String> nameAndPathSplit = new ArrayList<String>(Arrays.asList(infoAndPath[infoAndPath.length - 1].split("\n")));
|
||||
for (Iterator<String> it = nameAndPathSplit.iterator(); it.hasNext();) {
|
||||
if (it.next().trim().isEmpty()) {
|
||||
it.remove();
|
||||
String pathsAndStatuses = matcher.group(2);
|
||||
if (pathsAndStatuses == null) {
|
||||
throwGFE("No match for group#2 in", line);
|
||||
}
|
||||
|
||||
if (myNameStatusOption == NameStatus.NAME) {
|
||||
Matcher pathsMatcher = NAME_ONLY.matcher(pathsAndStatuses);
|
||||
while (pathsMatcher.find()) {
|
||||
String path1 = pathsMatcher.group(1);
|
||||
String path2 = pathsMatcher.group(2);
|
||||
assertNotNull(path1, "path", pathsAndStatuses);
|
||||
paths.add(path1);
|
||||
if (path2 != null) { // null is perfectly legal here: second path is given only in case of rename
|
||||
paths.add(path2);
|
||||
}
|
||||
}
|
||||
|
||||
for (String pathLine : nameAndPathSplit) {
|
||||
String[] partsArr;
|
||||
if (includeStatus) {
|
||||
final int idx = pathLine.indexOf("\t");
|
||||
if (idx != -1) {
|
||||
final String whatLeft = pathLine.substring(idx).trim();
|
||||
partsArr = whatLeft.split("\\t");
|
||||
final List<String> strings = new ArrayList<String>(partsArr.length + 1);
|
||||
strings.add(pathLine.substring(0, 1));
|
||||
strings.addAll(Arrays.asList(partsArr));
|
||||
parts.add(strings);
|
||||
} else {
|
||||
partsArr = pathLine.split("\\t"); // should not
|
||||
}
|
||||
} else {
|
||||
partsArr = pathLine.split("\\t");
|
||||
} else {
|
||||
Matcher nameStatusMatcher = NAME_STATUS.matcher(pathsAndStatuses);
|
||||
while (nameStatusMatcher.find()) {
|
||||
String status = nameStatusMatcher.group(1);
|
||||
String path1 = nameStatusMatcher.group(2);
|
||||
String path2 = nameStatusMatcher.group(3);
|
||||
assertNotNull(status, "status", pathsAndStatuses);
|
||||
assertNotNull(path1, "path1", pathsAndStatuses);
|
||||
paths.add(path1);
|
||||
if (path2 != null) {
|
||||
paths.add(path2);
|
||||
}
|
||||
paths.addAll(Arrays.asList(partsArr));
|
||||
statuses.add(new GitLogStatusInfo(GitChangeType.fromString(status), path1, path2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
line = line.substring(0, line.length()-1); // removing the last character which is RECORD_END
|
||||
}
|
||||
return new GitLogRecord(res, paths, statuses, mySupportsRawBody);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private Map<GitLogOption, String> parseCommitInfo(@NotNull String commitInfo) {
|
||||
// parsing revision information
|
||||
// we rely on the order of options
|
||||
final String[] values = line.split(ITEMS_SEPARATOR);
|
||||
final String[] values = commitInfo.split(ITEMS_SEPARATOR);
|
||||
final Map<GitLogOption, String> res = new HashMap<GitLogOption, String>(values.length);
|
||||
int i = 0;
|
||||
for (; i < values.length && i < myOptions.length; i++) { // fill valid values
|
||||
@@ -225,16 +248,17 @@ class GitLogParser {
|
||||
for (; i < myOptions.length; i++) { // options which were not returned are set to blank string, extra options are ignored.
|
||||
res.put(myOptions[i], "");
|
||||
}
|
||||
return new GitLogRecord(res, paths, parts, mySupportsRawBody);
|
||||
return res;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String removeRecordStartIndicator(@NotNull String line) {
|
||||
// We may have <RECORD_START> indicator at the beginning of the line (if we called parseOneLine directly), may not (if we called parse()).
|
||||
// If we have, get rid of it.
|
||||
if (line.charAt(0) == RECORD_START.charAt(0)) {
|
||||
line = line.substring(RECORD_START.length());
|
||||
private static void assertNotNull(String value, String valueName, String line) {
|
||||
if (value == null) {
|
||||
throwGFE("Unexpectedly null " + valueName + " in ", line);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private static void throwGFE(String message, String line) {
|
||||
throw new GitFormatException(message + " [" + StringUtil.escapeStringCharacters(line) + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,16 +43,18 @@ import static git4idea.history.GitLogParser.GitLogOption.*;
|
||||
* @see git4idea.history.GitLogParser
|
||||
*/
|
||||
class GitLogRecord {
|
||||
|
||||
private final Map<GitLogParser.GitLogOption, String> myOptions;
|
||||
private final List<String> myPaths;
|
||||
private final List<List<String>> myParts;
|
||||
private final List<GitLogStatusInfo> myStatusInfo;
|
||||
private final boolean mySupportsRawBody;
|
||||
|
||||
private GitHandler myHandler;
|
||||
|
||||
GitLogRecord(Map<GitLogParser.GitLogOption, String> options, List<String> paths, List<List<String>> parts, boolean supportsRawBody) {
|
||||
GitLogRecord(@NotNull Map<GitLogParser.GitLogOption, String> options, @NotNull List<String> paths, @NotNull List<GitLogStatusInfo> statusInfo, boolean supportsRawBody) {
|
||||
myOptions = options;
|
||||
myPaths = paths;
|
||||
myParts = parts;
|
||||
myStatusInfo = statusInfo;
|
||||
mySupportsRawBody = supportsRawBody;
|
||||
}
|
||||
|
||||
@@ -60,10 +62,6 @@ class GitLogRecord {
|
||||
return myPaths;
|
||||
}
|
||||
|
||||
private List<List<String>> getParts() {
|
||||
return myParts;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<FilePath> getFilePaths(VirtualFile root) throws VcsException {
|
||||
List<FilePath> res = new ArrayList<FilePath>();
|
||||
@@ -175,44 +173,48 @@ class GitLogRecord {
|
||||
return new String(raw);
|
||||
}
|
||||
|
||||
public List<Change> coolChangesParser(Project project, VirtualFile vcsRoot) throws VcsException {
|
||||
final List<Change> result = new ArrayList<Change>();
|
||||
final GitRevisionNumber thisRevision = new GitRevisionNumber(getHash(), getDate());
|
||||
public List<Change> parseChanges(Project project, VirtualFile vcsRoot) throws VcsException {
|
||||
GitRevisionNumber thisRevision = new GitRevisionNumber(getHash(), getDate());
|
||||
List<GitRevisionNumber> parentRevisions = prepareParentRevisions();
|
||||
|
||||
List<Change> result = new ArrayList<Change>();
|
||||
for (GitLogStatusInfo statusInfo: myStatusInfo) {
|
||||
result.add(parseChange(project, vcsRoot, parentRevisions, statusInfo, thisRevision));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<GitRevisionNumber> prepareParentRevisions() {
|
||||
final String[] parentsShortHashes = getParentsShortHashes();
|
||||
final List<AbstractHash> parents = new ArrayList<AbstractHash>(parentsShortHashes.length);
|
||||
for (String parentsShortHash : parentsShortHashes) {
|
||||
parents.add(AbstractHash.create(parentsShortHash));
|
||||
}
|
||||
final List<List<String>> parts = getParts();
|
||||
if (parts != null) {
|
||||
for (List<String> partsPart: parts) {
|
||||
result.add(parseChange(project, vcsRoot, parents, partsPart, thisRevision));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Change parseChange(final Project project, final VirtualFile vcsRoot, final List<AbstractHash> parents,
|
||||
final List<String> parts, final VcsRevisionNumber thisRevision) throws VcsException {
|
||||
final ContentRevision before;
|
||||
final ContentRevision after;
|
||||
FileStatus status = null;
|
||||
final String path = parts.get(1);
|
||||
final List<GitRevisionNumber> parentRevisions = new ArrayList<GitRevisionNumber>(parents.size());
|
||||
for (AbstractHash parent : parents) {
|
||||
parentRevisions.add(new GitRevisionNumber(parent.getString()));
|
||||
}
|
||||
return parentRevisions;
|
||||
}
|
||||
|
||||
switch (parts.get(0).charAt(0)) {
|
||||
case 'C':
|
||||
case 'A':
|
||||
private static Change parseChange(final Project project, final VirtualFile vcsRoot, final List<GitRevisionNumber> parentRevisions,
|
||||
final GitLogStatusInfo statusInfo, final VcsRevisionNumber thisRevision) throws VcsException {
|
||||
final ContentRevision before;
|
||||
final ContentRevision after;
|
||||
FileStatus status = null;
|
||||
final String path = statusInfo.getFirstPath();
|
||||
|
||||
switch (statusInfo.getType()) {
|
||||
case ADDED:
|
||||
case COPIED:
|
||||
before = null;
|
||||
status = FileStatus.ADDED;
|
||||
after = GitContentRevision.createRevision(vcsRoot, path, thisRevision, project, false, false, true);
|
||||
break;
|
||||
case 'U':
|
||||
case UNRESOLVED:
|
||||
status = FileStatus.MERGED_WITH_CONFLICTS;
|
||||
case 'M':
|
||||
case MODIFIED:
|
||||
if (status == null) {
|
||||
status = FileStatus.MODIFIED;
|
||||
}
|
||||
@@ -220,26 +222,26 @@ class GitLogRecord {
|
||||
before = GitContentRevision.createMultipleParentsRevision(project, filePath, parentRevisions);
|
||||
after = GitContentRevision.createRevision(vcsRoot, path, thisRevision, project, false, false, true);
|
||||
break;
|
||||
case 'D':
|
||||
case DELETED:
|
||||
status = FileStatus.DELETED;
|
||||
final FilePath filePathDeleted = GitContentRevision.createPath(vcsRoot, path, true, true, true);
|
||||
before = GitContentRevision.createMultipleParentsRevision(project, filePathDeleted, parentRevisions);
|
||||
after = null;
|
||||
break;
|
||||
case 'R':
|
||||
case RENAMED:
|
||||
status = FileStatus.MODIFIED;
|
||||
final FilePath filePathAfterRename = GitContentRevision.createPath(vcsRoot, parts.get(2), false, false, true);
|
||||
final FilePath filePathAfterRename = GitContentRevision.createPath(vcsRoot, statusInfo.getSecondPath(), false, false, true);
|
||||
after = GitContentRevision.createMultipleParentsRevision(project, filePathAfterRename, parentRevisions);
|
||||
before = GitContentRevision.createRevision(vcsRoot, path, thisRevision, project, true, true, true);
|
||||
break;
|
||||
case 'T':
|
||||
case TYPE_CHANGED:
|
||||
status = FileStatus.MODIFIED;
|
||||
final FilePath filePath2 = GitContentRevision.createPath(vcsRoot, path, false, true, true);
|
||||
before = GitContentRevision.createMultipleParentsRevision(project, filePath2, parentRevisions);
|
||||
after = GitContentRevision.createRevision(vcsRoot, path, thisRevision, project, false, false, true);
|
||||
break;
|
||||
default:
|
||||
throw new VcsException("Unknown file status: " + Arrays.asList(parts));
|
||||
throw new AssertionError("Unknown file status: " + statusInfo);
|
||||
}
|
||||
return new Change(before, after, status);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.history;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Information about a single file change as returned by {@code git log status --name-status}.
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitLogStatusInfo {
|
||||
private final GitChangeType myType;
|
||||
private final String myPath;
|
||||
private final String mySecondPath;
|
||||
|
||||
GitLogStatusInfo(@NotNull GitChangeType type, @NotNull String path, @Nullable String secondPath) {
|
||||
verifyParameters(type, path, secondPath);
|
||||
mySecondPath = secondPath;
|
||||
myPath = path;
|
||||
myType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* SecondPath == null iff it the type is rename
|
||||
*/
|
||||
private static void verifyParameters(@NotNull GitChangeType type, @NotNull String path, @Nullable String secondPath) {
|
||||
if (type == GitChangeType.RENAMED) {
|
||||
assert secondPath != null;
|
||||
} else {
|
||||
assert secondPath == null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFirstPath() {
|
||||
return myPath;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GitChangeType getType() {
|
||||
return myType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSecondPath() {
|
||||
return mySecondPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -211,7 +211,7 @@ public class GitLogParserTest extends GitTest {
|
||||
assertPaths(actual.getFilePaths(myRoot), expected.paths());
|
||||
} else if (option == GitTestLogRecord.NameStatusOption.STATUS) {
|
||||
assertPaths(actual.getFilePaths(myRoot), expected.paths());
|
||||
assertChanges(actual.coolChangesParser(myProject, myRoot), expected.changes());
|
||||
assertChanges(actual.parseChanges(myProject, myRoot), expected.changes());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user