Skip to content

Commit

Permalink
feat(readme): ✨ adds partial support for GLFM
Browse files Browse the repository at this point in the history
  • Loading branch information
JWWilks committed Jul 12, 2024
1 parent 8504089 commit bfce13b
Show file tree
Hide file tree
Showing 11 changed files with 1,098 additions and 28 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "es5"
"trailingComma": "es5",
"endOfLine": "auto"
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
- View Contributors for a project
- View Languages used for a project
- View Pipeline status for a project
- View README for a project
- View README for a project (with partial support for GLFM)
- Works for both project and personal tokens
- Pagination for builds
- Pagination for Merge Requests
Expand Down
43 changes: 27 additions & 16 deletions packages/gitlab/dev/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
import React from 'react';
import { createDevApp } from '@backstage/dev-utils';
import { EntityProvider } from '@backstage/plugin-catalog-react';
import { gitlabPlugin, EntityGitlabContent } from '../src/plugin';
import {
gitlabPlugin,
EntityGitlabContent,
EntityGitlabReadmeCard,
} from '../src/plugin';
import { GitlabCIApiRef, GitlabCIClient } from '../src/api';
import { mockedGitlabReqToRes, projectId } from './mock-gitlab/api-v4-v15.7.0';
import { configApiRef, discoveryApiRef } from '@backstage/core-plugin-api';
import { GraphQLQuery } from '../src/api/GitlabCIApi';

const devEntity = {
metadata: {
annotations: {
'gitlab.com/project-id': `${projectId}`,
'gitlab.com/codeowners-path': `CODEOWNERS`,
'gitlab.com/readme-path': `README.md`,
},
name: 'backstage',
},
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
};

