diff --git a/README.md b/README.md index 826ba90910..47b6943e09 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ RepoSense is a contribution analysis tool for Git repositories. It is particular - [User Guide for the latest `master` (not yet released to users)](https://reposense.github.io/RepoSense) --- +### Our Contributors : + + + **Acknowledgements**: The web previews of RepoSense is powered by Netlify and Surge. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 56afac2e4f..97789ce3b0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7574,9 +7574,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "dev": true, "funding": [ { @@ -22394,9 +22394,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "dev": true }, "for-each": { diff --git a/src/main/java/reposense/parser/ArgsParser.java b/src/main/java/reposense/parser/ArgsParser.java index 05632bfb4d..91a46c180f 100644 --- a/src/main/java/reposense/parser/ArgsParser.java +++ b/src/main/java/reposense/parser/ArgsParser.java @@ -80,6 +80,10 @@ public class ArgsParser { private static final String MESSAGE_INVALID_CONFIG_JSON = "%s Ignoring the report config provided."; private static final String MESSAGE_SINCE_D1_WITH_PERIOD = "You may be using --since d1 with the --period flag. " + "This may result in an incorrect date range being analysed."; + private static final String MESSAGE_SINCE_DATE_LATER_THAN_UNTIL_DATE = + "\"Since Date\" cannot be later than \"Until Date\"."; + private static final String MESSAGE_SINCE_DATE_LATER_THAN_TODAY_DATE = + "\"Since Date\" must not be later than today's date."; private static final Path EMPTY_PATH = Paths.get(""); private static final Path DEFAULT_CONFIG_PATH = Paths.get(System.getProperty("user.dir") + File.separator + "config" + File.separator); @@ -258,76 +262,78 @@ private static ArgumentParser getArgumentParser() { * @throws ParseException if the given string arguments fails to parse to a {@link CliArguments} object. */ public static CliArguments parse(String[] args) throws HelpScreenException, ParseException { + ArgumentParser parser = getArgumentParser(); + Namespace results; + try { - ArgumentParser parser = getArgumentParser(); - Namespace results = parser.parseArgs(args); - - Path configFolderPath = results.get(CONFIG_FLAGS[0]); - Path reportFolderPath = results.get(VIEW_FLAGS[0]); - Path outputFolderPath = results.get(OUTPUT_FLAGS[0]); - ZoneId zoneId = results.get(TIMEZONE_FLAGS[0]); - Path assetsFolderPath = results.get(ASSETS_FLAGS[0]); - List locations = results.get(REPO_FLAGS[0]); - List formats = FileType.convertFormatStringsToFileTypes(results.get(FORMAT_FLAGS[0])); - boolean isStandaloneConfigIgnored = results.get(IGNORE_CONFIG_FLAGS[0]); - boolean isFileSizeLimitIgnored = results.get(IGNORE_SIZELIMIT_FLAGS[0]); - boolean shouldIncludeLastModifiedDate = results.get(LAST_MODIFIED_DATE_FLAGS[0]); - boolean shouldPerformShallowCloning = results.get(SHALLOW_CLONING_FLAGS[0]); - boolean shouldFindPreviousAuthors = results.get(FIND_PREVIOUS_AUTHORS_FLAGS[0]); - boolean isTestMode = results.get(TEST_MODE_FLAG[0]); - int numCloningThreads = results.get(CLONING_THREADS_FLAG[0]); - int numAnalysisThreads = results.get(ANALYSIS_THREADS_FLAG[0]); - - CliArguments.Builder cliArgumentsBuilder = new CliArguments.Builder() - .configFolderPath(configFolderPath) - .reportDirectoryPath(reportFolderPath) - .outputFilePath(outputFolderPath) - .zoneId(zoneId) - .assetsFilePath(assetsFolderPath) - .locations(locations) - .formats(formats) - .isStandaloneConfigIgnored(isStandaloneConfigIgnored) - .isFileSizeLimitIgnored(isFileSizeLimitIgnored) - .isLastModifiedDateIncluded(shouldIncludeLastModifiedDate) - .isShallowCloningPerformed(shouldPerformShallowCloning) - .isFindingPreviousAuthorsPerformed(shouldFindPreviousAuthors) - .numCloningThreads(numCloningThreads) - .numAnalysisThreads(numAnalysisThreads) - .isTestMode(isTestMode); - - LogsManager.setLogFolderLocation(outputFolderPath); - - if (locations == null && configFolderPath.equals(DEFAULT_CONFIG_PATH)) { - logger.info(MESSAGE_USING_DEFAULT_CONFIG_PATH); - } + results = parser.parseArgs(args); + } catch (HelpScreenException hse) { + throw hse; + } catch (ArgumentParserException ape) { + throw new ParseException(getArgumentParser().formatUsage() + ape.getMessage() + "\n"); + } + + Path configFolderPath = results.get(CONFIG_FLAGS[0]); + Path reportFolderPath = results.get(VIEW_FLAGS[0]); + Path outputFolderPath = results.get(OUTPUT_FLAGS[0]); + ZoneId zoneId = results.get(TIMEZONE_FLAGS[0]); + Path assetsFolderPath = results.get(ASSETS_FLAGS[0]); + List locations = results.get(REPO_FLAGS[0]); + List formats = FileType.convertFormatStringsToFileTypes(results.get(FORMAT_FLAGS[0])); + boolean isStandaloneConfigIgnored = results.get(IGNORE_CONFIG_FLAGS[0]); + boolean isFileSizeLimitIgnored = results.get(IGNORE_SIZELIMIT_FLAGS[0]); + boolean shouldIncludeLastModifiedDate = results.get(LAST_MODIFIED_DATE_FLAGS[0]); + boolean shouldPerformShallowCloning = results.get(SHALLOW_CLONING_FLAGS[0]); + boolean shouldFindPreviousAuthors = results.get(FIND_PREVIOUS_AUTHORS_FLAGS[0]); + boolean isTestMode = results.get(TEST_MODE_FLAG[0]); + int numCloningThreads = results.get(CLONING_THREADS_FLAG[0]); + int numAnalysisThreads = results.get(ANALYSIS_THREADS_FLAG[0]); + + CliArguments.Builder cliArgumentsBuilder = new CliArguments.Builder() + .configFolderPath(configFolderPath) + .reportDirectoryPath(reportFolderPath) + .outputFilePath(outputFolderPath) + .zoneId(zoneId) + .assetsFilePath(assetsFolderPath) + .locations(locations) + .formats(formats) + .isStandaloneConfigIgnored(isStandaloneConfigIgnored) + .isFileSizeLimitIgnored(isFileSizeLimitIgnored) + .isLastModifiedDateIncluded(shouldIncludeLastModifiedDate) + .isShallowCloningPerformed(shouldPerformShallowCloning) + .isFindingPreviousAuthorsPerformed(shouldFindPreviousAuthors) + .numCloningThreads(numCloningThreads) + .numAnalysisThreads(numAnalysisThreads) + .isTestMode(isTestMode); + + LogsManager.setLogFolderLocation(outputFolderPath); + + if (locations == null && configFolderPath.equals(DEFAULT_CONFIG_PATH)) { + logger.info(MESSAGE_USING_DEFAULT_CONFIG_PATH); + } - addReportConfigToBuilder(cliArgumentsBuilder, results); - addAnalysisDatesToBuilder(cliArgumentsBuilder, results); + addReportConfigToBuilder(cliArgumentsBuilder, results); + addAnalysisDatesToBuilder(cliArgumentsBuilder, results); - boolean isViewModeOnly = reportFolderPath != null - && !reportFolderPath.equals(EMPTY_PATH) - && configFolderPath.equals(DEFAULT_CONFIG_PATH) - && locations == null; - cliArgumentsBuilder.isViewModeOnly(isViewModeOnly); + boolean isViewModeOnly = reportFolderPath != null + && !reportFolderPath.equals(EMPTY_PATH) + && configFolderPath.equals(DEFAULT_CONFIG_PATH) + && locations == null; + cliArgumentsBuilder.isViewModeOnly(isViewModeOnly); - boolean isAutomaticallyLaunching = reportFolderPath != null; - if (isAutomaticallyLaunching && !reportFolderPath.equals(EMPTY_PATH) && !isViewModeOnly) { - logger.info(String.format("Ignoring argument '%s' for --view.", reportFolderPath.toString())); - } - cliArgumentsBuilder.isAutomaticallyLaunching(isAutomaticallyLaunching); + boolean isAutomaticallyLaunching = reportFolderPath != null; + if (isAutomaticallyLaunching && !reportFolderPath.equals(EMPTY_PATH) && !isViewModeOnly) { + logger.info(String.format("Ignoring argument '%s' for --view.", reportFolderPath.toString())); + } + cliArgumentsBuilder.isAutomaticallyLaunching(isAutomaticallyLaunching); - boolean shouldPerformFreshCloning = isTestMode - ? results.get(FRESH_CLONING_FLAG[0]) - : DEFAULT_SHOULD_FRESH_CLONE; - cliArgumentsBuilder.isFreshClonePerformed(shouldPerformFreshCloning); + boolean shouldPerformFreshCloning = isTestMode + ? results.get(FRESH_CLONING_FLAG[0]) + : DEFAULT_SHOULD_FRESH_CLONE; + cliArgumentsBuilder.isFreshClonePerformed(shouldPerformFreshCloning); - return cliArgumentsBuilder.build(); - } catch (HelpScreenException hse) { - throw hse; - } catch (ArgumentParserException ape) { - throw new ParseException(getArgumentParser().formatUsage() + ape.getMessage() + "\n"); - } + return cliArgumentsBuilder.build(); } /** @@ -420,8 +426,13 @@ private static void addAnalysisDatesToBuilder(CliArguments.Builder builder, Name ? untilDate : currentDate; - TimeUtil.verifySinceDateIsValid(sinceDate, currentDate); - TimeUtil.verifyDatesRangeIsCorrect(sinceDate, untilDate); + if (sinceDate.compareTo(currentDate) > 0) { + throw new ParseException(MESSAGE_SINCE_DATE_LATER_THAN_TODAY_DATE); + } + + if (sinceDate.compareTo(untilDate) > 0) { + throw new ParseException(MESSAGE_SINCE_DATE_LATER_THAN_UNTIL_DATE); + } builder.sinceDate(sinceDate) .isSinceDateProvided(isSinceDateProvided) diff --git a/src/main/java/reposense/parser/RepoConfigCsvParser.java b/src/main/java/reposense/parser/RepoConfigCsvParser.java index 8c22be4a57..4a084d31a9 100644 --- a/src/main/java/reposense/parser/RepoConfigCsvParser.java +++ b/src/main/java/reposense/parser/RepoConfigCsvParser.java @@ -115,20 +115,19 @@ protected void processLine(List results, CSVRecord record) th // If file diff limit is specified if (fileSizeLimitStringList.size() > 0) { + String fileSizeLimitString = fileSizeLimitStringList.get(0).trim(); + int parseValue; + if (isFileSizeLimitIgnored) { logger.warning("Ignoring file size limit column since file size limit is ignored"); isFileSizeLimitOverriding = false; + } else if (!StringsUtil.isNumeric(fileSizeLimitString) + || (parseValue = Integer.parseInt(fileSizeLimitString)) <= 0) { + logger.warning(String.format("Values in \"%s\" column should be positive integers.", + FILESIZE_LIMIT_HEADER[0])); + isFileSizeLimitOverriding = false; } else { - String fileSizeLimitString = fileSizeLimitStringList.get(0).trim(); - int parseValue; - if (!StringsUtil.isNumeric(fileSizeLimitString) - || (parseValue = Integer.parseInt(fileSizeLimitString)) <= 0) { - logger.warning(String.format("Values in \"%s\" column should be positive integers.", - FILESIZE_LIMIT_HEADER[0])); - isFileSizeLimitOverriding = false; - } else { - fileSizeLimit = parseValue; - } + fileSizeLimit = parseValue; } } diff --git a/src/main/java/reposense/util/TimeUtil.java b/src/main/java/reposense/util/TimeUtil.java index 96a71b7e17..83de42414c 100644 --- a/src/main/java/reposense/util/TimeUtil.java +++ b/src/main/java/reposense/util/TimeUtil.java @@ -9,7 +9,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import reposense.parser.ParseException; import reposense.parser.SinceDateArgumentType; import reposense.system.LogsManager; @@ -23,10 +22,6 @@ public class TimeUtil { // "uuuu" is used for year since "yyyy" does not work with ResolverStyle.STRICT private static final DateTimeFormatter CLI_ARGS_DATE_FORMAT = DateTimeFormatter.ofPattern("d/M/uuuu HH:mm:ss"); - private static final String MESSAGE_SINCE_DATE_LATER_THAN_UNTIL_DATE = - "\"Since Date\" cannot be later than \"Until Date\"."; - private static final String MESSAGE_SINCE_DATE_LATER_THAN_TODAY_DATE = - "\"Since Date\" must not be later than today's date."; private static final String EARLIEST_VALID_DATE = "1970-01-01T00:00:00"; private static final String LATEST_VALID_DATE = "2099-12-31T23:59:59"; @@ -168,30 +163,6 @@ public static boolean isEqualToArbitraryFirstDateConverted(LocalDateTime dateTim return dateTime.equals(getArbitraryFirstCommitDateConverted(zoneId)); } - /** - * Verifies that {@code sinceDate} is earlier than {@code untilDate}. - * - * @throws ParseException if {@code sinceDate} supplied is later than {@code untilDate}. - */ - public static void verifyDatesRangeIsCorrect(LocalDateTime sinceDate, LocalDateTime untilDate) - throws ParseException { - if (sinceDate.compareTo(untilDate) > 0) { - throw new ParseException(MESSAGE_SINCE_DATE_LATER_THAN_UNTIL_DATE); - } - } - - /** - * Verifies that {@code sinceDate} is no later than the date of report generation, given by {@code currentDate}. - * - * @throws ParseException if {@code sinceDate} supplied is later than date of report generation. - */ - public static void verifySinceDateIsValid(LocalDateTime sinceDate, LocalDateTime currentDate) - throws ParseException { - if (sinceDate.compareTo(currentDate) > 0) { - throw new ParseException(MESSAGE_SINCE_DATE_LATER_THAN_TODAY_DATE); - } - } - /** * Extracts the first substring of {@code date} string that matches the {@code DATE_FORMAT_REGEX}. */ diff --git a/src/test/java/reposense/parser/ArgsParserTest.java b/src/test/java/reposense/parser/ArgsParserTest.java index 11fa3a5714..1ed90dbbc9 100644 --- a/src/test/java/reposense/parser/ArgsParserTest.java +++ b/src/test/java/reposense/parser/ArgsParserTest.java @@ -11,6 +11,7 @@ import java.time.LocalDateTime; import java.time.Month; import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; @@ -606,6 +607,36 @@ public void sinceDate_laterThanUntilDate_throwsParseException() { Assertions.assertThrows(ParseException.class, () -> ArgsParser.parse(translateCommandline(input))); } + @Test + public void sinceDate_laterThanCurrentDate_throwsParseException() { + LocalDateTime tomorrowDateTime = LocalDateTime.now() + .plusDays(1L); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + String tomorrow = tomorrowDateTime.format(formatter); + + + String input = DEFAULT_INPUT_BUILDER.addSinceDate(tomorrow) + .build(); + Assertions.assertThrows(ParseException.class, () -> ArgsParser.parse(translateCommandline(input))); + } + + @Test + public void sinceDate_beforeUntilDateAndLaterThanCurrentDate_throwsParseException() { + LocalDateTime tomorrowDateTime = LocalDateTime.now() + .plusDays(1L); + LocalDateTime dayAfterDateTime = LocalDateTime.now() + .plusDays(2L); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + String tomorrow = tomorrowDateTime.format(formatter); + String dayAfter = dayAfterDateTime.format(formatter); + + String input = DEFAULT_INPUT_BUILDER.addSinceDate(tomorrow) + .addUntilDate(dayAfter) + .build(); + Assertions.assertThrows(ParseException.class, () -> ArgsParser.parse(translateCommandline(input))); + } + @Test public void period_withBothSinceDateAndUntilDate_throwsParseException() { String input = DEFAULT_INPUT_BUILDER.addPeriod("18d")