aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorPhilippe Perrin <philippe.perrin@sonarsource.com>2020-09-07 13:00:06 +0200
committersonartech <sonartech@sonarsource.com>2020-09-18 20:07:15 +0000
commit1b7e5b30a5695d613d5c2f5942985f52ac76100e (patch)
treef2275816d944de63a0f93ee156b687cdf3744635 /server/sonar-web/src
parentc43b97e2d8f15f03472ee001503a2a13fda6e8c1 (diff)
downloadsonarqube-1b7e5b30a5695d613d5c2f5942985f52ac76100e.tar.gz
sonarqube-1b7e5b30a5695d613d5c2f5942985f52ac76100e.zip
SONAR-13689 Add issue tracker url to languages embedded documentation page
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/App.tsx92
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx20
-rw-r--r--server/sonar-web/src/main/js/types/plugins.ts1
3 files changed, 68 insertions, 45 deletions
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx
index 3ad204c15a2..dab74273954 100644
--- a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx
@@ -35,7 +35,7 @@ import ScreenPositionHelper from '../../../components/common/ScreenPositionHelpe
import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock';
import { ParsedContent, separateFrontMatter } from '../../../helpers/markdown';
import { isSonarCloud } from '../../../helpers/system';
-import { PluginType } from '../../../types/plugins';
+import { InstalledPlugin, PluginType } from '../../../types/plugins';
import { getUrlsList } from '../navTreeUtils';
import getPages from '../pages';
import '../styles.css';
@@ -97,49 +97,55 @@ export default class App extends React.PureComponent<Props, State> {
removeSideBarClass();
}
- getLanguagePluginsDocumentation = (tree: DocNavigationItem[]) => {
- return getInstalledPlugins(PluginType.Bundled)
- .then(plugins =>
- Promise.all(
- plugins.map(plugin => {
- if (plugin.documentationPath) {
- const matchArray = /^static\/(.*)/.exec(plugin.documentationPath);
-
- if (matchArray && matchArray.length > 1) {
- // eslint-disable-next-line promise/no-nesting
- return getPluginStaticFileContent(plugin.key, matchArray[1]).then(
- content => content,
- () => undefined
- );
- }
- }
- return undefined;
- })
- )
- )
- .then(contents => contents.filter(isDefined))
- .then(contents => {
- const regex = new RegExp(`/${LANGUAGES_BASE_URL}/\\w+/$`);
- const overridablePaths = getUrlsList(tree).filter(
- path => regex.test(path) && path !== `/${LANGUAGES_BASE_URL}/overview/`
- );
-
- const parsedContent: T.Dict<ParsedContent> = {};
-
- contents.forEach(content => {
- const parsed = separateFrontMatter(content);
- if (
- parsed &&
- parsed.frontmatter &&
- parsed.frontmatter.key &&
- overridablePaths.includes(`/${LANGUAGES_BASE_URL}/${parsed.frontmatter.key}/`)
- ) {
- parsedContent[`${LANGUAGES_BASE_URL}/${parsed.frontmatter.key}`] = parsed;
+ getLanguagePluginsDocumentation = async (tree: DocNavigationItem[]) => {
+ const plugins = await getInstalledPlugins(PluginType.Bundled).catch(
+ () => [] as InstalledPlugin[]
+ );
+
+ const pluginsWithDoc = await Promise.all(
+ plugins.map(plugin => {
+ if (plugin.documentationPath) {
+ const matchArray = /^static\/(.*)/.exec(plugin.documentationPath);
+
+ if (matchArray && matchArray.length > 1) {
+ return getPluginStaticFileContent(plugin.key, matchArray[1]).then(
+ content => ({ ...plugin, content }),
+ () => undefined
+ );
}
- });
+ }
+
+ return undefined;
+ })
+ );
+
+ const regex = new RegExp(`/${LANGUAGES_BASE_URL}/\\w+/$`);
+ const overridablePaths = getUrlsList(tree).filter(
+ path => regex.test(path) && path !== `/${LANGUAGES_BASE_URL}/overview/`
+ );
+
+ const parsedContent: T.Dict<ParsedContent> = {};
+
+ pluginsWithDoc.filter(isDefined).forEach(plugin => {
+ const parsed = separateFrontMatter(plugin.content);
+
+ if (plugin.issueTrackerUrl) {
+ // Inject issue tracker link
+ let issueTrackerLink = '## Issue Tracker';
+ issueTrackerLink += '\r\n';
+ issueTrackerLink += `Check the [issue tracker](${plugin.issueTrackerUrl}) for this language.`;
+ parsed.content = `${parsed.content}\r\n${issueTrackerLink}`;
+ }
+
+ if (
+ parsed?.frontmatter?.key &&
+ overridablePaths.includes(`/${LANGUAGES_BASE_URL}/${parsed.frontmatter.key}/`)
+ ) {
+ parsedContent[`${LANGUAGES_BASE_URL}/${parsed.frontmatter.key}`] = parsed;
+ }
+ });
- return parsedContent;
- });
+ return parsedContent;
};
render() {
@@ -154,7 +160,7 @@ export default class App extends React.PureComponent<Props, State> {
);
}
- const page = pages.find(p => p.url === '/' + splat);
+ const page = pages.find(p => p.url === `/${splat}`);
const mainTitle = translate(
'documentation.page_title',
isSonarCloud() ? 'sonarcloud' : 'sonarqube'
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
index 2c34d10119a..ea416cd08ca 100644
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
@@ -23,6 +23,7 @@ import { addSideBarClass, removeSideBarClass } from 'sonar-ui-common/helpers/pag
import { request } from 'sonar-ui-common/helpers/request';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { isSonarCloud } from '../../../../helpers/system';
+import { InstalledPlugin } from '../../../../types/plugins';
import getPages from '../../pages';
import App from '../App';
@@ -108,10 +109,14 @@ jest.mock('../../pages', () => {
jest.mock('../../../../api/plugins', () => ({
getInstalledPlugins: jest.fn().mockResolvedValue([
- { key: 'csharp', documentationPath: 'static/documentation.md' },
+ {
+ key: 'csharp',
+ documentationPath: 'static/documentation.md',
+ issueTrackerUrl: 'csharp_plugin_issue_tracker_url'
+ },
{ key: 'vbnet', documentationPath: 'Sstatic/documentation.md' },
{ key: 'vbnett', documentationPath: undefined }
- ])
+ ] as InstalledPlugin[])
}));
beforeEach(() => {
@@ -160,6 +165,17 @@ it('should try to fetch language plugin documentation if documentationPath match
);
});
+it('should display the issue tracker url of the plugin if it exists', async () => {
+ (isSonarCloud as jest.Mock).mockReturnValue(false);
+
+ const wrapper = shallowRender({ params: { splat: 'analysis/languages/csharp/' } });
+ await waitAndUpdate(wrapper);
+
+ const { content } = (getPages as jest.Mock).mock.calls[0][0]['analysis/languages/csharp'];
+
+ expect(content).toContain('csharp_plugin_issue_tracker_url');
+});
+
function shallowRender(props: Partial<App['props']> = {}) {
return shallow(<App params={{ splat: 'lorem/ipsum' }} {...props} />);
}
diff --git a/server/sonar-web/src/main/js/types/plugins.ts b/server/sonar-web/src/main/js/types/plugins.ts
index 27a5ce4d37c..648b792103a 100644
--- a/server/sonar-web/src/main/js/types/plugins.ts
+++ b/server/sonar-web/src/main/js/types/plugins.ts
@@ -50,6 +50,7 @@ export interface PendingPlugin extends Plugin {
export interface InstalledPlugin extends PendingPlugin {
documentationPath?: string;
+ issueTrackerUrl?: string;
filename: string;
hash: string;
sonarLintSupported: boolean;