Skip to content

Commit 4ced2e8

Browse files
authored
[#2524] Add new --author-dedup-mode flag for deduplicating authors (#2532)
Add deduplication flag Allows for deduplating authors without specifying all authors to display in repo (all authors are displayed, and deduplication is applied onto them based on author-config)
1 parent 8d8f038 commit 4ced2e8

File tree

22 files changed

+331
-10
lines changed

22 files changed

+331
-10
lines changed

docs/ug/cli.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ partial credit.
4646

4747
<!-- --------------------------◘---------------------------------------------------------------------------- -->
4848

49+
### `--author-dedup-mode`
50+
51+
**`--author-dedup-mode`**: Deduplicates authors based on the `author-config.csv` file, while preserving all commit authors.
52+
* Default: this feature is turned **_off_** by default
53+
* Example: `--author-dedup-mode`
54+
55+
<box type="info" seamless>
56+
57+
* Must be used in conjunction with the `--config` flag and requires an `author-config.csv` file to be present.
58+
* When enabled, all commit authors will be included in the report while respecting the aliases configured in the `author-config.csv` file.
59+
* Authors not found in the `author-config.csv` file will be added as per normal with their commit names.
60+
</box>
61+
62+
<!-- --------------------------◘---------------------------------------------------------------------------- -->
63+
4964
### `--config`, `-c`
5065

5166
<div id="section-config">

src/main/java/reposense/RepoSense.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public static void main(String[] args) {
7575
cliArguments.isShallowCloningPerformed());
7676
RepoConfiguration.setIsFindingPreviousAuthorsPerformedToRepoConfigs(configs,
7777
cliArguments.isFindingPreviousAuthorsPerformed());
78+
RepoConfiguration.setIsAuthorDedupModeToRepoConfigs(configs,
79+
cliArguments.isAuthorDedupMode());
7880

7981
List<String[]> globalGitConfig = GitConfig.getGlobalGitLfsConfig();
8082
if (globalGitConfig.size() != 0) {

src/main/java/reposense/model/CliArguments.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class CliArguments {
4141
private boolean isPortfolio;
4242
private boolean isFreshClonePerformed = ArgsParser.DEFAULT_SHOULD_FRESH_CLONE;
4343
private boolean isOnlyTextRefreshed;
44+
private boolean isAuthorDedupMode;
4445

4546
private List<String> locations;
4647
private boolean isViewModeOnly;
@@ -210,6 +211,10 @@ public boolean isOnlyTextRefreshed() {
210211
return isOnlyTextRefreshed;
211212
}
212213

214+
public boolean isAuthorDedupMode() {
215+
return isAuthorDedupMode;
216+
}
217+
213218
@Override
214219
public boolean equals(Object other) {
215220
// short circuit if same object
@@ -253,7 +258,8 @@ public boolean equals(Object other) {
253258
&& this.isAuthorshipAnalyzed == otherCliArguments.isAuthorshipAnalyzed
254259
&& Objects.equals(this.originalityThreshold, otherCliArguments.originalityThreshold)
255260
&& this.isPortfolio == otherCliArguments.isPortfolio
256-
&& this.isOnlyTextRefreshed == otherCliArguments.isOnlyTextRefreshed;
261+
&& this.isOnlyTextRefreshed == otherCliArguments.isOnlyTextRefreshed
262+
&& this.isAuthorDedupMode == otherCliArguments.isAuthorDedupMode;
257263
}
258264

259265
/**
@@ -552,6 +558,16 @@ public Builder isOnlyTextRefreshed(boolean isOnlyTextRefreshed) {
552558
return this;
553559
}
554560

561+
/**
562+
* Adds the {@code isAuthorDedupMode} to CLIArguments.
563+
*
564+
* @param isAuthorDedupMode Is author dedup mode.
565+
*/
566+
public Builder isAuthorDedupMode(boolean isAuthorDedupMode) {
567+
this.cliArguments.isAuthorDedupMode = isAuthorDedupMode;
568+
return this;
569+
}
570+
555571
/**
556572
* Builds CliArguments.
557573
*

src/main/java/reposense/model/RepoConfiguration.java

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class RepoConfiguration {
4848
private transient boolean isLastModifiedDateIncluded;
4949
private transient boolean isShallowCloningPerformed = false;
5050
private transient boolean isFindingPreviousAuthorsPerformed = false;
51+
private transient boolean isAuthorDedupMode = false;
5152
private transient boolean isFormatsOverriding = false;
5253
private transient boolean isIgnoreGlobListOverriding;
5354
private transient boolean isIgnoreCommitListOverriding = false;
@@ -328,7 +329,19 @@ public Builder isShallowCloningPerformed(boolean isShallowCloningPerformed) {
328329
}
329330

330331
/**
331-
* Updates the {@code isFindingPreviousAuthorsPerformed} for {@code RepoConfiguration}.
332+
* Updates the {@code isAuthorDedupMode} for {@code RepoConfiguration}.
333+
*
334+
* @param isAuthorDedupMode Checks if author dedup mode is enabled.
335+
* @return This builder object.
336+
*/
337+
public Builder isAuthorDedupMode(boolean isAuthorDedupMode) {
338+
this.repoConfiguration.isAuthorDedupMode = isAuthorDedupMode;
339+
return this;
340+
}
341+
342+
/**
343+
* Updates the {@code isFindingPreviousAuthorsPerformed} for
344+
* {@code RepoConfiguration}.
332345
*
333346
* @param isFindingPreviousAuthorsPerformed Checks if finding previous authors is performed.
334347
* @return This builder object.
@@ -530,28 +543,35 @@ public static void setZoneIdToRepoConfigs(List<RepoConfiguration> configs, ZoneI
530543
}
531544

532545
public static void setIsLastModifiedDateIncludedToRepoConfigs(List<RepoConfiguration> configs,
533-
boolean isLastModifiedDateIncluded) {
546+
boolean isLastModifiedDateIncluded) {
534547
for (RepoConfiguration config : configs) {
535548
config.setIsLastModifiedDateIncluded(isLastModifiedDateIncluded);
536549
}
537550
}
538551

539552
public static void setIsShallowCloningPerformedToRepoConfigs(List<RepoConfiguration> configs,
540-
boolean isShallowCloningPerformed) {
553+
boolean isShallowCloningPerformed) {
541554
if (isShallowCloningPerformed) {
542555
configs.stream().forEach(config -> config.setIsShallowCloningPerformed(true));
543556
}
544557
}
545558

546559
public static void setIsFindingPreviousAuthorsPerformedToRepoConfigs(List<RepoConfiguration> configs,
547-
boolean isFindingPreviousAuthorsPerformed) {
560+
boolean isFindingPreviousAuthorsPerformed) {
548561
if (isFindingPreviousAuthorsPerformed) {
549562
configs.stream().forEach(config -> config.setIsFindingPreviousAuthorsPerformed(true));
550563
}
551564
}
552565

566+
public static void setIsAuthorDedupModeToRepoConfigs(List<RepoConfiguration> configs,
567+
boolean isAuthorDedupMode) {
568+
if (isAuthorDedupMode) {
569+
configs.stream().forEach(config -> config.setIsAuthorDedupMode(true));
570+
}
571+
}
572+
553573
public static void setHasAuthorConfigFileToRepoConfigs(List<RepoConfiguration> configs,
554-
boolean setHasAuthorConfigFile) {
574+
boolean setHasAuthorConfigFile) {
555575
configs.stream().forEach(config -> config.setHasAuthorConfigFile(setHasAuthorConfigFile));
556576
}
557577

@@ -568,8 +588,8 @@ public static void merge(List<RepoConfiguration> repoConfigs, List<AuthorConfigu
568588
continue;
569589
}
570590

571-
List<RepoConfiguration> locationMatchingRepoConfigs =
572-
getMatchingRepoConfigsByLocation(repoConfigs, authorConfig.getLocation());
591+
List<RepoConfiguration> locationMatchingRepoConfigs = getMatchingRepoConfigsByLocation(repoConfigs,
592+
authorConfig.getLocation());
573593

574594
if (locationMatchingRepoConfigs.isEmpty()) {
575595
logger.warning(String.format(
@@ -678,7 +698,7 @@ public static void setStandaloneConfigIgnoredToRepoConfigs(List<RepoConfiguratio
678698
* {@code ignoreFilesizeLimit} is true.
679699
*/
680700
public static void setFileSizeLimitIgnoredToRepoConfigs(List<RepoConfiguration> configs,
681-
boolean ignoreFileSizeLimit) {
701+
boolean ignoreFileSizeLimit) {
682702
if (ignoreFileSizeLimit) {
683703
configs.forEach(config -> config.setFileSizeLimitIgnored(true));
684704
}
@@ -881,6 +901,10 @@ public void setIsFindingPreviousAuthorsPerformed(boolean isFindingPreviousAuthor
881901
this.isFindingPreviousAuthorsPerformed = isFindingPreviousAuthorsPerformed;
882902
}
883903

904+
public void setIsAuthorDedupMode(boolean isAuthorDedupMode) {
905+
this.isAuthorDedupMode = isAuthorDedupMode;
906+
}
907+
884908
public boolean isLastModifiedDateIncluded() {
885909
return this.isLastModifiedDateIncluded;
886910
}
@@ -1081,6 +1105,10 @@ public boolean isFindingPreviousAuthorsPerformed() {
10811105
return isFindingPreviousAuthorsPerformed;
10821106
}
10831107

1108+
public boolean isAuthorDedupMode() {
1109+
return isAuthorDedupMode;
1110+
}
1111+
10841112
public boolean isHasUpdatedSinceDateInConfig() {
10851113
return hasUpdatedSinceDateInConfig;
10861114
}

src/main/java/reposense/parser/ArgsParser.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.File;
44
import java.io.IOException;
5+
import java.nio.file.Files;
56
import java.nio.file.Path;
67
import java.nio.file.Paths;
78
import java.time.LocalDateTime;
@@ -79,6 +80,7 @@ public class ArgsParser {
7980
public static final String[] ORIGINALITY_THRESHOLD_FLAGS = new String[] {"--originality-threshold", "-ot"};
8081
public static final String[] PORTFOLIO_FLAG = new String[] {"--portfolio", "-P"};
8182
public static final String[] REFRESH_ONLY_TEXT_FLAG = new String[] {"--text", "-T"};
83+
public static final String[] AUTHOR_DEDUP_MODE_FLAGS = new String[] {"--author-dedup-mode"};
8284

8385
private static final Logger logger = LogsManager.getLogger(ArgsParser.class);
8486

@@ -99,6 +101,10 @@ public class ArgsParser {
99101
"\"Since Date\" cannot be later than \"Until Date\".";
100102
private static final String MESSAGE_SINCE_DATE_LATER_THAN_TODAY_DATE =
101103
"\"Since Date\" must not be later than today's date.";
104+
private static final String MESSAGE_AUTHOR_DEDUP_MODE_WITHOUT_CONFIG =
105+
"--author-dedup-mode flag is used without --config flag. The flag will be ignored.";
106+
private static final String MESSAGE_AUTHOR_CONFIG_FILE_NOT_FOUND =
107+
"--author-dedup-mode flag is used but author-config.csv file not found at %s. The flag will be ignored.";
102108
private static final Path EMPTY_PATH = Paths.get("");
103109
private static final Path DEFAULT_CONFIG_PATH = Paths.get(System.getProperty("user.dir")
104110
+ File.separator + "config" + File.separator);
@@ -231,6 +237,11 @@ private static ArgumentParser getArgumentParser() {
231237
.action(Arguments.storeTrue())
232238
.help("Refreshes only the text content of the report, without analyzing the repositories again.");
233239

240+
parser.addArgument(AUTHOR_DEDUP_MODE_FLAGS)
241+
.dest(AUTHOR_DEDUP_MODE_FLAGS[0])
242+
.action(Arguments.storeTrue())
243+
.help("Deduplicates authors based on the author-config file, while preserving all commit authors.");
244+
234245
// Mutex flags - these will always be the last parameters in help message.
235246
mutexParser.addArgument(CONFIG_FLAGS)
236247
.dest(CONFIG_FLAGS[0])
@@ -316,6 +327,7 @@ public static CliArguments parse(String[] args) throws HelpScreenException, Pars
316327
int numAnalysisThreads = results.get(ANALYSIS_THREADS_FLAG[0]);
317328
boolean shouldPerformFreshCloning = results.get(FRESH_CLONING_FLAG[0]);
318329
boolean shouldRefreshOnlyText = results.get(REFRESH_ONLY_TEXT_FLAG[0]);
330+
boolean isAuthorDedupMode = results.get(AUTHOR_DEDUP_MODE_FLAGS[0]);
319331

320332
CliArguments.Builder cliArgumentsBuilder = new CliArguments.Builder()
321333
.configFolderPath(configFolderPath)
@@ -335,7 +347,8 @@ public static CliArguments parse(String[] args) throws HelpScreenException, Pars
335347
.originalityThreshold(originalityThreshold)
336348
.isPortfolio(isPortfolio)
337349
.isFreshClonePerformed(shouldPerformFreshCloning)
338-
.isOnlyTextRefreshed(shouldRefreshOnlyText);
350+
.isOnlyTextRefreshed(shouldRefreshOnlyText)
351+
.isAuthorDedupMode(isAuthorDedupMode);
339352

340353
LogsManager.setLogFolderLocation(outputFolderPath);
341354

@@ -361,6 +374,20 @@ public static CliArguments parse(String[] args) throws HelpScreenException, Pars
361374
}
362375
cliArgumentsBuilder.isAutomaticallyLaunching(isAutomaticallyLaunching);
363376

377+
// Validate author-dedup-mode flag
378+
if (isAuthorDedupMode) {
379+
// Check if --config flag was explicitly provided
380+
if (configFolderPath.equals(DEFAULT_CONFIG_PATH)) {
381+
logger.warning(MESSAGE_AUTHOR_DEDUP_MODE_WITHOUT_CONFIG);
382+
} else {
383+
// Check if author-config.csv exists
384+
Path authorConfigPath = configFolderPath.resolve(AuthorConfigCsvParser.AUTHOR_CONFIG_FILENAME);
385+
if (!Files.exists(authorConfigPath)) {
386+
logger.warning(String.format(MESSAGE_AUTHOR_CONFIG_FILE_NOT_FOUND, authorConfigPath));
387+
}
388+
}
389+
}
390+
364391
return cliArgumentsBuilder.build();
365392
}
366393

src/main/java/reposense/report/ReportGenerator.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,27 @@ private void updateAuthorList(RepoConfiguration config) throws NoAuthorsWithComm
503503
}
504504

505505
config.setAuthorList(authorList);
506+
} else if (config.isAuthorDedupMode() && config.getAuthorConfig().hasAuthorConfigFile()) {
507+
// In dedup mode, add all commit authors to the config while keeping configured aliases
508+
logger.info(String.format("Author dedup mode enabled. Including all commit authors while "
509+
+ "preserving configured aliases for %s (%s).", config.getLocation(), config.getBranch()));
510+
List<Author> authorList = GitShortlog.getAuthors(config);
511+
512+
if (authorList.isEmpty()) {
513+
throw new NoAuthorsWithCommitsFoundException();
514+
}
515+
516+
// Add all commit authors to the config, but skip those that match configured aliases
517+
for (Author commitAuthor : authorList) {
518+
String gitId = commitAuthor.getGitId();
519+
Author configuredAuthor = config.getAuthorConfig()
520+
.getAuthor(gitId, gitId);
521+
522+
if (configuredAuthor == Author.UNKNOWN_AUTHOR) {
523+
// Not in configured authors/aliases, add as new author
524+
config.addAuthor(commitAuthor);
525+
}
526+
}
506527
}
507528
config.removeIgnoredAuthors();
508529
}

0 commit comments

Comments
 (0)