Skip to content

Commit

Permalink
Merge branch 'master' into 944-analyze-authorship
Browse files Browse the repository at this point in the history
# Conflicts:
#	frontend/cypress/tests/chartView/chartView_zoomFeature.cy.js
#	frontend/src/views/c-authorship.vue
  • Loading branch information
SkyBlaise99 committed Nov 8, 2023
2 parents 4bd05a7 + e42c14e commit 950c912
Show file tree
Hide file tree
Showing 25 changed files with 130 additions and 99 deletions.
4 changes: 2 additions & 2 deletions docs/dg/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* [`GitBranch`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitBranch.java): Wrapper class for `git branch` functionality. Gets the name of the working branch of the target repo.
* [`GitCatFile`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitCatFile.java): Wrapper class for `git cat-file` functionality. Obtains the parent commit hash with the given commit indicated by the commit hash.
* [`GitCheckout`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitCheckout.java): Wrapper class for `git checkout` functionality. Checks out the repository by branch name or commit hash.
* [`GitClone`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitClone.java): Wrapper class for `git clone` functionality. Clones the repository from *GitHub* into a temporary folder in order to run the analysis.
* [`GitClone`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitClone.java): Wrapper class for `git clone` functionality. Clones the repository from the given URL or local directory into a temporary folder in order to run the analysis.
* [`GitDiff`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitDiff.java): Wrapper class for `git diff` functionality. Obtains the changes between commits.
* [`GitLog`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitLog.java): Wrapper class for `git log` functionality. Obtains the commit logs and the authors' info.
* [`GitRevList`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/git/GitRevList.java): Wrapper class for `git rev-list` functionality. Retrieves the commit objects in reverse chronological order.
Expand Down Expand Up @@ -93,7 +93,7 @@ Note that when constructing new commands containing path arguments, use the `Str
## Model

[`Model`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/model) holds the data structures that are commonly used by the different aspects of *RepoSense*.
* [`Author`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/model/Author.java) stores the `GitHub ID` of an author. Any contributions or commits made by the author, using his/her `GitHub ID` or aliases, will be attributed to the same `Author` object. `AuthorshipReporter` and `CommitsReporter` use it to attribute the commit and file contributions to the respective authors.
* [`Author`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/model/Author.java) stores the `Git ID` of an author. Any contributions or commits made by the author, using his/her `Git ID` or aliases, will be attributed to the same `Author` object. `AuthorshipReporter` and `CommitsReporter` use it to attribute the commit and file contributions to the respective authors.
* [`CliArguments`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/model/CliArguments.java) stores the parsed command-line arguments supplied by the user. It contains the configuration settings such as the CSV config file to read from, the directory to output the report to, and the date range of commits to analyze. These configuration settings are passed into `RepoConfiguration`.
* [`FileTypeManager`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/model/FileTypeManager.java) stores the file format to be analyzed and the custom groups specified by the user for any repository.
* [`RepoConfiguration`](https://github.com/reposense/RepoSense/blob/master/src/main/java/reposense/model/RepoConfiguration.java) stores the configuration information from the CSV config file for a single repository: the repository's organization, name, branch, list of authors to analyze, date range to analyze commits, and files from `CliArguments`.
Expand Down
8 changes: 4 additions & 4 deletions docs/ug/configFiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,14 @@ To use this feature, add a `_reposense/config.json` to the root of your repo usi
"authors":
[
{
"githubId": "alice",
"gitId": "alice",
"emails": ["alice@example.com", "alicet@example.com"],
"displayName": "Alice T.",
"authorNames": ["AT", "A"],
"ignoreGlobList": ["**.css"]
},
{
"githubId": "bob"
"gitId": "bob"
}
]
}
Expand All @@ -159,10 +159,10 @@ Note: all fields are optional unless specified otherwise.

**Fields to provide _author-level_ info**:<br>
Note: `authors` field should contain _all_ authors that should be captured in the analysis.
* `githubId`: Username of the author. {{ mandatory }} field.
* `gitId`: Username of the author. {{ mandatory }} field.
* `emails`: Associated git emails of the author. For GitHub, this can be found in your [GitHub settings](https://github.com/settings/emails).
* `displayName`: Name to display on the report for this author.
* `authorNames`: Git Author Name(s) used in the author's commits. By default, RepoSense assumes an author would use her GitHub username as the Git username too. The meaning of _Git Author Name_ is explained in [_A note about git author name_](#a-note-about-git-author-name).
* `authorNames`: Git Author Name(s) used in the author's commits. By default, RepoSense assumes an author would use their remote Git Host username as the Git username too. The meaning of _Git Author Name_ is explained in [_A note about git author name_](#a-note-about-git-author-name).
* `ignoreGlobList`: _Additional_ (i.e. on top of the repo-level `ignoreGlobList`) folders/files to ignore for a specific author. The path glob syntax is specified by the [_glob format_](https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob). In the example above, the actual `ignoreGlobList` for `alice` would be `["about-us/**", "**index.html", "**.css"]`.

To verify your standalone configuration is as intended, add the `_reposense/config.json` to your local copy of repo and run RepoSense against it as follows:<br>
Expand Down
4 changes: 2 additions & 2 deletions docs/ug/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@

### Contributions missing in the ramp chart (but appear in the contribution bar and code panel)

This is probably a case of giving an incorrect author name alias (or GitHub ID) in your [author-config file](./configFiles.md#author-config-csv).<br>
This is probably a case of giving an incorrect author name alias (or Git ID) in your [author-config file](./configFiles.md#author-config-csv).<br>
Please refer to [A Note About Git Author Name](./configFiles.md#a-note-about-git-author-name) above on how to find out the correct author name you are using and how to change it.<br>
Also, ensure that you have added all author name aliases you may be using (if you are using multiple computers or have previously changed your author name).<br>
Alternatively, you may choose to configure *RepoSense* to track using your GitHub email instead of in your [standalone config file](./configFiles.md#config-json-standalone-config-file) or [author-config file](./configFiles.md#author-config-csv), which is more accurate compared to author name aliases. The associated GitHub email you are using can be found in your [GitHub settings](https://github.com/settings/emails).
Alternatively, you may choose to configure *RepoSense* to track the email associated with your local Git config or remote Git host email in a [standalone config file](./configFiles.md#config-json-standalone-config-file) or [author-config file](./configFiles.md#author-config-csv), which is more accurate compared to author name aliases. For GitHub, the associated email you are using can be found in your [GitHub settings](https://github.com/settings/emails).


<!-- ------------------------------------------------------------------------------------------------------ -->
Expand Down
6 changes: 3 additions & 3 deletions frontend/cypress/tests/chartView/chartView_zoomFeature.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ describe('range changes in chartview should reflect in zoom', () => {
.get('#summary-charts .summary-chart__ramp .ramp')
.first()
.click(120, 20)
.click(200, 20);
.click(170, 20);

cy.get('#tab-zoom')
.should('be.visible');
Expand All @@ -306,7 +306,7 @@ describe('range changes in chartview should reflect in zoom', () => {
cy.get('body').type(zoomKey, { release: false })
.get('#summary-charts .summary-chart__ramp .ramp')
.first()
.click(200, 20)
.click(170, 20)
.click(250, 20);

cy.get('#tab-zoom')
Expand Down Expand Up @@ -334,7 +334,7 @@ describe('range changes in chartview should reflect in zoom', () => {
cy.get('body').type(zoomKey, { release: false })
.get('#summary-charts .summary-chart__ramp .ramp')
.first()
.click(200, 20)
.click(170, 20)
.click(225, 20);

cy.get('#tab-zoom')
Expand Down
1 change: 1 addition & 0 deletions frontend/src/styles/_z-indices.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ $z-indices: (
'header': 100,
'loader': 10,
'tooltip': 100,
'max-value': 250,
);
1 change: 0 additions & 1 deletion frontend/src/styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ a.broken-link {
}

&.bottom-aligned {
@include medium-font;
bottom: auto;
top: 125%;
}
Expand Down
69 changes: 37 additions & 32 deletions frontend/src/views/c-authorship.vue
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,22 @@
.empty(v-if="info.files.length === 0") nothing to see here :(
template(v-for="(file, i) in selectedFiles", v-bind:key="file.path")
.file(v-bind:ref="file.path")
.title(v-bind:class="{'sticky':\ file.active}")
.title(
v-bind:class="{'sticky':\ file.active}",
v-bind:ref="`${file.path}-title`"
)
span.caret(v-on:click="toggleFileActiveProperty(file)")
.tooltip(
v-show="file.active",
v-on:mouseover="onTooltipHover(`${file.path}-hide-file-tooltip`)",
v-on:mouseout="resetTooltip(`${file.path}-hide-file-tooltip`)"
v-on:mouseover="onTitleTooltipHover(`${file.path}-hide-file-tooltip`, `${file.path}-title`)",
v-on:mouseout="resetTitleTooltip(`${file.path}-hide-file-tooltip`, `${file.path}-title`)"
)
font-awesome-icon(icon="caret-down", fixed-width)
span.tooltip-text(v-bind:ref="`${file.path}-hide-file-tooltip`") Click to hide file details
.tooltip(
v-show="!file.active",
v-on:mouseover="onTooltipHover(`${file.path}-show-file-tooltip`)",
v-on:mouseout="resetTooltip(`${file.path}-show-file-tooltip`)"
v-on:mouseover="onTitleTooltipHover(`${file.path}-show-file-tooltip`, `${file.path}-title`)",
v-on:mouseout="resetTitleTooltip(`${file.path}-show-file-tooltip`, `${file.path}-title`)"
)
font-awesome-icon(icon="caret-right", fixed-width)
span.tooltip-text(v-bind:ref="`${file.path}-show-file-tooltip`") Click to show file details
Expand Down Expand Up @@ -148,18 +151,28 @@
v-bind:class="!isBrokenLink(getHistoryLink(file)) ? '' : 'broken-link'",
v-bind:href="getHistoryLink(file)", target="_blank"
)
.tooltip
.tooltip(
v-on:mouseover="onTitleTooltipHover(`${file.path}-view-history-tooltip`, `${file.path}-title`)",
v-on:mouseout="resetTitleTooltip(`${file.path}-view-history-tooltip`, `${file.path}-title`)"
)
font-awesome-icon.button(icon="history")
span.tooltip-text {{getLinkMessage(getHistoryLink(file), 'Click to view the history view of file')}}
span.tooltip-text(
v-bind:ref="`${file.path}-view-history-tooltip`"
) {{getLinkMessage(getHistoryLink(file), 'Click to view the history view of file')}}
a(
v-if='!file.isBinary',
v-bind:class="!isBrokenLink(getBlameLink(file)) ? '' : 'broken-link'",
v-bind:href="getBlameLink(file)", target="_blank",
title="click to view the blame view of file"
)
.tooltip
.tooltip(
v-on:mouseover="onTitleTooltipHover(`${file.path}-view-blame-tooltip`, `${file.path}-title`)",
v-on:mouseout="resetTitleTooltip(`${file.path}-view-blame-tooltip`, `${file.path}-title`)"
)
font-awesome-icon.button(icon="user-edit")
span.tooltip-text {{getLinkMessage(getBlameLink(file), 'Click to view the blame view of file')}}
span.tooltip-text(
v-bind:ref="`${file.path}-view-blame-tooltip`"
) {{getLinkMessage(getBlameLink(file), 'Click to view the blame view of file')}}
.author-breakdown(v-if="info.isMergeGroup")
.author-breakdown__legend(
v-for="author in getAuthors(file)",
Expand All @@ -186,6 +199,7 @@ import { defineComponent } from 'vue';
import { mapState } from 'vuex';
import minimatch from 'minimatch';
import brokenLinkDisabler from '../mixin/brokenLinkMixin';
import tooltipPositioner from '../mixin/dynamicTooltipMixin';
import cSegmentCollection from '../components/c-segment-collection.vue';
import Segment from '../utils/segment';
import getNonRepeatingColor from '../utils/random-color-generator';
Expand Down Expand Up @@ -229,7 +243,7 @@ export default defineComponent({
components: {
cSegmentCollection,
},
mixins: [brokenLinkDisabler],
mixins: [brokenLinkDisabler, tooltipPositioner],
emits: [
'deactivate-tab',
],
Expand Down Expand Up @@ -488,20 +502,16 @@ export default defineComponent({
}
},
onTooltipHover(refName: string): void {
const tooltipTextElement = (this.$refs[refName] as HTMLElement[])[0];
if (this.isElementAboveViewport(tooltipTextElement)) {
tooltipTextElement.classList.add('bottom-aligned');
}
},
resetTooltip(refName: string): void {
const tooltipTextElement = (this.$refs[refName] as HTMLElement[])[0];
tooltipTextElement.classList.remove('bottom-aligned');
onTitleTooltipHover(tooltipTextElement: string, titleTextElement: string): void {
this.onTooltipHover(tooltipTextElement);
const titleElement = (this.$refs[titleTextElement] as HTMLElement[])[0];
titleElement.classList.add('max-zIndex');
},
isElementAboveViewport(el: Element): boolean {
return el.getBoundingClientRect().top <= 0;
resetTitleTooltip(tooltipTextElement: string, titleTextElement: string): void {
this.resetTooltip(tooltipTextElement);
const titleElement = (this.$refs[titleTextElement] as HTMLElement[])[0];
titleElement.classList.remove('max-zIndex');
},
isUnknownAuthor(name: string): boolean {
Expand All @@ -511,7 +521,6 @@ export default defineComponent({
splitSegments(lines: Line[]): { segments: Segment[]; blankLineCount: number; } {
// split into segments separated by knownAuthor
let lastState: string | null;
let lastCreditState: boolean;
let lastId = -1;
const segments: Segment[] = [];
let blankLineCount = 0;
Expand All @@ -521,19 +530,16 @@ export default defineComponent({
? !this.isUnknownAuthor(line.author.gitId)
: line.author.gitId === this.info.author;
const knownAuthor = (line.author && isAuthorMatched) ? line.author.gitId : null;
const isFullCredit = line.isFullCredit;
if (knownAuthor !== lastState || lastId === -1 || (knownAuthor && isFullCredit !== lastCreditState)) {
if (knownAuthor !== lastState || lastId === -1) {
segments.push(new Segment(
knownAuthor,
isFullCredit,
[],
[],
));
lastId += 1;
lastState = knownAuthor;
lastCreditState = isFullCredit;
}
const content = line.content || ' ';
Expand Down Expand Up @@ -891,6 +897,10 @@ export default defineComponent({
position: sticky;
}
&.max-zIndex {
z-index: z-index('max-value');
}
.caret {
cursor: pointer;
order: -2;
Expand Down Expand Up @@ -993,11 +1003,6 @@ export default defineComponent({
padding-left: 2rem;
word-break: break-word;
}
&.isNotFullCredit {
.code {
background-color: mui-color('green', '100');
}
}
&.untouched {
$grey: mui-color('grey', '400');
border-left: .25rem solid $grey;
Expand Down
19 changes: 13 additions & 6 deletions src/main/java/reposense/model/Author.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ public class Author {
public static final String NAME_NO_AUTHOR_WITH_COMMITS_FOUND =
"NO AUTHOR WITH COMMITS FOUND WITHIN THIS PERIOD OF TIME";
private static final String UNKNOWN_AUTHOR_GIT_ID = "-";

private static final String STANDARD_GITHUB_EMAIL_DOMAIN = "@users.noreply.github.com";
private static final String STANDARD_GITLAB_EMAIL_DOMAIN = "@users.noreply.gitlab.com";

private static final String MESSAGE_UNCOMMON_EMAIL_PATTERN = "The provided email, %s, uses uncommon pattern.";
private static final String MESSAGE_UNCOMMON_GLOB_PATTERN = "The provided ignore glob, %s, uses uncommon pattern.";
private static final String COMMON_EMAIL_REGEX =
Expand All @@ -37,14 +40,14 @@ public Author(String gitId) {
this.authorAliases = new ArrayList<>();
this.ignoreGlobList = new ArrayList<>();

addStandardGitHubEmail(this.emails);
addStandardGitHostEmails(this.emails);
updateIgnoreGlobMatcher();
}

public Author(StandaloneAuthor sa) {
String gitId = sa.getGithubId();
String gitId = sa.getGitId();
List<String> emails = new ArrayList<>(sa.getEmails());
String displayName = !sa.getDisplayName().isEmpty() ? sa.getDisplayName() : sa.getGithubId();
String displayName = !sa.getDisplayName().isEmpty() ? sa.getDisplayName() : sa.getGitId();
List<String> authorAliases = sa.getAuthorNames();
List<String> ignoreGlobList = sa.getIgnoreGlobList();

Expand Down Expand Up @@ -102,7 +105,7 @@ public List<String> getEmails() {
public void setEmails(List<String> emails) {
validateEmails(emails);
this.emails = new ArrayList<>(emails);
addStandardGitHubEmail(this.emails);
addStandardGitHostEmails(this.emails);
}

public String getDisplayName() {
Expand Down Expand Up @@ -188,13 +191,17 @@ private void updateIgnoreGlobMatcher() {
}

/**
* Adds the standard github email to {@code emails} if doesn't exist.
* Adds the standard github and gitlab emails to {@code emails} if not present.
*/
private void addStandardGitHubEmail(List<String> emails) {
private void addStandardGitHostEmails(List<String> emails) {
String standardGitHubEmail = getGitId() + STANDARD_GITHUB_EMAIL_DOMAIN;
String standardGitLabEmail = getGitId() + STANDARD_GITLAB_EMAIL_DOMAIN;
if (!emails.contains(standardGitHubEmail)) {
emails.add(standardGitHubEmail);
}
if (!emails.contains(standardGitLabEmail)) {
emails.add(standardGitLabEmail);
}
}
}

2 changes: 1 addition & 1 deletion src/main/java/reposense/model/AuthorConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public List<Author> getAuthorList() {
* and display name.
*/
private void setAuthorDetails(Author author) {
// Set GitHub Id and its corresponding email as default
// Set Git Id and its corresponding email as default
addAuthorNamesToAuthorMapEntry(author, author.getGitId());
addAuthorNamesToAuthorMapEntry(author, author.getAuthorAliases());

Expand Down
Loading

0 comments on commit 950c912

Please sign in to comment.