From 66399a062071d23e122f2fe826dd2b539828a758 Mon Sep 17 00:00:00 2001 From: FH-30 Date: Thu, 1 Jul 2021 00:42:29 +0800 Subject: [PATCH 1/5] Add flag for catching non-PR commits --- src/main/java/reposense/model/CliArguments.java | 3 +++ .../java/reposense/model/ConfigCliArguments.java | 3 ++- .../java/reposense/model/LocationsCliArguments.java | 3 ++- src/main/java/reposense/parser/ArgsParser.java | 12 ++++++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/reposense/model/CliArguments.java b/src/main/java/reposense/model/CliArguments.java index 0c19aecee2..8188b43683 100644 --- a/src/main/java/reposense/model/CliArguments.java +++ b/src/main/java/reposense/model/CliArguments.java @@ -20,6 +20,7 @@ public abstract class CliArguments { protected boolean isShallowCloningPerformed; protected boolean isAutomaticallyLaunching; protected boolean isStandaloneConfigIgnored; + protected boolean isCatchingNonPrCommitsPerformed; protected int numCloningThreads; protected int numAnalysisThreads; protected ZoneId zoneId; @@ -60,6 +61,8 @@ public boolean isShallowCloningPerformed() { return isShallowCloningPerformed; } + public boolean isCatchingNonPrCommitsPerformed() { return isCatchingNonPrCommitsPerformed; } + public List getFormats() { return formats; } diff --git a/src/main/java/reposense/model/ConfigCliArguments.java b/src/main/java/reposense/model/ConfigCliArguments.java index eec29ef7dd..2421f923a3 100644 --- a/src/main/java/reposense/model/ConfigCliArguments.java +++ b/src/main/java/reposense/model/ConfigCliArguments.java @@ -27,7 +27,7 @@ public class ConfigCliArguments extends CliArguments { public ConfigCliArguments(Path configFolderPath, Path outputFilePath, Path assetsFilePath, Date sinceDate, Date untilDate, boolean isSinceDateProvided, boolean isUntilDateProvided, int numCloningThreads, int numAnalysisThreads, List formats, boolean isLastModifiedDateIncluded, - boolean isShallowCloningPerformed, boolean isAutomaticallyLaunching, + boolean isShallowCloningPerformed, boolean isCatchingNonPrCommitsPerformed, boolean isAutomaticallyLaunching, boolean isStandaloneConfigIgnored, ZoneId zoneId, ReportConfiguration reportConfiguration) { this.configFolderPath = configFolderPath.equals(EMPTY_PATH) ? configFolderPath.toAbsolutePath() @@ -45,6 +45,7 @@ public ConfigCliArguments(Path configFolderPath, Path outputFilePath, Path asset this.formats = formats; this.isLastModifiedDateIncluded = isLastModifiedDateIncluded; this.isShallowCloningPerformed = isShallowCloningPerformed; + this.isCatchingNonPrCommitsPerformed = isCatchingNonPrCommitsPerformed; this.isAutomaticallyLaunching = isAutomaticallyLaunching; this.isStandaloneConfigIgnored = isStandaloneConfigIgnored; this.numCloningThreads = numCloningThreads; diff --git a/src/main/java/reposense/model/LocationsCliArguments.java b/src/main/java/reposense/model/LocationsCliArguments.java index d984437182..621542efe7 100644 --- a/src/main/java/reposense/model/LocationsCliArguments.java +++ b/src/main/java/reposense/model/LocationsCliArguments.java @@ -14,7 +14,7 @@ public class LocationsCliArguments extends CliArguments { public LocationsCliArguments(List locations, Path outputFilePath, Path assetsFilePath, Date sinceDate, Date untilDate, boolean isSinceDateProvided, boolean isUntilDateProvided, int numCloningThreads, int numAnalysisThreads, List formats, boolean isLastModifiedDateIncluded, - boolean isShallowCloningPerformed, boolean isAutomaticallyLaunching, + boolean isShallowCloningPerformed, boolean isCatchingNonPrCommitsPerformed, boolean isAutomaticallyLaunching, boolean isStandaloneConfigIgnored, ZoneId zoneId) { this.locations = locations; this.outputFilePath = outputFilePath; @@ -25,6 +25,7 @@ public LocationsCliArguments(List locations, Path outputFilePath, Path a this.isUntilDateProvided = isUntilDateProvided; this.isLastModifiedDateIncluded = isLastModifiedDateIncluded; this.isShallowCloningPerformed = isShallowCloningPerformed; + this.isCatchingNonPrCommitsPerformed = isCatchingNonPrCommitsPerformed; this.formats = formats; this.isAutomaticallyLaunching = isAutomaticallyLaunching; this.isStandaloneConfigIgnored = isStandaloneConfigIgnored; diff --git a/src/main/java/reposense/parser/ArgsParser.java b/src/main/java/reposense/parser/ArgsParser.java index db6f97c12d..03b95d2828 100644 --- a/src/main/java/reposense/parser/ArgsParser.java +++ b/src/main/java/reposense/parser/ArgsParser.java @@ -56,6 +56,7 @@ public class ArgsParser { public static final String[] TIMEZONE_FLAGS = new String[]{"--timezone", "-t"}; public static final String[] VERSION_FLAGS = new String[]{"--version", "-V"}; public static final String[] LAST_MODIFIED_DATE_FLAGS = new String[]{"--last-modified-date", "-l"}; + public static final String[] CATCH_NON_PR_COMMITS_FLAGS = new String[]{"--catch-non-pr-commits", "-C"}; public static final String[] CLONING_THREADS_FLAG = new String[]{"--cloning-threads"}; public static final String[] ANALYSIS_THREADS_FLAG = new String[]{"--analysis-threads"}; @@ -116,6 +117,12 @@ private static ArgumentParser getArgumentParser() { .help("Show the version of RepoSense.") .action(new VersionArgumentAction()); + parser.addArgument(CATCH_NON_PR_COMMITS_FLAGS) + .dest(CATCH_NON_PR_COMMITS_FLAGS[0]) + .action(Arguments.storeTrue()) + .help("A flag to record the number of commits in the repository not merged from pull requests. " + + "A breakdown will be provided for each author that contributed to the repository"); + parser.addArgument(IGNORE_FLAGS) .dest(IGNORE_FLAGS[0]) .action(Arguments.storeTrue()) @@ -257,6 +264,7 @@ public static CliArguments parse(String[] args) throws HelpScreenException, Pars boolean isStandaloneConfigIgnored = results.get(IGNORE_FLAGS[0]); boolean shouldIncludeLastModifiedDate = results.get(LAST_MODIFIED_DATE_FLAGS[0]); boolean shouldPerformShallowCloning = results.get(SHALLOW_CLONING_FLAGS[0]); + boolean shouldCatchNonPrCommits = results.get(CATCH_NON_PR_COMMITS_FLAGS[0]); // Report config is ignored if --repos is provided if (locations == null) { @@ -324,7 +332,7 @@ public static CliArguments parse(String[] args) throws HelpScreenException, Pars if (locations != null) { return new LocationsCliArguments(locations, outputFolderPath, assetsFolderPath, sinceDate, untilDate, isSinceDateProvided, isUntilDateProvided, numCloningThreads, numAnalysisThreads, formats, - shouldIncludeLastModifiedDate, shouldPerformShallowCloning, isAutomaticallyLaunching, + shouldIncludeLastModifiedDate, shouldPerformShallowCloning, shouldCatchNonPrCommits, isAutomaticallyLaunching, isStandaloneConfigIgnored, zoneId); } @@ -333,7 +341,7 @@ public static CliArguments parse(String[] args) throws HelpScreenException, Pars } return new ConfigCliArguments(configFolderPath, outputFolderPath, assetsFolderPath, sinceDate, untilDate, isSinceDateProvided, isUntilDateProvided, numCloningThreads, numAnalysisThreads, formats, - shouldIncludeLastModifiedDate, shouldPerformShallowCloning, isAutomaticallyLaunching, + shouldIncludeLastModifiedDate, shouldPerformShallowCloning, shouldCatchNonPrCommits, isAutomaticallyLaunching, isStandaloneConfigIgnored, zoneId, reportConfig); } catch (HelpScreenException hse) { throw hse; From a4f2a1501c192127e899ab2e1f5c616197e4f2c9 Mon Sep 17 00:00:00 2001 From: FH-30 Date: Thu, 1 Jul 2021 01:02:05 +0800 Subject: [PATCH 2/5] Update each repo configuration with catching non pr commit decision --- src/main/java/reposense/RepoSense.java | 3 +++ .../java/reposense/model/RepoConfiguration.java | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/reposense/RepoSense.java b/src/main/java/reposense/RepoSense.java index 7ab49096cd..b5b65ee450 100644 --- a/src/main/java/reposense/RepoSense.java +++ b/src/main/java/reposense/RepoSense.java @@ -74,6 +74,9 @@ public static void main(String[] args) { cliArguments.isLastModifiedDateIncluded()); RepoConfiguration.setIsShallowCloningPerformedToRepoConfigs(configs, cliArguments.isShallowCloningPerformed()); + RepoConfiguration.setIsCatchingNonPrCommitsPerformedToRepoConfigs(configs, + cliArguments.isCatchingNonPrCommitsPerformed()); + List reportFoldersAndFiles = ReportGenerator.generateReposReport(configs, cliArguments.getOutputFilePath().toAbsolutePath().toString(), cliArguments.getAssetsFilePath().toAbsolutePath().toString(), reportConfig, diff --git a/src/main/java/reposense/model/RepoConfiguration.java b/src/main/java/reposense/model/RepoConfiguration.java index 5de6761e5b..3d37a2725b 100644 --- a/src/main/java/reposense/model/RepoConfiguration.java +++ b/src/main/java/reposense/model/RepoConfiguration.java @@ -38,6 +38,7 @@ public class RepoConfiguration { private transient List ignoreCommitList; private transient boolean isLastModifiedDateIncluded; private transient boolean isShallowCloningPerformed; + private transient boolean isCatchingNonPrCommitsPerformed; private transient boolean isFormatsOverriding; private transient boolean isIgnoreGlobListOverriding; private transient boolean isIgnoreCommitListOverriding; @@ -49,13 +50,13 @@ public RepoConfiguration(RepoLocation location) { public RepoConfiguration(RepoLocation location, String branch) { this(location, branch, Collections.emptyList(), Collections.emptyList(), false, Collections.emptyList(), - false, false, false, false); + false, false, false, false, false); } public RepoConfiguration(RepoLocation location, String branch, List formats, List ignoreGlobList, boolean isStandaloneConfigIgnored, List ignoreCommitList, boolean isFormatsOverriding, boolean isIgnoreGlobListOverriding, boolean isIgnoreCommitListOverriding, - boolean isShallowCloningPerformed) { + boolean isShallowCloningPerformed, boolean isCatchingNonPrCommitsPerformed) { this.authorConfig = new AuthorConfiguration(location, branch); this.location = location; this.branch = location.isEmpty() ? DEFAULT_BRANCH : branch; @@ -67,6 +68,7 @@ public RepoConfiguration(RepoLocation location, String branch, List fo this.isIgnoreGlobListOverriding = isIgnoreGlobListOverriding; this.isIgnoreCommitListOverriding = isIgnoreCommitListOverriding; this.isShallowCloningPerformed = isShallowCloningPerformed; + this.isCatchingNonPrCommitsPerformed = isCatchingNonPrCommitsPerformed; String organization = location.getOrganization(); String repoName = location.getRepoName(); @@ -108,6 +110,13 @@ public static void setIsShallowCloningPerformedToRepoConfigs(List configs, + boolean isCatchingNonPrCommitsPerformed) { + if (isCatchingNonPrCommitsPerformed) { + configs.stream().forEach(config -> config.setIsCatchingNonPrCommitsPerformed(true)); + } + } + /** * Merges a {@code RepoConfiguration} from {@code repoConfigs} with an {@code AuthorConfiguration} from * {@code authorConfigs} if their {@code RepoLocation} and branch matches @@ -395,6 +404,10 @@ public void setIsShallowCloningPerformed(boolean isShallowCloningPerformed) { this.isShallowCloningPerformed = isShallowCloningPerformed; } + public void setIsCatchingNonPrCommitsPerformed(boolean isCatchingNonPrCommitsPerformed) { + this.isCatchingNonPrCommitsPerformed = isCatchingNonPrCommitsPerformed; + } + public boolean isLastModifiedDateIncluded() { return this.isLastModifiedDateIncluded; } From d1785a2766087379984c1d31b6c0ddfd4b413253 Mon Sep 17 00:00:00 2001 From: FH-30 Date: Thu, 1 Jul 2021 02:18:47 +0800 Subject: [PATCH 3/5] Allow csv parsing of catching non pr commit config --- config/repo-config.csv | 20 +++++++++---------- .../reposense/parser/RepoConfigCsvParser.java | 14 ++++++++++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/config/repo-config.csv b/config/repo-config.csv index 1acbac36a8..445531afa2 100644 --- a/config/repo-config.csv +++ b/config/repo-config.csv @@ -1,10 +1,10 @@ -Repository's Location,Branch,File formats,Ignore Glob List,Ignore standalone config,Ignore Commits List,Ignore Authors List,Shallow Cloning -https://github.com/reposense/testrepo-Alpha.git,master,,,,2fb6b9b2dd9fa40bf0f9815da2cb0ae8731436c7;c5a6dc774e22099cd9ddeb0faff1e75f9cf4f151;cd7f610e0becbdf331d5231887d8010a689f87c7;768015345e70f06add2a8b7d1f901dc07bf70582,, -https://github.com/reposense/testrepo-Beta.git,master,fxml,docs**,yes,,, -https://github.com/reposense/testrepo-Beta.git,add-config-json,fxml,docs**,yes,,, -https://github.com/reposense/testrepo-Delta.git,master,override:java;md,,,,, -https://github.com/reposense/testrepo-Delta.git,nonExistentBranch,,,,,, -https://github.com/reposense/testrepo-Delta.git,add-binary-file,,,,,, -https://github.com/reposense/RepoSense.git,master,,,,,, -https://github.com/reposense/testrepo-Empty.git,master,,,,,, -ftp://github.com/reposense/RepoSense.git,master,,,,,, +Repository's Location,Branch,File formats,Ignore Glob List,Ignore standalone config,Ignore Commits List,Ignore Authors List,Shallow Cloning,Catch Non PR Commits +https://github.com/reposense/testrepo-Alpha.git,master,,,,2fb6b9b2dd9fa40bf0f9815da2cb0ae8731436c7;c5a6dc774e22099cd9ddeb0faff1e75f9cf4f151;cd7f610e0becbdf331d5231887d8010a689f87c7;768015345e70f06add2a8b7d1f901dc07bf70582,,, +https://github.com/reposense/testrepo-Beta.git,master,fxml,docs**,yes,,,, +https://github.com/reposense/testrepo-Beta.git,add-config-json,fxml,docs**,yes,,,, +https://github.com/reposense/testrepo-Delta.git,master,override:java;md,,,,,, +https://github.com/reposense/testrepo-Delta.git,nonExistentBranch,,,,,,, +https://github.com/reposense/testrepo-Delta.git,add-binary-file,,,,,,, +https://github.com/reposense/RepoSense.git,master,,,,,,,yes +https://github.com/reposense/testrepo-Empty.git,master,,,,,,, +ftp://github.com/reposense/RepoSense.git,master,,,,,,,yes \ No newline at end of file diff --git a/src/main/java/reposense/parser/RepoConfigCsvParser.java b/src/main/java/reposense/parser/RepoConfigCsvParser.java index 11ee5ef767..60f7efb354 100644 --- a/src/main/java/reposense/parser/RepoConfigCsvParser.java +++ b/src/main/java/reposense/parser/RepoConfigCsvParser.java @@ -18,6 +18,7 @@ public class RepoConfigCsvParser extends CsvParser { public static final String REPO_CONFIG_FILENAME = "repo-config.csv"; private static final String IGNORE_STANDALONE_CONFIG_KEYWORD = "yes"; private static final String SHALLOW_CLONING_CONFIG_KEYWORD = "yes"; + private static final String CATCH_NON_PR_COMMITS_CONFIG_KEYWORD = "yes"; /** * Positions of the elements of a line in repo-config.csv config file @@ -30,6 +31,7 @@ public class RepoConfigCsvParser extends CsvParser { private static final String IGNORE_COMMIT_LIST_CONFIG_HEADER = "Ignore Commit List"; private static final String IGNORE_AUTHOR_LIST_CONFIG_HEADER = "Ignore Authors List"; private static final String SHALLOW_CLONING_CONFIG_HEADER = "Shallow Cloning"; + private static final String CATCH_NON_PR_COMMITS_CONFIG_HEADER = "Catch Non PR Commits"; public RepoConfigCsvParser(Path csvFilePath) throws IOException { super(csvFilePath); @@ -53,6 +55,7 @@ protected String[] optionalHeaders() { return new String[] { BRANCH_HEADER, FILE_FORMATS_HEADER, IGNORE_GLOB_LIST_HEADER, IGNORE_STANDALONE_CONFIG_HEADER, IGNORE_COMMIT_LIST_CONFIG_HEADER, IGNORE_AUTHOR_LIST_CONFIG_HEADER, SHALLOW_CLONING_CONFIG_HEADER, + CATCH_NON_PR_COMMITS_CONFIG_HEADER, }; } @@ -98,10 +101,19 @@ protected void processLine(List results, CSVRecord record) th "Ignoring unknown value " + shallowCloningConfig + " in shallow cloning column."); } + String catchingNonPrCommitsConfig = get(record, CATCH_NON_PR_COMMITS_CONFIG_HEADER); + boolean isCatchingNonPrCommitsPerformed = + catchingNonPrCommitsConfig.equalsIgnoreCase(CATCH_NON_PR_COMMITS_CONFIG_KEYWORD); + + if (!isCatchingNonPrCommitsPerformed && !catchingNonPrCommitsConfig.isEmpty()) { + logger.warning( + "Ignoring unknown value " + catchingNonPrCommitsConfig + " in catch non pr commits column."); + } + RepoConfiguration config = new RepoConfiguration( location, branch, formats, ignoreGlobList, isStandaloneConfigIgnored, ignoreCommitList, isFormatsOverriding, isIgnoreGlobListOverriding, isIgnoreCommitListOverriding, - isShallowCloningPerformed); + isShallowCloningPerformed, isCatchingNonPrCommitsPerformed); config.setIgnoredAuthorsList(ignoredAuthorsList); config.setIsIgnoredAuthorsListOverriding(isIgnoredAuthorsListOverriding); From 86b91fb7b451ca4f7463ea7f38e790846705443b Mon Sep 17 00:00:00 2001 From: FH-30 Date: Thu, 1 Jul 2021 18:42:09 +0800 Subject: [PATCH 4/5] Implement backend logic to catch non pr commits --- build.gradle | 4 +- config/repo-config.csv | 10 +--- .../reposense/commits/CommitInfoAnalyzer.java | 55 ++++++++++++++++--- .../commits/CommitResultAggregator.java | 26 ++++++++- .../model/CommitContributionSummary.java | 7 ++- .../reposense/commits/model/CommitResult.java | 12 +++- .../reposense/report/CommitReportJson.java | 5 ++ .../commits/CommitInfoAnalyzerTest.java | 26 +++++---- 8 files changed, 109 insertions(+), 36 deletions(-) diff --git a/build.gradle b/build.gradle index f1e44a6cb2..76a19d33c0 100644 --- a/build.gradle +++ b/build.gradle @@ -14,8 +14,8 @@ mainClassName = 'reposense.RepoSense' node.nodeVersion = '10.16.0' -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 +sourceCompatibility = JavaVersion.VERSION_11 +targetCompatibility = JavaVersion.VERSION_11 repositories { mavenCentral() diff --git a/config/repo-config.csv b/config/repo-config.csv index 445531afa2..c2ef6247b5 100644 --- a/config/repo-config.csv +++ b/config/repo-config.csv @@ -1,10 +1,2 @@ Repository's Location,Branch,File formats,Ignore Glob List,Ignore standalone config,Ignore Commits List,Ignore Authors List,Shallow Cloning,Catch Non PR Commits -https://github.com/reposense/testrepo-Alpha.git,master,,,,2fb6b9b2dd9fa40bf0f9815da2cb0ae8731436c7;c5a6dc774e22099cd9ddeb0faff1e75f9cf4f151;cd7f610e0becbdf331d5231887d8010a689f87c7;768015345e70f06add2a8b7d1f901dc07bf70582,,, -https://github.com/reposense/testrepo-Beta.git,master,fxml,docs**,yes,,,, -https://github.com/reposense/testrepo-Beta.git,add-config-json,fxml,docs**,yes,,,, -https://github.com/reposense/testrepo-Delta.git,master,override:java;md,,,,,, -https://github.com/reposense/testrepo-Delta.git,nonExistentBranch,,,,,,, -https://github.com/reposense/testrepo-Delta.git,add-binary-file,,,,,,, -https://github.com/reposense/RepoSense.git,master,,,,,,,yes -https://github.com/reposense/testrepo-Empty.git,master,,,,,,, -ftp://github.com/reposense/RepoSense.git,master,,,,,,,yes \ No newline at end of file +https://github.com/FH-30/Test-Repo.git,master,,,,,,,yes \ No newline at end of file diff --git a/src/main/java/reposense/commits/CommitInfoAnalyzer.java b/src/main/java/reposense/commits/CommitInfoAnalyzer.java index efb457401c..3eae8f3ee4 100644 --- a/src/main/java/reposense/commits/CommitInfoAnalyzer.java +++ b/src/main/java/reposense/commits/CommitInfoAnalyzer.java @@ -2,15 +2,12 @@ import static reposense.util.StringsUtil.removeQuote; +import java.net.URL; +import java.net.URLConnection; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -76,6 +73,41 @@ public static List analyzeCommits(List commitInfos, Re .collect(Collectors.toList()); } + /** + * Get HTML from a website. + * Source: https://stackoverflow.com/questions/31462/how-to-fetch-html-in-java. + * @param site Site to query html from. + * @return the HTML from the given website. + */ + public static String getHtml(String site) { + String content = null; + URLConnection connection = null; + try { + connection = new URL(site).openConnection(); + Scanner scanner = new Scanner(connection.getInputStream()); + scanner.useDelimiter("\\Z"); + content = scanner.next(); + scanner.close(); + }catch ( Exception ex ) { + ex.printStackTrace(); + } + + return content; + } + + /** + * Get the URL which returns the pull request url that a commit hash belongs to (if any). + * @param config Config of the repository that the commit belongs to. + * @param hash Hash of the relevant commit. + * @return URL which returns HTML containing pull request url of given commit hash. + */ + private static String getGithubQueryUrl(RepoConfiguration config, String hash) { + String githubCloneUrl = config.getLocation().toString(); + String githubRepoUrl = githubCloneUrl.substring(0, githubCloneUrl.length() - 4); + String commitHashUrl = "/branch_commits/" + hash; + return githubRepoUrl + commitHashUrl; + } + /** * Extracts the relevant data from {@code commitInfo} into a {@code CommitResult}. */ @@ -98,6 +130,12 @@ public static CommitResult analyzeCommit(CommitInfo commitInfo, RepoConfiguratio String messageBody = (elements.length > MESSAGE_BODY_INDEX) ? getCommitMessageBody(elements[MESSAGE_BODY_INDEX]) : ""; + + String githubCommitUrl = getGithubQueryUrl(config, hash); + String htmlContainingPrUrl = getHtml(githubCommitUrl); + + boolean isNonPrCommit = !htmlContainingPrUrl.contains("class=\"pull-request\""); + String[] refs = (elements.length > REF_NAME_INDEX) ? elements[REF_NAME_INDEX].split(REF_SPLITTER) : new String[]{""}; @@ -109,7 +147,7 @@ public static CommitResult analyzeCommit(CommitInfo commitInfo, RepoConfiguratio } if (statLine.isEmpty()) { // empty commit, no files changed - return new CommitResult(author, hash, date, messageTitle, messageBody, tags); + return new CommitResult(author, hash, date, messageTitle, messageBody, isNonPrCommit, tags); } String[] statInfos = statLine.split(NEW_LINE_SPLITTER); @@ -117,7 +155,8 @@ public static CommitResult analyzeCommit(CommitInfo commitInfo, RepoConfiguratio Map fileTypeAndContributionMap = getFileTypesAndContribution(fileTypeContributions, config); - return new CommitResult(author, hash, date, messageTitle, messageBody, tags, fileTypeAndContributionMap); + return new CommitResult(author, hash, date, messageTitle, messageBody, isNonPrCommit, + tags, fileTypeAndContributionMap); } /** diff --git a/src/main/java/reposense/commits/CommitResultAggregator.java b/src/main/java/reposense/commits/CommitResultAggregator.java index 95031fce98..bb31233460 100644 --- a/src/main/java/reposense/commits/CommitResultAggregator.java +++ b/src/main/java/reposense/commits/CommitResultAggregator.java @@ -40,6 +40,9 @@ public static CommitContributionSummary aggregateCommitResults( getAuthorDailyContributionsMap(config.getAuthorDisplayNameMap().keySet(), commitResults, config.getZoneId()); + Map authorNonPrCommitsMap = getAuthorNonPrCommitsMap( + config.getAuthorDisplayNameMap().keySet(), commitResults); + Date lastDate = commitResults.size() == 0 ? null : getStartOfDate(commitResults.get(commitResults.size() - 1).getTime(), config.getZoneId()); @@ -50,7 +53,8 @@ public static CommitContributionSummary aggregateCommitResults( return new CommitContributionSummary( config.getAuthorDisplayNameMap(), authorDailyContributionsMap, - authorContributionVariance); + authorContributionVariance, + authorNonPrCommitsMap); } /** @@ -121,6 +125,26 @@ private static Map> getAuthorDailyContribu return authorDailyContributionsMap; } + private static Map getAuthorNonPrCommitsMap (Set authorSet, + List commitResults) { + Map authorNonPrCommitsMap = new HashMap<>(); + authorSet.forEach(author -> authorNonPrCommitsMap.put(author, 0)); + + for (CommitResult commitResult : commitResults) { + Author commitAuthor = commitResult.getAuthor(); + + Integer authorNonPrCommits = authorNonPrCommitsMap.get(commitAuthor); + + if (commitResult.isNonPrCommit()) { + authorNonPrCommits++; + } + + authorNonPrCommitsMap.put(commitAuthor, authorNonPrCommits); + } + + return authorNonPrCommitsMap; + } + private static void addDailyContributionForNewDate( List authorDailyContributions, Date date) { authorDailyContributions.add(new AuthorDailyContribution(date)); diff --git a/src/main/java/reposense/commits/model/CommitContributionSummary.java b/src/main/java/reposense/commits/model/CommitContributionSummary.java index 05ecbdea79..11ed104052 100644 --- a/src/main/java/reposense/commits/model/CommitContributionSummary.java +++ b/src/main/java/reposense/commits/model/CommitContributionSummary.java @@ -12,14 +12,17 @@ public class CommitContributionSummary { private final Map> authorDailyContributionsMap; private final Map authorContributionVariance; private final Map authorDisplayNameMap; + private final Map authorNonPrCommitsMap; public CommitContributionSummary( Map authorDisplayNameMap, Map> authorDailyContributionsMap, - Map authorContributionVariance) { + Map authorContributionVariance, + Map authorNonPrCommitsMap) { this.authorDisplayNameMap = authorDisplayNameMap; this.authorDailyContributionsMap = authorDailyContributionsMap; this.authorContributionVariance = authorContributionVariance; + this.authorNonPrCommitsMap = authorNonPrCommitsMap; } public Map getAuthorDisplayNameMap() { @@ -33,4 +36,6 @@ public Map> getAuthorDailyContributionsMap public Map getAuthorContributionVariance() { return authorContributionVariance; } + + public Map getAuthorNonPrCommitsMap() { return authorNonPrCommitsMap; } } diff --git a/src/main/java/reposense/commits/model/CommitResult.java b/src/main/java/reposense/commits/model/CommitResult.java index 75a2c05d42..656c7edc2a 100644 --- a/src/main/java/reposense/commits/model/CommitResult.java +++ b/src/main/java/reposense/commits/model/CommitResult.java @@ -15,29 +15,33 @@ public class CommitResult { private final String hash; private final String messageTitle; private final String messageBody; + private final boolean isNonPrCommit; private final String[] tags; private final Map fileTypesAndContributionMap; private final transient Author author; private final transient Date time; - public CommitResult(Author author, String hash, Date time, String messageTitle, String messageBody, String[] tags, - Map fileTypesAndContributionMap) { + public CommitResult(Author author, String hash, Date time, String messageTitle, String messageBody, + boolean isNonPrCommit, String[] tags, Map fileTypesAndContributionMap) { this.author = author; this.hash = hash; this.time = time; this.messageTitle = messageTitle; this.messageBody = messageBody; + this.isNonPrCommit = isNonPrCommit; this.tags = tags; this.fileTypesAndContributionMap = fileTypesAndContributionMap; } - public CommitResult(Author author, String hash, Date time, String messageTitle, String messageBody, String[] tags) { + public CommitResult(Author author, String hash, Date time, String messageTitle, String messageBody, + boolean isNonPrCommit, String[] tags) { this.author = author; this.hash = hash; this.time = time; this.messageTitle = messageTitle; this.messageBody = messageBody; + this.isNonPrCommit = isNonPrCommit; this.tags = tags; this.fileTypesAndContributionMap = Collections.emptyMap(); } @@ -66,6 +70,8 @@ public Date getTime() { return time; } + public boolean isNonPrCommit() { return isNonPrCommit; } + public int getInsertions() { int insertions = 0; for (ContributionPair contributionPair : fileTypesAndContributionMap.values()) { diff --git a/src/main/java/reposense/report/CommitReportJson.java b/src/main/java/reposense/report/CommitReportJson.java index 03fb5dac42..3d17ffbd3c 100644 --- a/src/main/java/reposense/report/CommitReportJson.java +++ b/src/main/java/reposense/report/CommitReportJson.java @@ -20,6 +20,7 @@ public class CommitReportJson { private final Map> authorFileTypeContributionMap; private final Map authorContributionVariance; private final Map authorDisplayNameMap; + private final Map authorNonPrCommitsMap; /** * Constructor to construct an empty commit report with the author's display name as {@code displayName}. @@ -38,6 +39,9 @@ public CommitReportJson(String displayName) { authorDisplayNameMap = new HashMap<>(); authorDisplayNameMap.put(emptyAuthor, displayName); + + authorNonPrCommitsMap = new HashMap<>(); + authorNonPrCommitsMap.put(emptyAuthor, 0); } public CommitReportJson(CommitContributionSummary commitSummary, AuthorshipSummary authorshipSummary) { @@ -45,5 +49,6 @@ public CommitReportJson(CommitContributionSummary commitSummary, AuthorshipSumma authorFileTypeContributionMap = authorshipSummary.getAuthorFileTypeContributionMap(); authorContributionVariance = commitSummary.getAuthorContributionVariance(); authorDisplayNameMap = commitSummary.getAuthorDisplayNameMap(); + authorNonPrCommitsMap = commitSummary.getAuthorNonPrCommitsMap(); } } diff --git a/src/test/java/reposense/commits/CommitInfoAnalyzerTest.java b/src/test/java/reposense/commits/CommitInfoAnalyzerTest.java index 85e00540f9..d8dd41b7e4 100644 --- a/src/test/java/reposense/commits/CommitInfoAnalyzerTest.java +++ b/src/test/java/reposense/commits/CommitInfoAnalyzerTest.java @@ -142,7 +142,7 @@ public void analyzeCommits_duplicateAuthorsDuplicateCommits_success() throws Exc expectedCommitResults.add(new CommitResult(author, LATEST_COMMIT_HASH, parseGitStrictIsoDate("2021-04-05T12:27:03+08:00"), "Add test lines for disowned code", - "", null, fileTypeAndContributionMap)); + "", false, null, fileTypeAndContributionMap)); config.setAuthorList(Arrays.asList(author, author)); config.setSinceDate(new GregorianCalendar(2021, Calendar.APRIL, 5).getTime()); @@ -168,12 +168,12 @@ public void analyzeCommits_multipleCommitsWithCommitMessageBody_success() throws expectedCommitResults.add(new CommitResult(author, "2eccc111e813e8b2977719b5959e32b674c56afe", parseGitStrictIsoDate("2019-06-19T13:02:01+08:00"), ">>>COMMIT INFO<<<", - "Hi there!\n\n>>>COMMIT INFO<<<\n", null, + "Hi there!\n\n>>>COMMIT INFO<<<\n", false, null, firstFileTypeAndContributionMap)); expectedCommitResults.add(new CommitResult(author, "8f8359649361f6736c31b87d499a4264f6cf7ed7", parseGitStrictIsoDate("2019-06-19T13:03:39+08:00"), "[#123] Reverted 1st commit", "This is a test to see if the commit message body works. " - + "All should be same same.\n>>>COMMIT INFO<<<\n|The end.", null, + + "All should be same same.\n>>>COMMIT INFO<<<\n|The end.", false, null, secondFileTypeAndContributionMap)); config.setBranch("751-CommitInfoAnalyzerTest-analyzeCommits_multipleCommitsWithCommitMessageBody_success"); @@ -201,11 +201,11 @@ public void analyzeCommits_commitsWithEmptyCommitMessageTitleOrBody_success() th // 1st test: Contains commit message title but no commit message body. expectedCommitResults.add(new CommitResult(author, "e54ae8fdb77c6c7d2c39131b816bfc03e6a6dd44", parseGitStrictIsoDate("2019-07-02T12:35:46+08:00"), "Test 1: With message title but no body", - "", null, firstFileTypeAndContributionMap)); + "", false, null, firstFileTypeAndContributionMap)); // 2nd test: Contains no commit message title and no commit message body. expectedCommitResults.add(new CommitResult(author, "57fa22fc2550210203c2941692f69ccb0cf18252", - parseGitStrictIsoDate("2019-07-02T12:36:14+08:00"), "", "", null, - secondFileTypeAndContributionMap)); + parseGitStrictIsoDate("2019-07-02T12:36:14+08:00"), "", "", false, + null, secondFileTypeAndContributionMap)); config.setBranch("751-CommitInfoAnalyzerTest-analyzeCommits_commitsWithEmptyCommitMessageTitleOrBody_success"); config.setAuthorList(Collections.singletonList(author)); @@ -231,10 +231,10 @@ public void analyzeCommits_commitsWithMultipleTags_success() throws Exception { expectedCommitResults.add(new CommitResult(author, "62c3a50ef9b3580b2070deac1eed2b3e2d701e04", parseGitStrictIsoDate("2019-12-20T22:45:18+08:00"), "Single Tag Commit", - "", new String[] {"1st"}, firstFileTypeAndContributionMap)); + "", false, new String[] {"1st"}, firstFileTypeAndContributionMap)); expectedCommitResults.add(new CommitResult(author, "c5e36ec059390233ac036db61a84fa6b55952506", parseGitStrictIsoDate("2019-12-20T22:47:21+08:00"), "Double Tag Commit", - "", new String[] {"2nd-tag", "1st-tag"}, secondFileTypeAndContributionMap)); + "", false, new String[] {"2nd-tag", "1st-tag"}, secondFileTypeAndContributionMap)); config.setBranch("879-CommitInfoAnalyzerTest-analyzeCommits_commitsWithMultipleTags_success"); config.setAuthorList(Collections.singletonList(author)); @@ -253,7 +253,8 @@ public void analyzeCommits_emptyCommits_success() throws Exception { List expectedCommitResults = new ArrayList<>(); expectedCommitResults.add(new CommitResult(author, "016ab87c4afe89a98225b96c98ff28dd4774410f", - parseGitStrictIsoDate("2020-01-27T22:20:51+08:00"), "empty commit", "", null)); + parseGitStrictIsoDate("2020-01-27T22:20:51+08:00"), "empty commit", "", + false, null)); config.setBranch("1019-CommitInfoAnalyzerTest-emptyCommits"); config.setAuthorList(Collections.singletonList(author)); @@ -274,7 +275,8 @@ public void analyzeCommits_commitsWithBinaryFileContribution_success() throws Ex // binary file contribution will have 0 contribution and won't be added to fileTypesAndContributionMap expectedCommitResults.add(new CommitResult(author, "a00c51138cbf5ab7d14f52b52abb182c8a369169", - parseGitStrictIsoDate("2020-04-06T16:41:10+08:00"), "Add binary file", "", null)); + parseGitStrictIsoDate("2020-04-06T16:41:10+08:00"), "Add binary file", "", + false, null)); config.setBranch("1192-CommitInfoAnalyzerTest-analyzeCommits_commitsWithBinaryContribution_success"); config.setAuthorList(Collections.singletonList(author)); @@ -300,13 +302,13 @@ public void analyzeCommits_fileNameWithSpecialChars_success() throws Exception { expectedCommitResults.add(new CommitResult(author, "cfb3c8dc477cb0af19fce8bead4d278f35afa396", parseGitStrictIsoDate("2020-04-20T12:09:39+08:00"), "Create file name without special chars", - "", null, firstFileTypeAndContributionMap)); + "", false, null, firstFileTypeAndContributionMap)); Map secondFileTypeAndContributionMap = new HashMap<>(); secondFileTypeAndContributionMap.put(FILETYPE_TXT, new ContributionPair(0, 0)); expectedCommitResults.add(new CommitResult(author, "17bde492e9a80d8699ad193cf87e677341f936cc", parseGitStrictIsoDate("2020-04-20T12:17:40+08:00"), "Rename to file name with special chars", - "", null, secondFileTypeAndContributionMap)); + "", false, null, secondFileTypeAndContributionMap)); config.setBranch("1244-CommitInfoAnalyzerTest-analyzeCommits_fileNameWithSpecialChars_success"); config.setAuthorList(Collections.singletonList(author)); From 4c16250b7918ac4aea9ddd284262493d77cb5da2 Mon Sep 17 00:00:00 2001 From: FH-30 Date: Thu, 1 Jul 2021 18:56:26 +0800 Subject: [PATCH 5/5] Fix checkstyle misatkes --- build.gradle | 4 ++-- .../java/reposense/commits/CommitInfoAnalyzer.java | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 76a19d33c0..f1e44a6cb2 100644 --- a/build.gradle +++ b/build.gradle @@ -14,8 +14,8 @@ mainClassName = 'reposense.RepoSense' node.nodeVersion = '10.16.0' -sourceCompatibility = JavaVersion.VERSION_11 -targetCompatibility = JavaVersion.VERSION_11 +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 repositories { mavenCentral() diff --git a/src/main/java/reposense/commits/CommitInfoAnalyzer.java b/src/main/java/reposense/commits/CommitInfoAnalyzer.java index 3eae8f3ee4..31f0eacb50 100644 --- a/src/main/java/reposense/commits/CommitInfoAnalyzer.java +++ b/src/main/java/reposense/commits/CommitInfoAnalyzer.java @@ -7,7 +7,14 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -43,6 +50,7 @@ public class CommitInfoAnalyzer { private static final String REF_SPLITTER = ",\\s"; private static final String NEW_LINE_SPLITTER = "\\n"; private static final String TAG_PREFIX = "tag:"; + private static final String PR_COMMIT_INDICATOR = "class=\"pull-request\""; private static final int COMMIT_HASH_INDEX = 0; private static final int AUTHOR_INDEX = 1; @@ -134,7 +142,7 @@ public static CommitResult analyzeCommit(CommitInfo commitInfo, RepoConfiguratio String githubCommitUrl = getGithubQueryUrl(config, hash); String htmlContainingPrUrl = getHtml(githubCommitUrl); - boolean isNonPrCommit = !htmlContainingPrUrl.contains("class=\"pull-request\""); + boolean isNonPrCommit = !htmlContainingPrUrl.contains(PR_COMMIT_INDICATOR); String[] refs = (elements.length > REF_NAME_INDEX) ? elements[REF_NAME_INDEX].split(REF_SPLITTER) @@ -163,7 +171,7 @@ public static CommitResult analyzeCommit(CommitInfo commitInfo, RepoConfiguratio * Returns the number of lines added and deleted for the specified file types in {@code config}. */ private static Map getFileTypesAndContribution(String[] filePathContributions, - RepoConfiguration config) { + RepoConfiguration config) { Map fileTypesAndContributionMap = new HashMap<>(); for (String filePathContribution : filePathContributions) { String[] infos = filePathContribution.split(TAB_SPLITTER);