createDevApp()
.registerPlugin(gitlabPlugin)
.registerApi({
Expand Down Expand Up @@ -60,25 +77,19 @@ createDevApp()
})
.addPage({
element: (
<EntityProvider
entity={{
metadata: {
annotations: {
'gitlab.com/project-id': `${projectId}`,
'gitlab.com/codeowners-path': `CODEOWNERS`,
'gitlab.com/readme-path': `README.md`,
},
name: 'backstage',
},
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
}}
>
{' '}
<EntityProvider entity={devEntity}>
<EntityGitlabContent />
</EntityProvider>
),
title: 'Root Page',
path: '/backstage-plugin-gitlab',
})
.addPage({
element: (
<EntityProvider entity={devEntity}>
<EntityGitlabReadmeCard />
</EntityProvider>
),
title: 'Readme Card',
})
.render();
4 changes: 3 additions & 1 deletion packages/gitlab/dev/mock-gitlab/api-v4-v15.7.0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6429,7 +6429,9 @@ rust-toolchain @xMAC94x
[![lines of code](https://tokei.rs/b1/gitlab/veloren/veloren)](https://tokei.rs/b1/gitlab/veloren/veloren)
[![contributor count](https://img.shields.io/github/contributors/veloren/veloren)](https://gitlab.com/veloren/veloren/-/graphs/master)
## Welcome to Veloren!
[TOC]
## Welcome to Veloren! :smile:
Veloren is a multiplayer voxel RPG written in Rust. It is inspired by games such as Cube World, The Legend of Zelda: Breath of the Wild, Dwarf Fortress and Minecraft. The game is in active development and enjoys a flourishing player community.
Expand Down
1 change: 1 addition & 0 deletions packages/gitlab/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'remark-remove-comments'; // Module has no type declarations
5 changes: 5 additions & 0 deletions packages/gitlab/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
"@material-ui/lab": "4.0.0-alpha.61",
"@mui/x-charts": "^6.0.0-alpha.7",
"dayjs": "^1.11.10",
"react-markdown": "^9.0.1",
"react-use": "^17.4.0",
"remark-gemoji": "^8.0.0",
"remark-gfm": "^4.0.0",
"remark-remove-comments": "^1.0.1",
"remark-toc": "^9.0.0",
"semver": "^7.5.4"
},
"peerDependencies": {
Expand Down
14 changes: 14 additions & 0 deletions packages/gitlab/src/components/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,17 @@ const parseCodeOwnerLine = (rule: string): FileOwnership => {
// ensures that only the following patterns are allowed @octocat @octocat/kitty docs@example.com
const codeOwnerRegex =
/(^@[a-zA-Z0-9_\-/]*$)|(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;

// Remark does not fully support GLFM, but remark-toc can generate a TOC, but it requires a # heading, whereas GLFM does not.
export const parseGitLabReadme = (readme: string): string => {
const lines = readme.split('\n');

const modifiedLines = lines.map((line) => {
if (/^\[TOC\]|\[\[_TOC_\]\]$/.test(line.trim())) {
return `## <!-- injected_toc -->`; // remark-toc turns this into a TOC but keeps the heading, then remark-remove-comments makes the heading invisible
}
return line;
});

return modifiedLines.join('\n');
};
62 changes: 57 additions & 5 deletions packages/gitlab/src/components/widgets/ReadmeCard/ReadmeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import ReactMarkdown from 'react-markdown';
import Alert from '@material-ui/lab/Alert';
import {
InfoCard,
Progress,
MarkdownContent,
InfoCardVariants,
} from '@backstage/core-components';
import { GitlabCIApiRef } from '../../../api';
Expand All @@ -16,6 +16,12 @@ import {
gitlabReadmePath,
gitlabInstance,
} from '../../gitlabAppData';
import gfm from 'remark-gfm';
import toc from 'remark-toc';
import removeComments from 'remark-remove-comments';

import gemoji from 'remark-gemoji';
import { parseGitLabReadme } from '../../utils';

const useStyles = makeStyles((theme) => ({
infoCard: {
Expand All @@ -24,10 +30,47 @@ const useStyles = makeStyles((theme) => ({
marginTop: theme.spacing(3),
},
},
// https://github.com/backstage/backstage/blob/master/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx#L28
markdown: {
'& table': {
borderCollapse: 'collapse',
border: `1px solid ${theme.palette.border}`,
},
'& th, & td': {
border: `1px solid ${theme.palette.border}`,
padding: theme.spacing(1),
},
'& td': {
wordBreak: 'break-word',
overflow: 'hidden',
verticalAlign: 'middle',
lineHeight: '1',
margin: 0,
padding: theme.spacing(3, 2, 3, 2.5),
borderBottom: 0,
},
'& th': {
backgroundColor: theme.palette.background.paper,
},
'& tr': {
backgroundColor: theme.palette.background.paper,
},
'& tr:nth-child(odd)': {
backgroundColor: theme.palette.background.default,
},

'& a': {
color: theme.palette.link,
},
'& img': {
maxWidth: '100%',
},
},
}));

type Props = {
variant?: InfoCardVariants;
markdownClasses?: string;
};

export const ReadmeCard = (props: Props) => {
Expand Down Expand Up @@ -61,8 +104,9 @@ export const ReadmeCard = (props: Props) => {
} catch (error) {
readmeData = undefined;
}

return {
readme: readmeData,
readme: readmeData ? parseGitLabReadme(readmeData) : undefined,
};
}, []);

Expand All @@ -82,9 +126,17 @@ export const ReadmeCard = (props: Props) => {
className={classes.infoCard}
variant={props.variant}
>
<MarkdownContent
content={value?.readme || 'No README found'}
dialect="gfm"
<ReactMarkdown
className={`${classes.markdown} ${
props.markdownClasses ?? ''
}`.trim()}
remarkPlugins={[
gfm,
gemoji,
[toc, { heading: '<!-- injected_toc -->' }], // tells remark-toc to look for toc injected by parseGitLabReadme
removeComments, // removes HTML comments, including the one we injected
]}
children={value?.readme ?? 'No README found'}
/>
</InfoCard>
);
Expand Down
20 changes: 19 additions & 1 deletion packages/gitlab/src/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { gitlabPlugin } from './plugin';
import { parseCodeOwners } from './components/utils';
import { parseCodeOwners, parseGitLabReadme } from './components/utils';

const CODEOWNERS = `
# Lines starting with '#' are comments.
Expand All @@ -20,6 +20,12 @@ const CODEOWNERS = `
const CODEOWNERS2 = `# Specify a default Code Owner by using a wildcard:
* @amusolino`;

const README = `## TOC
[TOC]
[[_TOC_]]
## Heading 1
[[_TOC_]] `;

describe('gitlabPlugin', () => {
it('should export plugin', () => {
expect(gitlabPlugin).toBeDefined();
Expand Down Expand Up @@ -49,4 +55,16 @@ describe('gitlabPlugin', () => {
},
]);
});

it('parseGitLabReadme converts GLFM TOC into a header', async () => {
expect(parseGitLabReadme(README)).toEqual(
[
`## TOC`,
`## <!-- injected_toc -->`,
`## <!-- injected_toc -->`,
`## Heading 1`,
`## <!-- injected_toc -->`,
].join('\n')
);
});
});
2 changes: 1 addition & 1 deletion packages/gitlab/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": "@backstage/cli/config/tsconfig.json",
"include": ["src"],
"include": ["src", "index.d.ts"],
"exclude": ["node_modules"],
"compilerOptions": {
"outDir": "dist-types",
Expand Down
Loading

0 comments on commit bfce13b

Please sign in to comment.