Skip to content

Commit

Permalink
[#2170] Add Blurbs for Repos (#2191)
Browse files Browse the repository at this point in the history
Currently, there are no ways for student developers to append messages
for each of the repositories they would like to showcase using
RepoSense.

Let's move to implement a blurbs feature to allow individual student
developers to showcase their contributions to their project.
  • Loading branch information
georgetayqy authored May 12, 2024
1 parent 20526f4 commit f4cad78
Show file tree
Hide file tree
Showing 41 changed files with 1,300 additions and 18 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dependencies {
implementation group: 'org.apache.ant', name: 'ant', version: '1.10.12'
implementation group: 'org.apache.commons', name: 'commons-csv', version: '1.9.0'
implementation group: 'org.fusesource.jansi', name: 'jansi', version: '2.4.0'
implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.17.0'

testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: jUnitVersion
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion
Expand Down
2 changes: 2 additions & 0 deletions config/blurbs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
https://github.com/reposense/testrepo-Alpha/tree/master
Master branch of testrepo-Alpha
5 changes: 5 additions & 0 deletions docs/ug/blurbs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
https://github.com/reposense/RepoSense/tree/cypress
Cypress branch of RepoSense
<!--repo-->------------------------------------
https://github.com/reposense/publish-RepoSense/tree/master
Publishing branch of RepoSense
2 changes: 1 addition & 1 deletion docs/ug/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ partial credit.
<div id="section-config">

**`--config CONFIG_DIRECTORY`**: Specifies that config files located in `CONFIG_DIRECTORY` should be used to customize the report.
* Parameter: `CONFIG_DIRECTORY` The directory containing the config files. Should contain a `repo-config.csv` file. Optionally, can contain an `author-config.csv` file or/and a `group-config.csv` file or/and a `report-config.json` file.
* Parameter: `CONFIG_DIRECTORY` The directory containing the config files. Should contain a `repo-config.csv` file. Optionally, can contain an `author-config.csv` file or/and a `group-config.csv` file or/and a `report-config.json` file or/and a `blurbs.md` file.
* Alias: `-c`
* Example: `java -jar RepoSense.jar --config ./config`

Expand Down
14 changes: 14 additions & 0 deletions docs/ug/configFiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,17 @@ Note: Symbols such as `"`, `!`, `/` etc. in your author name will be omitted, wh
</box>

</div>

<!-- ==================================================================================================== -->

<div id="section-blurbs">

## `blurbs.md`

You can optionally use `blurbs.md` to add blurbs in Markdown syntax for repository branches. These blurbs will be seen when grouping by `Repo/Branch`. ([example](https://github.com/reposense/RepoSense/blob/master/docs/ug/blurbs.md))

**Format**:
* First line in section: Link to the repository branch.
* Second line onwards: Blurb content.
* Delimiter: `<!--repo-->`. Everything on the line after the delimiter will be ignored.
</div>
10 changes: 9 additions & 1 deletion docs/ug/customizingReports.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ In both instances, it is **necessary to commit any changes** for them to be dete

<!-- ------------------------------------------------------------------------------------------------------ -->

### Add a title
### Personalizing Reports

#### Add a title
A title component can be added by creating a file titled `title.md` in the assets directory. You can specify the assets directory according to the reference below:
{{ embed("Appendix: **CLI syntax reference → `assets` flag**", "cli.md#section-assets") }}

Expand All @@ -73,3 +74,10 @@ The title can render a combination of Markdown/HTML and plaintext ([example](htt
Do note that the width of the title is bound by the width of the left panel.

For more information on how to use Markdown, see the [Markdown Guide](https://www.markdownguide.org/).

#### Add blurbs for branches
A blurb can be added for a repository branch by creating a file titled `blurbs.md` in the config directory. The blurbs will be visible when grouping by `Repo/Branch`. The format of the file is given below:
{{ embed("Appendix: **Config files format**", "configFiles.md#section-blurbs") }}

Specifying the config directory can be done as follows:
{{ embed("Appendix: **CLI syntax reference → `config` flag**", "cli.md#section-config") }}
11 changes: 11 additions & 0 deletions frontend/cypress/config/blurbs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
https://github.com/reposense/RepoSense/tree/cypress
first blurb
<!--repo-->------------------------------------
https://gitlab.com/reposense/testrepo-gitlab/-/tree/main
unseen blurb
<!--repo-->------------------------------------
https://github.com/reposense/publish-RepoSense/tree/master
## third blurb in h2 markdown tag
<!--repo-->------------------------------------
https://github.com/reposense/RepoSense-auth-helper/tree/master
<h1>second blurb in h1 tag</h1>
34 changes: 34 additions & 0 deletions frontend/cypress/tests/chartView/chartView_blurbs.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
describe('blurbs', () => {
it('shows blurbs', () => {
cy.get('.markdown.blurb')
.first()
.should('contain', 'first blurb');

cy.get('.markdown.blurb')
.eq(1)
.should('contain', 'second blurb');

cy.get('.markdown.blurb')
.eq(2)
.should('contain', 'third blurb');
});

it('has the correct number of valid blurbs', () => {
cy.get('.markdown.blurb')
.should('have.length', 3);
});

it('processes markdown in blurbs', () => {
cy.get('.markdown.blurb')
.eq(1)
.find('h1')
.contains('second blurb in h1 tag');
});

it('processes html in blurbs', () => {
cy.get('.markdown.blurb')
.eq(2)
.find('h2')
.contains('third blurb in h2 markdown tag');
});
});
2 changes: 2 additions & 0 deletions frontend/src/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ const app = defineComponent({
reportGenerationTime,
errorMessages,
names,
blurbMap,
} = summary;
this.creationDate = creationDate;
this.reportGenerationTime = reportGenerationTime;
Expand All @@ -134,6 +135,7 @@ const app = defineComponent({
this.getUsers();
this.renderTabHash();
this.userUpdated = true;
this.$store.commit('setBlurbMap', blurbMap);
} catch (error) {
window.alert(error);
} finally {
Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/c-markdown-chunk.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template lang="pug">
.markdown(v-html="parsedHtml", v-if="markdownText != ''")
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import MarkdownIt from 'markdown-it';
export default defineComponent({
props: {
markdownText: {
type: String,
required: true,
},
},
computed: {
parsedHtml() {
const md = new MarkdownIt({ html: true });
return md.render(this.markdownText);
},
},
});
</script>

<style lang="scss" scoped>
.markdown {
overflow-x: auto;
padding: 0 1.5rem;
}
</style>
44 changes: 42 additions & 2 deletions frontend/src/components/c-summary-charts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@
)
font-awesome-icon.icon-button(icon="clipboard")
span.tooltip-text(v-bind:ref="`summary-charts-${i}-copy-iframe`") Click to copy iframe link for group

.tooltip.summary-chart__title--percentile(
v-if="sortGroupSelection.includes('totalCommits')"
v-if="sortGroupSelection.includes('totalCommits')"
) {{ getPercentile(i) }} %&nbsp
span.tooltip-text.right-aligned {{ getPercentileExplanation(i) }}
.summary-charts__title--tags(
Expand All @@ -158,6 +157,14 @@
)
font-awesome-icon(icon="tags")
span &nbsp;{{ tag }}

.blurbWrapper(
v-if="filterGroupSelection === 'groupByRepos'",
)
c-markdown-chunk.blurb(
v-bind:markdown-text="getBlurb(repo[0])"
)

.summary-charts__fileType--breakdown(v-if="filterBreakdown")
template(v-if="filterGroupSelection !== 'groupByNone'")
.summary-charts__fileType--breakdown__legend(
Expand Down Expand Up @@ -337,6 +344,7 @@ import brokenLinkDisabler from '../mixin/brokenLinkMixin';
import tooltipPositioner from '../mixin/dynamicTooltipMixin';
import cRamp from './c-ramp.vue';
import cStackedBarChart from './c-stacked-bar-chart.vue';
import cMarkdownChunk from './c-markdown-chunk.vue';
import { Bar, Repo, User } from '../types/types';
import { FilterGroupSelection, FilterTimeFrame, SortGroupSelection } from '../types/summary';
import { StoreState, ZoomInfo } from '../types/vuex.d';
Expand All @@ -347,6 +355,7 @@ export default defineComponent({
components: {
cRamp,
cStackedBarChart,
cMarkdownChunk,
},
mixins: [brokenLinkDisabler, tooltipPositioner],
props: {
Expand Down Expand Up @@ -984,10 +993,41 @@ export default defineComponent({
return [...new Set(repo.flatMap((r) => r.commits).flatMap((c) => c.commitResults).flatMap((r) => r.tags))]
.filter(Boolean) as Array<string>;
},
getBlurb(repo: User): string {
const link = this.getRepoLink(repo);
if (!link) {
return '';
}
const blurb: string | undefined = this.$store.state.blurbMap[link];
if (!blurb) {
return '';
}
return blurb;
},
},
});
</script>

<style lang="scss" scoped>
@import '../styles/tags.scss';
@import '../styles/_colors.scss';
.blurbWrapper {
padding-bottom: 5px;
.blurb {
background-color: #F6F8FA;
border-color: #E9EBEF;
border-radius: 4px;
border-style: solid;
border-width: 1px;
overflow-y: hidden;
// This is needed because the inline style of normalize.css adds bottom margins to all p tags, including the
// ones in the blurb.
padding-top: 10px;
// This is needed because the parent summary-wrapper center aligns everything
text-align: initial;
}
}
</style>
4 changes: 4 additions & 0 deletions frontend/src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default createStore<StoreState>({
loadingOverlayCount: 0,
loadingOverlayMessage: '',
isTabActive: true,
blurbMap: {},
} as StoreState,
mutations: {
updateTabZoomInfo(state: StoreState, info: ZoomInfo) {
Expand Down Expand Up @@ -82,6 +83,9 @@ export default createStore<StoreState>({
file.wasCodeLoaded = file.wasCodeLoaded || file.active;
});
},
setBlurbMap(state: StoreState, blurbMap: { [key: string]: string }) {
state.blurbMap = blurbMap;
},
},
actions: {
// Actions are called with dispatch
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/vuex.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface StoreState {
loadingOverlayCount: number;
loadingOverlayMessage: string;
isTabActive: boolean;
blurbMap: { [key: string]: string };
}

declare module '@vue/runtime-core' {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface Api {
reportGenerationTime: string;
errorMessages: { [key: string]: ErrorMessage };
names: string[];
blurbMap: { [key: string]: string };
} | null>;
loadCommits: (repoName: string) => Promise<User[]>;
loadAuthorship: (repoName: string) => Promise<AuthorshipSchema>;
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/types/zod/summary-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export const summarySchema = z.object({
isUntilDateProvided: z.boolean(),
isAuthorshipAnalyzed: z.boolean().default(false), // for backwards compatability
supportedDomainUrlMap: supportedDomainUrlMapSchema,
blurbs: z.object({
urlBlurbMap: z.record(z.string(), z.string()),
}),
});

// Export typescript types
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,14 @@ window.api = {
window.REPOS[repoName] = repo;
names.push(repoName);
});

const blurbMap: { [key: string]: string } = data.blurbs.urlBlurbMap;
return {
creationDate: reportGeneratedTime,
reportGenerationTime,
errorMessages,
names,
blurbMap,
};
},

Expand Down
10 changes: 9 additions & 1 deletion src/main/java/reposense/RepoSense.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@

import net.sourceforge.argparse4j.helper.HelpScreenException;
import reposense.git.GitConfig;
import reposense.model.BlurbMap;
import reposense.model.CliArguments;
import reposense.model.RepoConfiguration;
import reposense.model.ReportConfiguration;
import reposense.model.RunConfigurationDecider;
import reposense.parser.ArgsParser;
import reposense.parser.exceptions.InvalidCsvException;
import reposense.parser.exceptions.InvalidHeaderException;
import reposense.parser.exceptions.InvalidMarkdownException;
import reposense.parser.exceptions.ParseException;
import reposense.report.ReportGenerator;
import reposense.system.LogsManager;
Expand All @@ -43,6 +45,7 @@ public static void main(String[] args) {
CliArguments cliArguments = ArgsParser.parse(args);
List<RepoConfiguration> configs = null;
ReportConfiguration reportConfig = new ReportConfiguration();
BlurbMap blurbMap = new BlurbMap();

if (cliArguments.isViewModeOnly()) {
ReportServer.startServer(SERVER_PORT_NUMBER, cliArguments.getReportDirectoryPath().toAbsolutePath());
Expand All @@ -51,6 +54,7 @@ public static void main(String[] args) {

configs = RunConfigurationDecider.getRunConfiguration(cliArguments).getRepoConfigurations();
reportConfig = cliArguments.getReportConfiguration();
blurbMap = cliArguments.getBlurbMap();

RepoConfiguration.setFormatsToRepoConfigs(configs, cliArguments.getFormats());
RepoConfiguration.setDatesToRepoConfigs(configs, cliArguments.getSinceDate(), cliArguments.getUntilDate());
Expand Down Expand Up @@ -80,7 +84,9 @@ public static void main(String[] args) {
cliArguments.isSinceDateProvided(), cliArguments.isUntilDateProvided(),
cliArguments.getNumCloningThreads(), cliArguments.getNumAnalysisThreads(),
TimeUtil::getElapsedTime, cliArguments.getZoneId(), cliArguments.isFreshClonePerformed(),
cliArguments.isAuthorshipAnalyzed(), cliArguments.getOriginalityThreshold());
cliArguments.isAuthorshipAnalyzed(), cliArguments.getOriginalityThreshold(),
blurbMap
);

FileUtil.zipFoldersAndFiles(reportFoldersAndFiles, cliArguments.getOutputFilePath().toAbsolutePath(),
".json");
Expand All @@ -97,6 +103,8 @@ public static void main(String[] args) {
logger.log(Level.WARNING, e.getMessage(), e);
} catch (HelpScreenException e) {
// help message was printed by the ArgumentParser; it is safe to exit.
} catch (InvalidMarkdownException ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}

LogsManager.moveLogFileToOutputFolder();
Expand Down
Loading

0 comments on commit f4cad78

Please sign in to comment.