]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11608 Conditional formatting broken when used within a table
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Fri, 4 Jan 2019 15:46:00 +0000 (16:46 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Jan 2019 08:42:17 +0000 (09:42 +0100)
server/sonar-docs/gatsby-config.js
server/sonar-docs/plugins/sonarsource-source-filesystem/gatsby-node.js [new file with mode: 0644]
server/sonar-docs/plugins/sonarsource-source-filesystem/index.js [new file with mode: 0644]
server/sonar-docs/plugins/sonarsource-source-filesystem/package.json [new file with mode: 0644]
server/sonar-docs/src/templates/page.js
server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx
server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/markdown-test.ts
server/sonar-web/src/main/js/helpers/markdown.js

index fc20659d2d7e89eb9cc1bb8001160283549bf49f..843b36e36832b8e060f22131899330be69e416c3 100644 (file)
@@ -26,7 +26,7 @@ module.exports = {
   },
   plugins: [
     {
-      resolve: 'gatsby-source-filesystem',
+      resolve: `sonarsource-source-filesystem`,
       options: { name: 'src', path: `${__dirname}/src/` }
     },
     'gatsby-plugin-react-helmet',
diff --git a/server/sonar-docs/plugins/sonarsource-source-filesystem/gatsby-node.js b/server/sonar-docs/plugins/sonarsource-source-filesystem/gatsby-node.js
new file mode 100644 (file)
index 0000000..0fd7c88
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const { sourceNodes, setFieldsOnGraphQLNodeType } = require('gatsby-source-filesystem/gatsby-node');
+
+exports.sourceNodes = sourceNodes;
+exports.setFieldsOnGraphQLNodeType = setFieldsOnGraphQLNodeType;
diff --git a/server/sonar-docs/plugins/sonarsource-source-filesystem/index.js b/server/sonar-docs/plugins/sonarsource-source-filesystem/index.js
new file mode 100644 (file)
index 0000000..4ed6bec
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const { createFilePath, createRemoteFileNode } = require('gatsby-source-filesystem');
+const fs = require('fs-extra');
+
+function loadNodeContent(fileNode) {
+  const content = fs.readFileSync(fileNode.absolutePath, 'utf-8');
+  return new Promise((resolve, reject) => {
+    let newContent = cutSonarCloudContent(content);
+    newContent = removeRemainingContentTags(newContent);
+    resolve(newContent);
+  });
+}
+
+function removeRemainingContentTags(content) {
+  const regexBase = '<!-- \\/?(sonarqube|sonarcloud|static) -->';
+  return content
+    .replace(new RegExp(`^${regexBase}(\n|\r|\r\n|$)`, 'gm'), '') // First, remove single-line ones, including ending carriage-returns.
+    .replace(new RegExp(`${regexBase}`, 'g'), ''); // Now remove all remaining ones.
+}
+
+function cutSonarCloudContent(content) {
+  const beginning = '<!-- sonarcloud -->';
+  const ending = '<!-- /sonarcloud -->';
+
+  let newContent = content;
+  let start = newContent.indexOf(beginning);
+  let end = newContent.indexOf(ending);
+  while (start !== -1 && end !== -1) {
+    newContent = newContent.substring(0, start) + newContent.substring(end + ending.length);
+    start = newContent.indexOf(beginning);
+    end = newContent.indexOf(ending);
+  }
+
+  return newContent;
+}
+
+exports.createFilePath = createFilePath;
+exports.createRemoteFileNode = createRemoteFileNode;
+exports.loadNodeContent = loadNodeContent;
diff --git a/server/sonar-docs/plugins/sonarsource-source-filesystem/package.json b/server/sonar-docs/plugins/sonarsource-source-filesystem/package.json
new file mode 100644 (file)
index 0000000..03199f7
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "name": "sonarsource-source-filesystem",
+  "version": "1.0.0",
+  "description": "",
+  "main": "create-file-node.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC"
+}
index 164ff5909ac2cc317f87a48c2990371339a2dd71..d627cd7a3380abe813793c414cb1fe9abcab2509 100644 (file)
@@ -46,15 +46,13 @@ export default class Page extends React.PureComponent {
 
   render() {
     const page = this.props.data.markdownRemark;
-    let htmlWithInclusions = cutSonarCloudContent(page.html).replace(
-      /<p>@include (.*)<\/p>/,
-      (_, path) => {
-        const chunk = data.allMarkdownRemark.edges.find(edge => edge.node.fields.slug === path);
-        return chunk ? chunk.node.html : '';
-      }
-    );
+    let htmlWithInclusions = page.html.replace(/<p>@include (.*)<\/p>/, (_, path) => {
+      const chunk = data.allMarkdownRemark.edges.find(edge => edge.node.fields.slug === path);
+      return chunk ? chunk.node.html : '';
+    });
 
     const realHeadingsList = removeExtraHeadings(page.html, page.headings);
+
     htmlWithInclusions = removeTableOfContents(htmlWithInclusions);
     htmlWithInclusions = createAnchorForHeadings(htmlWithInclusions, realHeadingsList);
     htmlWithInclusions = replaceDynamicLinks(htmlWithInclusions);
@@ -190,19 +188,3 @@ function createAnchorForHeadings(content, headings) {
 function removeTableOfContents(content) {
   return content.replace(/<h[1-9]>Table Of Contents<\/h[1-9]>/i, '');
 }
-
-function cutSonarCloudContent(content) {
-  const beginning = '<!-- sonarcloud -->';
-  const ending = '<!-- /sonarcloud -->';
-
-  let newContent = content;
-  let start = newContent.indexOf(beginning);
-  let end = newContent.indexOf(ending);
-  while (start !== -1 && end !== -1) {
-    newContent = newContent.substring(0, start) + newContent.substring(end + ending.length);
-    start = newContent.indexOf(beginning);
-    end = newContent.indexOf(ending);
-  }
-
-  return newContent;
-}
index b7574befa1c5611db121b28ac16d7a36e150cb68..afacbd5ec0af2e1fbb75eddd182f50abeb8e5f77 100644 (file)
@@ -20,7 +20,6 @@
 import * as React from 'react';
 import { shallow } from 'enzyme';
 import DocMarkdownBlock from '../DocMarkdownBlock';
-import { isSonarCloud } from '../../../helpers/system';
 
 const CONTENT_WITH_TOC = `
 ## Table of Contents
@@ -75,37 +74,6 @@ it('should use custom component for links', () => {
   ).toMatchSnapshot();
 });
 
-it('should cut sonarqube/sonarcloud/static content', () => {
-  const content = `
-some
-
-<!-- sonarqube -->
-sonarqube
-<!-- /sonarqube -->
-
-<!-- sonarcloud -->
-sonarcloud
-<!-- /sonarcloud -->
-
-<!-- static -->
-static
-<!-- /static -->
-
-<!-- sonarqube -->
-  long
-
-  multiline
-<!-- /sonarqube -->
-
-text`;
-
-  (isSonarCloud as jest.Mock).mockImplementation(() => false);
-  expect(shallowRender({ content })).toMatchSnapshot();
-
-  (isSonarCloud as jest.Mock).mockImplementation(() => true);
-  expect(shallowRender({ content })).toMatchSnapshot();
-});
-
 it('should render with custom props for links', () => {
   expect(
     shallowRender({
index 90d7b35cab40c29d5bb8bb070643d1cecfac9e48..ae537c7f71291b5cbbc0091528a4beedd7193c3f 100644 (file)
@@ -1,87 +1,5 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`should cut sonarqube/sonarcloud/static content 1`] = `
-<div
-  className="markdown"
->
-  <div
-    className="markdown-content"
-  >
-    <Block
-      key="h-1"
-    >
-      <p
-        key="h-2"
-      >
-        some
-      </p>
-      
-
-      <p
-        key="h-3"
-      >
-        sonarqube
-      </p>
-      
-
-      <p
-        key="h-4"
-      >
-          long
-      </p>
-      
-
-      <p
-        key="h-5"
-      >
-          multiline
-      </p>
-      
-
-      <p
-        key="h-6"
-      >
-        text
-      </p>
-    </Block>
-  </div>
-</div>
-`;
-
-exports[`should cut sonarqube/sonarcloud/static content 2`] = `
-<div
-  className="markdown"
->
-  <div
-    className="markdown-content"
-  >
-    <Block
-      key="h-1"
-    >
-      <p
-        key="h-2"
-      >
-        some
-      </p>
-      
-
-      <p
-        key="h-3"
-      >
-        sonarcloud
-      </p>
-      
-
-      <p
-        key="h-4"
-      >
-        text
-      </p>
-    </Block>
-  </div>
-</div>
-`;
-
 exports[`should render a TOC if available 1`] = `
 <div
   className="markdown"
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap
new file mode 100644 (file)
index 0000000..4d075b2
--- /dev/null
@@ -0,0 +1,57 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should cut sonarqube/sonarcloud/static content 1`] = `
+"
+This text has inline text for SonarQube. Donec sed nulla magna.
+
+This is text for SonarQube, multi-line. Consectetur adipiscing elit. Duis dignissim nulla at massa iaculis interdum.
+Aenean sit amet lacus a tortor ullamcorper interdum. Donec sed nulla magna.
+
+
+
+
+
+This is text for SonarQube, single line.
+
+* In hac habitasse
+* Duis sagittis semper sapien nec tempor
+* This is a bullet point for SonarQube
+
+* Platea dictumst
+
+Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam.
+
+| Parameter Name        | Description |
+| --------------------- | ------------------ |
+| sonar.pullrequest.github.repository | SLUG of the GitHub Repo |
+| sonar.pullrequest.github.endpoint | The API url for your GitHub instance. |
+"
+`;
+
+exports[`should cut sonarqube/sonarcloud/static content 2`] = `
+"
+This text has inline text for SonarCloud. Donec sed nulla magna.
+
+
+
+This is text for SonarCloud, multi-line. In hac habitasse platea dictumst. Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam. Mauris volutpat nunc non fermentum rhoncus. Aenean laoreet, orci vitae tempor bibendum,
+metus nisl euismod neque, vitae euismod nibh nisl eu velit. Vivamus luctus suscipit elit vel semper.
+
+
+
+
+
+* In hac habitasse
+* Duis sagittis semper sapien nec tempor
+
+* This is a bullet point for SonarCloud
+* Platea dictumst
+
+Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam.
+
+| Parameter Name        | Description |
+| --------------------- | ------------------ |
+| sonar.pullrequest.github.repository | SLUG of the GitHub Repo |
+
+"
+`;
index b2b2a1c0b645ba55675e299b227ee1697a724d2a..b292f321cf38b29050d153ca7a1bd69bb4af4bd0 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { getFrontMatter, separateFrontMatter, filterContent } from '../markdown';
+import { isSonarCloud } from '../system';
 
 jest.mock('../system', () => ({
   getInstance: () => 'SonarQube',
-  isSonarCloud: () => false
+  isSonarCloud: jest.fn().mockReturnValue(false)
 }));
 
 it('returns parsed frontmatter of one item', () => {
@@ -116,3 +117,47 @@ it('replaces {instance}', () => {
     filterContent('This is {instance} content. It replaces all {instance}{instance} messages')
   ).toBe('This is SonarQube content. It replaces all SonarQubeSonarQube messages');
 });
+
+it('should cut sonarqube/sonarcloud/static content', () => {
+  const content = `
+This text has inline text for <!-- sonarqube -->SonarQube<!-- /sonarqube --><!-- sonarcloud -->SonarCloud<!-- /sonarcloud -->. Donec sed nulla magna.
+
+<!-- sonarqube -->
+This is text for SonarQube, multi-line. Consectetur adipiscing elit. Duis dignissim nulla at massa iaculis interdum.
+Aenean sit amet lacus a tortor ullamcorper interdum. Donec sed nulla magna.
+<!-- /sonarqube -->
+
+<!-- sonarcloud -->
+This is text for SonarCloud, multi-line. In hac habitasse platea dictumst. Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam. Mauris volutpat nunc non fermentum rhoncus. Aenean laoreet, orci vitae tempor bibendum,
+metus nisl euismod neque, vitae euismod nibh nisl eu velit. Vivamus luctus suscipit elit vel semper.
+<!-- /sonarcloud -->
+
+<!-- static -->
+This is static text.
+<!-- /static -->
+
+<!-- sonarqube -->
+This is text for SonarQube, single line.
+<!-- /sonarqube -->
+
+* In hac habitasse
+* Duis sagittis semper sapien nec tempor
+<!-- sonarqube -->* This is a bullet point for SonarQube<!-- /sonarqube -->
+<!-- sonarcloud -->* This is a bullet point for SonarCloud<!-- /sonarcloud -->
+* Platea dictumst
+
+Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam.
+
+| Parameter Name        | Description |
+| --------------------- | ------------------ |
+| sonar.pullrequest.github.repository | SLUG of the GitHub Repo |
+<!-- sonarqube -->
+| sonar.pullrequest.github.endpoint | The API url for your GitHub instance. |
+<!-- /sonarqube -->
+`;
+
+  expect(filterContent(content)).toMatchSnapshot();
+
+  (isSonarCloud as jest.Mock).mockReturnValueOnce(true);
+  expect(filterContent(content)).toMatchSnapshot();
+});
index b92c05e04dd96eddc1c86658395961ccde5cd218..1b7f29c25bf73e5b82ee5acb5931568655106c9c 100644 (file)
@@ -71,12 +71,16 @@ function parseFrontMatter(lines) {
  * @returns {string}
  */
 function filterContent(content) {
+  const regexBase = '<!-- \\/?(sonarqube|sonarcloud|static) -->';
   const { isSonarCloud, getInstance } = require('./system');
   const contentWithInstance = content.replace(/{instance}/gi, getInstance());
   const contentWithoutStatic = cutConditionalContent(contentWithInstance, 'static');
-  return isSonarCloud()
+  const filteredContent = isSonarCloud()
     ? cutConditionalContent(contentWithoutStatic, 'sonarqube')
     : cutConditionalContent(contentWithoutStatic, 'sonarcloud');
+  return filteredContent
+    .replace(new RegExp(`^${regexBase}(\n|\r|\r\n|$)`, 'gm'), '') // First, remove single-line ones, including ending carriage-returns.
+    .replace(new RegExp(`${regexBase}`, 'g'), ''); // Now remove all remaining ones.
 }
 
 /**