aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-docs/src
diff options
context:
space:
mode:
authorPascal Mugnier <pascal.mugnier@sonarsource.com>2018-09-19 14:03:27 +0200
committerSonarTech <sonartech@sonarsource.com>2018-09-19 20:20:55 +0200
commit7d7bfd09c1bdbe753899265ef15212b0e4682c32 (patch)
tree6dbd3525482056ae8375a730bb2be26e5eda8485 /server/sonar-docs/src
parent4f5e9d9f87a37dc04fa147667afee85743cab643 (diff)
downloadsonarqube-7d7bfd09c1bdbe753899265ef15212b0e4682c32.tar.gz
sonarqube-7d7bfd09c1bdbe753899265ef15212b0e4682c32.zip
MMF-1420 Ease management of Embedded Docs navigation (#699)
Diffstat (limited to 'server/sonar-docs/src')
-rw-r--r--server/sonar-docs/src/EmbedDocsSuggestions.json58
-rw-r--r--server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js178
-rw-r--r--server/sonar-docs/src/layouts/components/CategoryLink.js84
-rw-r--r--server/sonar-docs/src/layouts/components/ExternalLink.js34
-rw-r--r--server/sonar-docs/src/layouts/components/Footer.js8
-rw-r--r--server/sonar-docs/src/layouts/components/HeadingAnchor.js35
-rw-r--r--server/sonar-docs/src/layouts/components/HeadingsLink.js30
-rw-r--r--server/sonar-docs/src/layouts/components/Search.js25
-rw-r--r--server/sonar-docs/src/layouts/components/SearchEntryResult.js2
-rw-r--r--server/sonar-docs/src/layouts/components/Sidebar.js101
-rw-r--r--server/sonar-docs/src/layouts/components/icons/DetachIcon.js32
-rw-r--r--server/sonar-docs/src/layouts/index.js11
-rw-r--r--server/sonar-docs/src/layouts/utils.js30
-rw-r--r--server/sonar-docs/src/pages/404.md8
-rw-r--r--server/sonar-docs/src/pages/analysis/background-tasks.md1
-rw-r--r--server/sonar-docs/src/pages/analysis/generic-issue.md (renamed from server/sonar-docs/src/pages/analysis/generic_issue.md)4
-rw-r--r--server/sonar-docs/src/pages/analysis/generic-test.md (renamed from server/sonar-docs/src/pages/analysis/generic_test.md)1
-rw-r--r--server/sonar-docs/src/pages/analysis/overview.md (renamed from server/sonar-docs/src/pages/analysis/index.md)3
-rw-r--r--server/sonar-docs/src/pages/analysis/pull-request.md3
-rw-r--r--server/sonar-docs/src/pages/analysis/scm-integration.md (renamed from server/sonar-docs/src/pages/analysis/scm_integration.md)3
-rw-r--r--server/sonar-docs/src/pages/branches/branches-faq.md38
-rw-r--r--server/sonar-docs/src/pages/branches/long-lived-branches.md1
-rw-r--r--server/sonar-docs/src/pages/branches/overview.md (renamed from server/sonar-docs/src/pages/branches/index.md)13
-rw-r--r--server/sonar-docs/src/pages/branches/short-lived-branches.md1
-rw-r--r--server/sonar-docs/src/pages/index.md15
-rw-r--r--server/sonar-docs/src/pages/instance-administration/custom-measures.md (renamed from server/sonar-docs/src/pages/custom-measures.md)2
-rw-r--r--server/sonar-docs/src/pages/instance-administration/housekeeping.md (renamed from server/sonar-docs/src/pages/housekeeping.md)1
-rw-r--r--server/sonar-docs/src/pages/instance-administration/look-and-feel.md (renamed from server/sonar-docs/src/pages/look-and-feel.md)2
-rw-r--r--server/sonar-docs/src/pages/instance-administration/quality-profiles.md (renamed from server/sonar-docs/src/pages/quality-profiles.md)1
-rw-r--r--server/sonar-docs/src/pages/integrations/index.md10
-rw-r--r--server/sonar-docs/src/pages/project-administration/webhooks.md (renamed from server/sonar-docs/src/pages/webhooks.md)1
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/analyze-a-project.md (renamed from server/sonar-docs/src/pages/analyze-a-project.md)12
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/integrations/bitbucketcloud.md (renamed from server/sonar-docs/src/pages/integrations/bitbucketcloud.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/integrations/github.md (renamed from server/sonar-docs/src/pages/integrations/github.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/integrations/vsts.md (renamed from server/sonar-docs/src/pages/integrations/vsts.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/organizations/index.md (renamed from server/sonar-docs/src/pages/organizations/index.md)8
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/organizations/manage-team.md (renamed from server/sonar-docs/src/pages/organizations/manage-team.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/organizations/organization-visibility.md (renamed from server/sonar-docs/src/pages/organizations/organization-visibility.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/privacy.md (renamed from server/sonar-docs/src/pages/privacy.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/security.md (renamed from server/sonar-docs/src/pages/security.md)2
-rw-r--r--server/sonar-docs/src/pages/sonarcloud/sonarcloud-pricing.md (renamed from server/sonar-docs/src/pages/sonarcloud-pricing.md)2
-rw-r--r--server/sonar-docs/src/pages/user-guide/fixing-the-water-leak.md (renamed from server/sonar-docs/src/pages/fixing-the-water-leak.md)7
-rw-r--r--server/sonar-docs/src/pages/user-guide/keyboard-shortcuts.md (renamed from server/sonar-docs/src/pages/keyboard-shortcuts.md)2
-rw-r--r--server/sonar-docs/src/pages/user-guide/metric-definitions.md (renamed from server/sonar-docs/src/pages/metric-definitions.md)1
-rw-r--r--server/sonar-docs/src/pages/user-guide/quality-gates.md (renamed from server/sonar-docs/src/pages/quality-gates.md)3
-rw-r--r--server/sonar-docs/src/pages/user-guide/security-reports.md (renamed from server/sonar-docs/src/pages/security-reports.md)1
-rw-r--r--server/sonar-docs/src/pages/user-guide/user-account.md (renamed from server/sonar-docs/src/pages/user-account.md)7
-rw-r--r--server/sonar-docs/src/templates/page.js13
48 files changed, 588 insertions, 218 deletions
diff --git a/server/sonar-docs/src/EmbedDocsSuggestions.json b/server/sonar-docs/src/EmbedDocsSuggestions.json
index 996ecb4c49b..45beba34d09 100644
--- a/server/sonar-docs/src/EmbedDocsSuggestions.json
+++ b/server/sonar-docs/src/EmbedDocsSuggestions.json
@@ -3,152 +3,152 @@
"api_documentation": [],
"background_tasks": [
{
- "link": "/documentation/analysis/background-tasks",
+ "link": "/documentation/analysis/background-tasks/",
"text": "About Background Tasks"
}
],
"code": [],
"coding_rules": [
{
- "link": "/documentation/quality-profiles",
+ "link": "/documentation/quality-profiles/",
"text": "Quality Profiles"
},
{
- "link": "/documentation/keyboard-shortcuts",
+ "link": "/documentation/keyboard-shortcuts/",
"text": "Keyboard Shortcuts"
}
],
"component_measures": [
{
- "link": "/documentation/fixing-the-water-leak",
+ "link": "/documentation/fixing-the-water-leak/",
"text": "Fixing the Water Leak"
},
{
- "link":"/documentation/metric-definitions",
- "text":"Metric Definitions"
+ "link": "/documentation/metric-definitions/",
+ "text": "Metric Definitions"
},
{
- "link": "/documentation/keyboard-shortcuts",
+ "link": "/documentation/keyboard-shortcuts/",
"text": "Keyboard Shortcuts"
}
],
"custom_measures": [
{
- "link": "/documentation/custom-measures",
+ "link": "/documentation/custom-measures/",
"text": "About Custom Measures"
}
],
"custom_metrics": [
{
- "link": "/documentation/custom-measures",
+ "link": "/documentation/custom-measures/",
"text": "Custom Measures"
}
],
"extension_billing": [
{
- "link": "/documentation/sonarcloud-pricing",
+ "link": "/documentation/sonarcloud-pricing/",
"text": "Pricing",
"scope": "sonarcloud"
}
],
"global_permissions": [
{
- "link": "/documentation/organizations/manage-team",
+ "link": "/documentation/organizations/manage-team/",
"text": "Manage a Team",
"scope": "sonarcloud"
}
],
"issues": [
{
- "link": "/documentation/keyboard-shortcuts",
+ "link": "/documentation/keyboard-shortcuts/",
"text": "Keyboard Shortcuts"
}
],
"marketplace": [],
"organization_members": [
{
- "link": "/documentation/organizations/manage-team",
+ "link": "/documentation/organizations/manage-team/",
"text": "Manage a Team",
"scope": "sonarcloud"
}
],
"organization_projects": [
{
- "link": "/documentation/organizations/manage-team",
+ "link": "/documentation/organizations/manage-team/",
"text": "Manage a Team",
"scope": "sonarcloud"
}
],
"organization_space": [
{
- "link": "/documentation/organizations/index",
+ "link": "/documentation/organizations/index/",
"text": "Organizations",
"scope": "sonarcloud"
}
],
"overview": [
{
- "link": "/documentation/fixing-the-water-leak",
+ "link": "/documentation/fixing-the-water-leak/",
"text": "Fixing the Water Leak"
},
{
- "link": "/documentation/branches/index",
+ "link": "/documentation/branches/index/",
"text": "Branches Overview"
},
{
- "link": "/documentation/analysis/pull-request",
+ "link": "/documentation/analysis/pull-request/",
"text": "Analyzing Pull Requests"
}
],
"permission_templates": [],
- "profiles": [
+ "profiles": [
{
- "link": "/documentation/quality-profiles",
+ "link": "/documentation/quality-profiles/",
"text": "Quality Profiles"
}
],
"project_activity": [],
"project_quality_gate": [
{
- "link": "/documentation/fixing-the-water-leak",
+ "link": "/documentation/fixing-the-water-leak/",
"text": "Fixing the Water Leak"
}
],
"project_quality_profiles": [
{
- "link": "/documentation/quality-profiles",
+ "link": "/documentation/quality-profiles/",
"text": "About Quality Profiles"
}
],
"projects_management": [
{
- "link": "/documentation/analyze-a-project",
+ "link": "/documentation/analyze-a-project/",
"text": "Analyze a Project",
"scope": "sonarcloud"
}
],
"projects": [
{
- "link": "/documentation/analyze-a-project",
+ "link": "/documentation/analyze-a-project/",
"text": "Analyze a Project",
"scope": "sonarcloud"
}
],
"quality_gates": [
{
- "link": "/documentation/fixing-the-water-leak",
+ "link": "/documentation/fixing-the-water-leak/",
"text": "Fixing the Water Leak"
}
],
"quality_profiles": [
{
- "link": "/documentation/quality-profiles",
+ "link": "/documentation/quality-profiles/",
"text": "Quality Profiles"
}
],
"security_reports": [
{
- "link": "/documentation/security-reports",
+ "link": "/documentation/security-reports/",
"text": "About Security Reports"
}
],
@@ -156,7 +156,7 @@
"system_info": [],
"user_groups": [
{
- "link": "/documentation/organizations/manage-team",
+ "link": "/documentation/organizations/manage-team/",
"text": "Manage a Team",
"scope": "sonarcloud"
}
@@ -164,7 +164,7 @@
"users": [],
"webhooks": [
{
- "link": "/documentation/webhooks",
+ "link": "/documentation/webhooks/",
"text": "About Webhooks"
}
]
diff --git a/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js b/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js
new file mode 100644
index 00000000000..5eafbfa7178
--- /dev/null
+++ b/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js
@@ -0,0 +1,178 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 remark = require('remark');
+const fs = require('fs');
+const path = require('path');
+const glob = require('glob-promise');
+const visit = require('unist-util-visit');
+
+it('should not have any broken link', async () => {
+ const root = path.resolve(__dirname + '/..');
+ const files = await glob(root + '/pages/**/*.md')
+ .then(files => files.map(file => file.substr(root.length + 1)))
+ .then(files =>
+ files.map(file => ({
+ path: file.slice(0, -3),
+ content: handleIncludes(fs.readFileSync(root + '/' + file, 'utf8'), root)
+ }))
+ );
+
+ const parsedFiles = files.map(file => {
+ return { ...separateFrontMatter(file.content), path: file.path };
+ });
+
+ const trees = [
+ 'SonarCloudNavigationTree.json',
+ 'SonarQubeNavigationTree.json',
+ 'StaticNavigationTree.json'
+ ];
+ trees.forEach(file => {
+ const tree = JSON.parse(fs.readFileSync(root + '/../static/' + file, 'utf8'));
+ tree.forEach(leaf => {
+ if (typeof leaf === 'object') {
+ if (leaf.children) {
+ leaf.children.forEach(child => {
+ // Check children markdown file path validity
+ const result = urlExists(parsedFiles, child);
+ if (!result) {
+ // Display custom error message
+ console.log('[', child, '] is not a valid link, in ', file);
+ }
+ expect(result).toBeTruthy();
+ });
+ }
+ } else {
+ // Check markdown file path validity
+ const result = urlExists(parsedFiles, leaf);
+ if (!result) {
+ console.log('[', leaf, '] is not a valid link, in ', file);
+ }
+ expect(result).toBeTruthy();
+ }
+ });
+ });
+
+ // Check if all url tag in frontmatter are valid and uniques
+ let urlLists = [];
+ parsedFiles.map(file => {
+ let result = file.frontmatter.url;
+ if (!result) {
+ console.log('[', file.path, '] has no url metadata');
+ }
+ expect(result).toBeTruthy();
+
+ result = file.frontmatter.url.startsWith('/');
+ if (!result) {
+ console.log('[', file.path, '] should starts with a slash ', file.frontmatter.url);
+ }
+ expect(result).toBeTruthy();
+
+ result = file.frontmatter.url.endsWith('/');
+ if (!result) {
+ console.log('[', file.path, '] should ends with a slash ', file.frontmatter.url);
+ }
+ expect(result).toBeTruthy();
+
+ result = !urlLists.includes(file.frontmatter.url);
+ if (!result) {
+ console.log('[', file.path, '] has an url that is not unique ', file.frontmatter.url);
+ }
+ expect(result).toBeTruthy();
+
+ urlLists = [...urlLists, file.frontmatter.url];
+ });
+
+ parsedFiles.map(file => {
+ const ast = remark().parse(file.content);
+ visit(ast, node => {
+ if (node.type === 'image' && !node.url.startsWith('http')) {
+ // Check image path validity
+ const result = fs.existsSync(root + '/' + node.url);
+ if (!result) {
+ console.log('[', node.url, '] is not a valid image path, in ', file.path + '.md');
+ }
+ expect(result).toBeTruthy();
+ } else if (
+ node.type === 'link' &&
+ !node.url.startsWith('http') &&
+ !node.url.startsWith('/#')
+ ) {
+ // Check markdown file path validity
+ const result = urlExists(parsedFiles, node.url);
+ if (!result) {
+ console.log('[', node.url, '] is not a valid link, in ', file.path + '.md');
+ }
+ expect(result).toBeTruthy();
+ }
+ });
+ });
+ expect(true).toBeTruthy();
+});
+
+function urlExists(files, url) {
+ return files.find(f => f.frontmatter.url === url) !== undefined;
+}
+
+function handleIncludes(content, root) {
+ return content.replace(/@include (.+)/, (match, p) => {
+ const filePath = path.join(root, '..', `${p}.md`);
+ return fs.readFileSync(filePath, 'utf8');
+ });
+}
+
+function getFrontMatterPosition(lines) {
+ let firstLine;
+ let lastLine;
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i];
+ if (line.trim() === '---') {
+ if (firstLine === undefined) {
+ firstLine = i;
+ } else {
+ lastLine = i;
+ break;
+ }
+ }
+ }
+ return lastLine !== undefined ? { firstLine, lastLine } : undefined;
+}
+
+function parseFrontMatter(lines) {
+ const data = {};
+ for (let i = 0; i < lines.length; i++) {
+ const tokens = lines[i].split(':').map(x => x.trim());
+ if (tokens.length === 2) {
+ data[tokens[0]] = tokens[1];
+ }
+ }
+ return data;
+}
+
+function separateFrontMatter(content) {
+ const lines = content.split('\n');
+ const position = getFrontMatterPosition(lines);
+ if (position) {
+ const frontmatter = parseFrontMatter(lines.slice(position.firstLine + 1, position.lastLine));
+ const content = lines.slice(position.lastLine + 1).join('\n');
+ return { frontmatter, content };
+ } else {
+ return { frontmatter: {}, content };
+ }
+}
diff --git a/server/sonar-docs/src/layouts/components/CategoryLink.js b/server/sonar-docs/src/layouts/components/CategoryLink.js
index 2cfc743b1ec..12e51b570ae 100644
--- a/server/sonar-docs/src/layouts/components/CategoryLink.js
+++ b/server/sonar-docs/src/layouts/components/CategoryLink.js
@@ -21,39 +21,59 @@ import * as React from 'react';
import Link from 'gatsby-link';
import SubpageLink from './SubpageLink';
import HeadingsLink from './HeadingsLink';
-import { sortNodes } from '../utils';
import ChevronDownIcon from './icons/ChevronDownIcon';
import ChevronUpIcon from './icons/ChevronUpIcon';
-export default function CategoryLink({ node, location, headers, onToggle }) {
- const hasChild = node.pages && node.pages.length > 0;
- const prefix = process.env.GATSBY_USE_PREFIX === '1' ? '/' + process.env.GATSBY_DOCS_VERSION : '';
- const { slug } = node.fields;
- const isCurrentPage = location.pathname === prefix + slug;
- const open = location.pathname.startsWith(prefix + slug);
- return (
- <div>
- <h2 className={isCurrentPage || open ? 'active' : ''}>
- <Link to={slug} title={node.frontmatter.title}>
- {hasChild && open && <ChevronUpIcon />}
- {hasChild && !open && <ChevronDownIcon />}
- {node.frontmatter.title}
- </Link>
- </h2>
- {isCurrentPage && <HeadingsLink headers={headers} />}
- {hasChild &&
- open && (
- <div className="sub-menu">
- {sortNodes(node.pages).map(page => (
- <SubpageLink
- key={page.fields.slug}
- headers={headers}
- displayHeading={location.pathname === prefix + page.fields.slug}
- node={page}
- />
- ))}
- </div>
- )}
- </div>
- );
+export default class CategoryLink extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = { open: props.open };
+ }
+
+ toggle = event => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.props.onToggle(this.props.title);
+ };
+
+ render() {
+ const { node, location, headers, children, title, open } = this.props;
+ const prefix =
+ process.env.GATSBY_USE_PREFIX === '1' ? '/' + process.env.GATSBY_DOCS_VERSION : '';
+ const url = node ? node.frontmatter.url || node.fields.slug : '';
+ const isCurrentPage = location.pathname === prefix + url;
+ return (
+ <div>
+ <h2 className={isCurrentPage || open ? 'active' : ''}>
+ {node ? (
+ <Link to={url} title={node.frontmatter.title}>
+ {node.frontmatter.title}
+ </Link>
+ ) : (
+ <a href="#" onClick={this.toggle}>
+ {open ? <ChevronUpIcon /> : <ChevronDownIcon />}
+ {title}
+ </a>
+ )}
+ </h2>
+ {isCurrentPage && <HeadingsLink headers={headers} />}
+ {children &&
+ open && (
+ <div className="sub-menu">
+ {children.map(page => {
+ const url = page.frontmatter.url || page.fields.slug;
+ return (
+ <SubpageLink
+ displayHeading={location.pathname === prefix + url}
+ headers={headers}
+ key={url}
+ node={page}
+ />
+ );
+ })}
+ </div>
+ )}
+ </div>
+ );
+ }
}
diff --git a/server/sonar-docs/src/layouts/components/ExternalLink.js b/server/sonar-docs/src/layouts/components/ExternalLink.js
new file mode 100644
index 00000000000..516f1d05951
--- /dev/null
+++ b/server/sonar-docs/src/layouts/components/ExternalLink.js
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+import * as React from 'react';
+import DetachIcon from './icons/DetachIcon';
+
+export function ExternalLink({ external, title }) {
+ return (
+ <div>
+ <h2>
+ <a href={external} target="_blank">
+ <DetachIcon />
+ {title}
+ </a>
+ </h2>
+ </div>
+ );
+}
diff --git a/server/sonar-docs/src/layouts/components/Footer.js b/server/sonar-docs/src/layouts/components/Footer.js
index e807022e79b..83e72f5c56f 100644
--- a/server/sonar-docs/src/layouts/components/Footer.js
+++ b/server/sonar-docs/src/layouts/components/Footer.js
@@ -23,10 +23,10 @@ export default function Footer() {
return (
<div className="page-footer">
<a
+ href="https://creativecommons.org/licenses/by-nc/3.0/us/"
rel="noopener noreferrer"
target="_blank"
- title="Creative Commons License"
- href="https://creativecommons.org/licenses/by-nc/3.0/us/">
+ title="Creative Commons License">
<img
alt="Creative Commons License"
src="https://licensebuttons.net/l/by-nc/3.0/us/88x31.png"
@@ -35,9 +35,9 @@ export default function Footer() {
© 2008-2017, SonarSource S.A, Switzerland. Except where otherwise noted, content in this space
is licensed under a{' '}
<a
+ href="https://creativecommons.org/licenses/by-nc/3.0/us/"
rel="noopener noreferrer"
- target="_blank"
- href="https://creativecommons.org/licenses/by-nc/3.0/us/">
+ target="_blank">
Creative Commons Attribution-NonCommercial 3.0 United States License.
</a>{' '}
SONARQUBE is a trademark of SonarSource SA. All other trademarks and copyrights are the
diff --git a/server/sonar-docs/src/layouts/components/HeadingAnchor.js b/server/sonar-docs/src/layouts/components/HeadingAnchor.js
new file mode 100644
index 00000000000..a831007fa0a
--- /dev/null
+++ b/server/sonar-docs/src/layouts/components/HeadingAnchor.js
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+import * as React from 'react';
+
+export default function HeadingAnchor(props) {
+ const onClick = event => {
+ event.stopPropagation();
+ event.preventDefault();
+ props.clickHandler(props.index);
+ };
+ return (
+ <li>
+ <a className={props.active ? 'active' : ''} href={'#header-' + props.index} onClick={onClick}>
+ {props.value}
+ </a>
+ </li>
+ );
+}
diff --git a/server/sonar-docs/src/layouts/components/HeadingsLink.js b/server/sonar-docs/src/layouts/components/HeadingsLink.js
index 6abd72ceee3..a012a04a78f 100644
--- a/server/sonar-docs/src/layouts/components/HeadingsLink.js
+++ b/server/sonar-docs/src/layouts/components/HeadingsLink.js
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import HeadingAnchor from './HeadingAnchor';
export default class HeadingsLink extends React.Component {
skipScrollingHandler = false;
@@ -51,7 +52,7 @@ export default class HeadingsLink extends React.Component {
highlightHeading = scrollTop => {
let headingIndex = 0;
for (let i = 0; i < this.state.headers.length; i++) {
- if (document.querySelector('#header-' + (i + 1)).offsetTop > scrollTop + 40) {
+ if (document.querySelector('#header-' + (i + 1)).offsetTop > scrollTop + 200) {
break;
}
headingIndex = i;
@@ -71,8 +72,8 @@ export default class HeadingsLink extends React.Component {
node.classList.add('targetted-heading');
if (scrollTo) {
this.skipScrollingHandler = true;
- window.scrollTo(0, node.offsetTop - 30);
- this.highlightHeading(node.offsetTop - 30);
+ window.scrollTo(0, node.offsetTop - 200);
+ this.highlightHeading(node.offsetTop - 200);
}
}
};
@@ -87,12 +88,8 @@ export default class HeadingsLink extends React.Component {
this.highlightHeading(scrollTop);
};
- clickHandler = target => {
- return event => {
- event.stopPropagation();
- event.preventDefault();
- this.markH2(target, true);
- };
+ clickHandler = index => {
+ this.markH2(index, true);
};
render() {
@@ -106,14 +103,13 @@ export default class HeadingsLink extends React.Component {
<ul>
{headers.map((header, index) => {
return (
- <li key={index + 1}>
- <a
- onClick={this.clickHandler(index + 1)}
- href={'#header-' + (index + 1)}
- className={this.state.activeIndex === index ? 'active' : ''}>
- {header.value}
- </a>
- </li>
+ <HeadingAnchor
+ active={this.state.activeIndex === index}
+ clickHandler={this.clickHandler}
+ key={index}
+ index={index + 1}
+ value={header.value}
+ />
);
})}
</ul>
diff --git a/server/sonar-docs/src/layouts/components/Search.js b/server/sonar-docs/src/layouts/components/Search.js
index 05b31278f4e..1562ff0484e 100644
--- a/server/sonar-docs/src/layouts/components/Search.js
+++ b/server/sonar-docs/src/layouts/components/Search.js
@@ -18,8 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React, { Component } from 'react';
-import lunr, { LunrIndex } from 'lunr';
+import lunr from 'lunr';
import ClearIcon from './icons/ClearIcon';
+import { getUrlsList } from '../utils';
// Search component
export default class Search extends Component {
@@ -36,13 +37,17 @@ export default class Search extends Component {
this.metadataWhitelist = ['position'];
- props.pages.forEach(page =>
- this.add({
- id: page.id,
- title: page.frontmatter.title,
- text: page.html.replace(/<(?:.|\n)*?>/gm, '').replace(/&#x3C;(?:.|\n)*?>/gm, '')
- })
- );
+ props.pages
+ .filter(page =>
+ getUrlsList(props.navigation).includes(page.frontmatter.url || page.fields.slug)
+ )
+ .forEach(page =>
+ this.add({
+ id: page.id,
+ text: page.html.replace(/<(?:.|\n)*?>/gm, '').replace(/&#x3C;(?:.|\n)*?>/gm, ''),
+ title: page.frontmatter.title
+ })
+ );
});
}
@@ -67,9 +72,9 @@ export default class Search extends Component {
return {
page: {
id: page.id,
- slug: page.fields.slug,
+ text: page.html.replace(/<(?:.|\n)*?>/gm, '').replace(/&#x3C;(?:.|\n)*?>/gm, ''),
title: page.frontmatter.title,
- text: page.html.replace(/<(?:.|\n)*?>/gm, '').replace(/&#x3C;(?:.|\n)*?>/gm, '')
+ url: page.frontmatter.url || page.fields.slug
},
highlights,
longestTerm
diff --git a/server/sonar-docs/src/layouts/components/SearchEntryResult.js b/server/sonar-docs/src/layouts/components/SearchEntryResult.js
index bfd0daba0ca..c1456691674 100644
--- a/server/sonar-docs/src/layouts/components/SearchEntryResult.js
+++ b/server/sonar-docs/src/layouts/components/SearchEntryResult.js
@@ -23,7 +23,7 @@ import { highlightMarks, cutWords } from '../utils';
export default function SearchResultEntry({ active, result }) {
return (
- <Link className={active ? 'active search-result' : 'search-result'} to={result.page.slug}>
+ <Link className={active ? 'active search-result' : 'search-result'} to={result.page.url}>
<SearchResultTitle result={result} />
<SearchResultText result={result} />
</Link>
diff --git a/server/sonar-docs/src/layouts/components/Sidebar.js b/server/sonar-docs/src/layouts/components/Sidebar.js
index a9cf8668d29..e6a7fa1408e 100644
--- a/server/sonar-docs/src/layouts/components/Sidebar.js
+++ b/server/sonar-docs/src/layouts/components/Sidebar.js
@@ -19,20 +19,46 @@
*/
import React from 'react';
import Link from 'gatsby-link';
-import { fromPairs } from 'lodash';
-import { sortNodes } from '../utils';
import CategoryLink from './CategoryLink';
import VersionSelect from './VersionSelect';
import Search from './Search';
import SearchEntryResult from './SearchEntryResult';
+import NavigationTree from '../../../static/StaticNavigationTree.json';
+import { ExternalLink } from './ExternalLink';
export default class Sidebar extends React.PureComponent {
- state = { loaded: false, query: '', results: [], versions: [] };
+ constructor(props) {
+ super(props);
+ this.state = {
+ loaded: false,
+ openBlockTitle: this.getOpenBlockFromLocation(this.props.location),
+ query: '',
+ results: [],
+ versions: []
+ };
+ }
componentDidMount() {
this.loadVersions();
}
+ componentDidUpdate(prevProps) {
+ if (this.props.location.pathname !== prevProps.location.pathname) {
+ this.setState({ openBlockTitle: this.getOpenBlockFromLocation(this.props.location) });
+ }
+ }
+
+ // A block is opened if the current page is set to one of his children
+ getOpenBlockFromLocation({ pathname }) {
+ const element = NavigationTree.find(
+ item =>
+ typeof item === 'object' &&
+ item.children &&
+ item.children.some(child => pathname.endsWith(child))
+ );
+ return element ? element.title : '';
+ }
+
loadVersions() {
fetch('/DocsVersions.json').then(response =>
response.json().then(json => {
@@ -41,21 +67,43 @@ export default class Sidebar extends React.PureComponent {
);
}
- getPagesHierarchy() {
- const categories = sortNodes(
- this.props.pages.filter(p => p.fields.slug.split('/').length === 3)
- );
- const pages = this.props.pages.filter(p => p.fields.slug.split('/').length > 3);
- const categoriesObject = fromPairs(categories.map(c => [c.fields.slug, { ...c, pages: [] }]));
- pages.forEach(page => {
- const parentSlug = page.fields.slug
- .split('/')
- .slice(0, 2)
- .join('/');
- categoriesObject[parentSlug + '/'].pages.push(page);
+ getNodeFromUrl = url => {
+ return this.props.pages.find(p => p.fields.slug === url + '/' || p.frontmatter.url === url);
+ };
+
+ handleToggle = title => {
+ this.setState(state => ({ openBlockTitle: state.openBlockTitle === title ? '' : title }));
+ };
+
+ renderCategories = tree => {
+ return tree.map(item => {
+ if (typeof item === 'object') {
+ if (item.children) {
+ return (
+ <CategoryLink
+ children={item.children.map(child => this.getNodeFromUrl(child))}
+ headers={this.props.headers}
+ key={item.title}
+ location={this.props.location}
+ onToggle={this.handleToggle}
+ open={item.title === this.state.openBlockTitle}
+ title={item.title}
+ />
+ );
+ } else {
+ return <ExternalLink external={item.url} key={item.title} title={item.title} />;
+ }
+ }
+ return (
+ <CategoryLink
+ headers={this.props.headers}
+ key={item}
+ location={this.props.location}
+ node={this.getNodeFromUrl(item)}
+ />
+ );
});
- return categoriesObject;
- }
+ };
renderResults = () => {
return (
@@ -79,7 +127,6 @@ export default class Sidebar extends React.PureComponent {
};
render() {
- const nodes = this.getPagesHierarchy();
const isOnCurrentVersion =
this.state.versions.find(v => v.value === this.props.version) !== undefined;
return (
@@ -89,9 +136,9 @@ export default class Sidebar extends React.PureComponent {
<img
alt="Continuous Code Quality"
css={{ verticalAlign: 'top', margin: 0 }}
- width="160"
src="/images/SonarQubeIcon.svg"
title="Continuous Code Quality"
+ width="160"
/>
</Link>
<VersionSelect
@@ -110,17 +157,13 @@ export default class Sidebar extends React.PureComponent {
)}
</div>
<div className="page-indexes">
- <Search pages={this.props.pages} onResultsChange={this.handleSearch} />
+ <Search
+ navigation={NavigationTree}
+ onResultsChange={this.handleSearch}
+ pages={this.props.pages}
+ />
{this.state.query !== '' && this.renderResults()}
- {this.state.query === '' &&
- Object.keys(nodes).map(key => (
- <CategoryLink
- key={key}
- headers={this.props.headers}
- node={nodes[key]}
- location={this.props.location}
- />
- ))}
+ {this.state.query === '' && this.renderCategories(NavigationTree)}
</div>
</div>
);
diff --git a/server/sonar-docs/src/layouts/components/icons/DetachIcon.js b/server/sonar-docs/src/layouts/components/icons/DetachIcon.js
new file mode 100644
index 00000000000..a48571957a4
--- /dev/null
+++ b/server/sonar-docs/src/layouts/components/icons/DetachIcon.js
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+import * as React from 'react';
+import Icon from './Icon';
+
+export default function DetachIcon({ className, fill = 'currentColor', size }) {
+ return (
+ <Icon className={className} size={size}>
+ <path
+ d="M12 9.25v2.5A2.25 2.25 0 0 1 9.75 14h-6.5A2.25 2.25 0 0 1 1 11.75v-6.5A2.25 2.25 0 0 1 3.25 3h5.5c.14 0 .25.11.25.25v.5c0 .14-.11.25-.25.25h-5.5C2.562 4 2 4.563 2 5.25v6.5c0 .688.563 1.25 1.25 1.25h6.5c.688 0 1.25-.563 1.25-1.25v-2.5c0-.14.11-.25.25-.25h.5c.14 0 .25.11.25.25zm3-6.75v4c0 .273-.227.5-.5.5a.497.497 0 0 1-.352-.148l-1.375-1.375L7.68 10.57a.27.27 0 0 1-.18.078.27.27 0 0 1-.18-.078l-.89-.89a.27.27 0 0 1-.078-.18.27.27 0 0 1 .078-.18l5.093-5.093-1.375-1.375A.497.497 0 0 1 10 2.5c0-.273.227-.5.5-.5h4c.273 0 .5.227.5.5z"
+ style={{ fill }}
+ />
+ </Icon>
+ );
+}
diff --git a/server/sonar-docs/src/layouts/index.js b/server/sonar-docs/src/layouts/index.js
index 2fc755141ce..824955d0ae5 100644
--- a/server/sonar-docs/src/layouts/index.js
+++ b/server/sonar-docs/src/layouts/index.js
@@ -38,13 +38,7 @@ export default function Layout(props) {
location={props.location}
pages={props.data.allMarkdownRemark.edges
.map(e => e.node)
- .filter(n => !n.fields.slug.startsWith('/tooltips'))
- .filter(
- n =>
- !n.frontmatter.scope ||
- n.frontmatter.scope === 'sonarqube' ||
- n.frontmatter.scope === 'static'
- )}
+ .filter(n => !n.fields.slug.startsWith('/tooltips'))}
searchIndex={props.data.siteSearchIndex}
version={version}
/>
@@ -95,8 +89,7 @@ export const query = graphql`
}
frontmatter {
title
- order
- scope
+ url
}
fields {
slug
diff --git a/server/sonar-docs/src/layouts/utils.js b/server/sonar-docs/src/layouts/utils.js
index 9fdae25b2fd..40c2c59da23 100644
--- a/server/sonar-docs/src/layouts/utils.js
+++ b/server/sonar-docs/src/layouts/utils.js
@@ -1,12 +1,26 @@
-import { sortBy } from 'lodash';
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+import { sortBy, flatten } from 'lodash';
-export function sortNodes(nodes) {
- return nodes.sort((a, b) => {
- if (a.frontmatter.order) {
- return b.frontmatter.order ? a.frontmatter.order - b.frontmatter.order : 1;
- }
- return a.frontmatter.title < b.frontmatter.title ? -1 : 1;
- });
+export function getUrlsList(navigation) {
+ return flatten(navigation.map(item => item.children || [item]));
}
const WORDS = 6;
diff --git a/server/sonar-docs/src/pages/404.md b/server/sonar-docs/src/pages/404.md
new file mode 100644
index 00000000000..d6a0f85fd7e
--- /dev/null
+++ b/server/sonar-docs/src/pages/404.md
@@ -0,0 +1,8 @@
+---
+title: Page not found
+url: /404/
+---
+
+# Error
+
+This page does not exist
diff --git a/server/sonar-docs/src/pages/analysis/background-tasks.md b/server/sonar-docs/src/pages/analysis/background-tasks.md
index 62157db41da..c12fcfde131 100644
--- a/server/sonar-docs/src/pages/analysis/background-tasks.md
+++ b/server/sonar-docs/src/pages/analysis/background-tasks.md
@@ -1,5 +1,6 @@
---
title: Background Tasks
+url: /analysis/background-tasks/
---
A Background Task can be:
diff --git a/server/sonar-docs/src/pages/analysis/generic_issue.md b/server/sonar-docs/src/pages/analysis/generic-issue.md
index 33c3ff456f6..27ef5577131 100644
--- a/server/sonar-docs/src/pages/analysis/generic_issue.md
+++ b/server/sonar-docs/src/pages/analysis/generic-issue.md
@@ -1,5 +1,6 @@
---
title: Generic Issue Data
+url: /analysis/generic-issue/
---
SonarQube supports a generic import format for raising "external" issues in code. It is intended to allow you to import the issues from your favorite linter even if no plugin exists for it.
@@ -11,7 +12,7 @@ External issues suffer from two important limitations:
External issues and the rules that raise them must be managed in the configuration of your linter.
-## Import
+## Import
The analysis parameter `sonar.externalIssuesReportPaths` accepts a comma-delimited list of paths to reports.
Each report must contain, at top-level, an array of `Issue` objects named `issues`.
@@ -39,6 +40,7 @@ Each report must contain, at top-level, an array of `Issue` objects named `issue
* `startColumn` - integer, optional. 0-indexed
* `endColumn` - integer, optional. 0-indexed
+## Example
Here is an example of the expected format:
{ "issues": [
diff --git a/server/sonar-docs/src/pages/analysis/generic_test.md b/server/sonar-docs/src/pages/analysis/generic-test.md
index 47a5850076e..d7fa694f7d9 100644
--- a/server/sonar-docs/src/pages/analysis/generic_test.md
+++ b/server/sonar-docs/src/pages/analysis/generic-test.md
@@ -1,5 +1,6 @@
---
title: Generic Test Data
+url: /analysis/generic-test/
---
Out of the box, SonarQube supports generic formats for test coverage and test execution import. If your coverage engines' native output formats aren't supported by your language plugins, simply covert them to these formats.
diff --git a/server/sonar-docs/src/pages/analysis/index.md b/server/sonar-docs/src/pages/analysis/overview.md
index e6603fe0a8c..1dc4166abed 100644
--- a/server/sonar-docs/src/pages/analysis/index.md
+++ b/server/sonar-docs/src/pages/analysis/overview.md
@@ -1,5 +1,6 @@
---
-title: Analyzing Source Code
+title: Overview
+url: /analysis/overview/
---
Once the SonarQube platform has been installed, you're ready to install an analyzer and begin creating projects. To do that, you must install and configure the scanner that is most appropriate for your needs. Do you build with:
diff --git a/server/sonar-docs/src/pages/analysis/pull-request.md b/server/sonar-docs/src/pages/analysis/pull-request.md
index 497b5ffb830..4e17d90c01d 100644
--- a/server/sonar-docs/src/pages/analysis/pull-request.md
+++ b/server/sonar-docs/src/pages/analysis/pull-request.md
@@ -1,5 +1,6 @@
---
title: Pull Request Analysis
+url: /analysis/pull-request/
---
<!-- sonarqube -->
@@ -24,7 +25,7 @@ PR analyses on SonarQube are deleted automatically after 30 days with no analysi
<!-- sonarcloud -->
## Integrations for GitHub, Bitbucket Cloud and VSTS
-If your repositories are hosted on GitHub, Bitbucket Cloud or VSTS, check out first the dedicated ["Integrations" pages](/integrations/index). Chances are that you do not need to read this page further since those integrations handle the configuration and analysis parameters for you.
+If your repositories are hosted on GitHub, Bitbucket Cloud or VSTS, check out first the dedicated Integrations for: [BitBucketCloud](/integrations/bitbucketcloud/), [GitHub](/integrations/github/), and [VSTS](/integrations/vsts/). Chances are that you do not need to read this page further since those integrations handle the configuration and analysis parameters for you.
<!-- /sonarcloud -->
## Analysis Parameters
diff --git a/server/sonar-docs/src/pages/analysis/scm_integration.md b/server/sonar-docs/src/pages/analysis/scm-integration.md
index 8771b78b2f1..78a498f9c81 100644
--- a/server/sonar-docs/src/pages/analysis/scm_integration.md
+++ b/server/sonar-docs/src/pages/analysis/scm-integration.md
@@ -1,12 +1,13 @@
---
title: SCM Integration
+url: /analysis/scm-integration/
---
Collecting SCM data during code analysis can unlock a number of SonarQube features:
* Automatic Issue Assignment
* code annotation (blame data) in the Code Viewer
-* SCM-driven detection of new code (to help with [Fixing the Water Leak](/fixing-the-water-leak)). Without SCM data, SonarQube determines new code using analysis dates (to timestamp modification of lines).
+* SCM-driven detection of new code (to help with [Fixing the Water Leak](/user-guide/fixing-the-water-leak/)). Without SCM data, SonarQube determines new code using analysis dates (to timestamp modification of lines).
### Turning it on/off
SCM integration requires support for your individual SCM provider. Git and SVN are supported by default. <!-- sonarqube -->For other SCM providers, see the Marketplace.<!-- /sonarqube -->
diff --git a/server/sonar-docs/src/pages/branches/branches-faq.md b/server/sonar-docs/src/pages/branches/branches-faq.md
index e5925192786..304db0a2fdd 100644
--- a/server/sonar-docs/src/pages/branches/branches-faq.md
+++ b/server/sonar-docs/src/pages/branches/branches-faq.md
@@ -1,6 +1,6 @@
---
title: Frequently Asked Branches Questions
-order: 99
+url: /branches/branches-faq/
---
<!-- sonarqube -->
@@ -10,32 +10,32 @@ _Branch analysis is available as part of [Developer Edition](https://redirect.so
<!-- /sonarqube -->
-**Q:** How long are branches retained?
-**A:** Long-lived branches are retained until you delete them manually (**Administration > Branches**).
+## How long are branches retained?
+Long-lived branches are retained until you delete them manually (**Administration > Branches**).
Short-lived branches are deleted automatically after 30 days with no analysis.
This can be updated in **Configuration > General > Number of days before purging inactive short living branches**.
-**Q:** Do I need to have my project stored in an SCM such as Git or SVN to use this feature?
-**A:** No, you don't need to be connected to a SCM. But if you use Git or SVN we can better track the new files on short-lived branches and so better report new issues on the files that really changed during the life of the short-lived branch.
+## Does my project need to be stored in an SCM like Git or SVN?
+No, you don't need to be connected to a SCM. But if you use Git or SVN we can better track the new files on short-lived branches and so better report new issues on the files that really changed during the life of the short-lived branch.
-**Q:** If I flag an Issue as "Won't Fix" or "False-Positive", will it be replicated as such when merging my short-lived branch into the Master?
-**A:** Yes. Each time there is an analysis of a long-lived branch, we look at the issues on the short-lived branches and try to synchronize them with the newly raised issues on the long-lived branch. In case you made some changes on the issues (false-positive, won't fix), these changes will be reported on the long-lived branch.
+## What if I mark an Issue "Won't Fix" or "False-Positive" in a branch?
+It be replicated as such when merging my short-lived branch into the Master. Each time there is an analysis of a long-lived branch, we look at the issues on the short-lived branches and try to synchronize them with the newly raised issues on the long-lived branch. In case you made some changes on the issues (false-positive, won't fix), these changes will be reported on the long-lived branch.
-**Q:** Can I still use `sonar.branch`?
-**A:** `sonar.branch` is deprecated. You can still use it but it will behave the same way it always has: a separate project will be created. We encourage you to smoothly migrate your users to the new parameter `sonar.branch.name`.
+## Can I still use 'sonar.branch'?
+`sonar.branch` is deprecated. You can still use it but it will behave the same way it always has: a separate project will be created. We encourage you to smoothly migrate your users to the new parameter `sonar.branch.name`.
Please note you cannot use `sonar.branch` together with `sonar.branch.name`.
-**Q:** Can I manually delete a branch?
-**A:** This can be achieved by going into the Administration menu at Project's level, then Branches.
+## Can I manually delete a branch?
+This can be achieved by going into the Administration menu at Project's level, then Branches.
-**Q:** How do I control the lifespan of a short-lived branch?
-**A:** As a global admin, you can set the parameter sonar.dbcleaner.daysBeforeDeletingInactiveShortLivingBranches to control how many days you want to keep an inactive short-lived branch.
+## How do I control the lifespan of a short-lived branch?
+As a global admin, you can set the parameter `sonar.dbcleaner.daysBeforeDeletingInactiveShortLivingBranches` to control how many days you want to keep an inactive short-lived branch.
-**Q:** Does the payload of the Webhook contain extra information related to Branches?
-**A:** Yes, an extra node called "branch" is added to the payload.
+## Does the payload of the Webhook include branch information?
+Yes, an extra node called "branch" is added to the payload.
-**Q:** When are Webhooks called?
-**A:** When the computation of the background task is done for a given branch but also when an issue is updated on a short-lived branch.
+## When are Webhooks called?
+When the computation of the background task is done for a given branch but also when an issue is updated on a short-lived branch.
-**Q:** What is the impact on my LOCs consumption vs my license?
-**A:** The LOC of your largest branch are counted toward your license limit. All other branches are ignored.
+## What is the impact on my LOCs consumption vs my license?
+The LOC of your largest branch are counted toward your license limit. All other branches are ignored.
diff --git a/server/sonar-docs/src/pages/branches/long-lived-branches.md b/server/sonar-docs/src/pages/branches/long-lived-branches.md
index b806d2b6a21..1d0aae67c47 100644
--- a/server/sonar-docs/src/pages/branches/long-lived-branches.md
+++ b/server/sonar-docs/src/pages/branches/long-lived-branches.md
@@ -1,5 +1,6 @@
---
title: Long-lived Branches
+url: /branches/long-lived-branches/
---
<!-- sonarqube -->
diff --git a/server/sonar-docs/src/pages/branches/index.md b/server/sonar-docs/src/pages/branches/overview.md
index ffe24b02b98..c73cb5fc3c8 100644
--- a/server/sonar-docs/src/pages/branches/index.md
+++ b/server/sonar-docs/src/pages/branches/overview.md
@@ -1,5 +1,6 @@
---
-title: Branches
+title: Overview
+url: /branches/overview/
---
<!-- sonarqube -->
@@ -30,7 +31,7 @@ This corresponds to Pull/Merge Requests or Feature Branches. This kind of branch
![conceptual illustration of short-lived branches.](/images/short-lived-branch-concept.png)
-For more, see [Short-lived Branches](/branches/short-lived-branches)
+For more, see [Short-lived Branches](/branches/short-lived-branches/)
### Long-lived
@@ -44,7 +45,7 @@ This kind of branch will:
![conceptual illustration of long-lived branches.](/images/long-lived-branch-concept.png)
-For more, see [Long-lived Branches](/branches/long-lived-branches)
+For more, see [Long-lived Branches](/branches/long-lived-branches/)
### Master / Main Branch
@@ -76,6 +77,6 @@ This can be updated globally in **Configuration > General > Detection** of long-
Once a branch type has been set, it cannot be changed. Explicitly, you cannot transform a long-lived to short-lived branch, or vice-versa.
## See also
-* [Short-lived Branches](short-lived-branches)
-* [Long-lived Branches](long-lived-branches)
-* [Frequently Asked Questions](branches-faq)
+* [Short-lived Branches](/branches/short-lived-branches/)
+* [Long-lived Branches](/branches/long-lived-branches/)
+* [Frequently Asked Questions](/branches/branches-faq/)
diff --git a/server/sonar-docs/src/pages/branches/short-lived-branches.md b/server/sonar-docs/src/pages/branches/short-lived-branches.md
index 8a937009f64..53e27a263b6 100644
--- a/server/sonar-docs/src/pages/branches/short-lived-branches.md
+++ b/server/sonar-docs/src/pages/branches/short-lived-branches.md
@@ -1,5 +1,6 @@
---
title: Short-lived Branches
+url: /branches/short-lived-branches/
---
<!-- sonarqube -->
diff --git a/server/sonar-docs/src/pages/index.md b/server/sonar-docs/src/pages/index.md
index cfaf315e74d..240e76889da 100644
--- a/server/sonar-docs/src/pages/index.md
+++ b/server/sonar-docs/src/pages/index.md
@@ -1,18 +1,23 @@
---
title: Documentation
+url: /
---
+
<!-- sonarqube -->
+
[SonarQube](http://www.sonarqube.org/)® software (previously called Sonar) is an open source quality management platform, dedicated to continuously analyze and measure technical quality, from project portfolio to method. If you wish to extend the SonarQube platform with open source plugins, have a look at our [plugin library](https://docs.sonarqube.org/display/PLUG/Plugin+Library).
## I write code
-* [Fixing the Water Leak](/fixing-the-water-leak)
-* [Quality Gates](/quality-gates)
-* [Quality Profiles](/quality-profiles)
-<!-- /sonarqube -->
+* [Fixing the Water Leak](/user-guide/fixing-the-water-leak/)
+* [Quality Gates](/user-guide/quality-gates/)
+* [Quality Profiles](/instance-administration/quality-profiles/)
+ <!-- /sonarqube -->
<!-- sonarcloud -->
+
SonarCloud is the leading product for Continuous Code Quality online, totally free for open-source projects. It supports all major programming languages, including Java, C#, JavaScript, TypeScript, C/C++ and many more. If your code is closed source, SonarCloud also offers a paid plan to run private analyses.
-SonarCloud offers end-to-end integrations for teams leveraging [GitHub](/integrations/github), [VSTS](/integrations/vsts), or [Bitbucket Cloud](/integrations/bitbucketcloud) in their development processes.
+SonarCloud offers end-to-end integrations for teams leveraging [GitHub](/integrations/github/), [VSTS](/integrations/vsts/), or [Bitbucket Cloud](/integrations/bitbucketcloud/) in their development processes.
+
<!-- /sonarcloud -->
diff --git a/server/sonar-docs/src/pages/custom-measures.md b/server/sonar-docs/src/pages/instance-administration/custom-measures.md
index 2c3979b283f..8867f060670 100644
--- a/server/sonar-docs/src/pages/custom-measures.md
+++ b/server/sonar-docs/src/pages/instance-administration/custom-measures.md
@@ -1,6 +1,6 @@
---
title: Custom Measures
-scope: sonarqube
+url: /instance-administration/custom-measures/
---
SonarQube collects a maximum of measures in an automated manner but there are some measures for which this is not possible, such as when: the information is not available for collection, the measure is computed by a human, and so on. Whatever the reason, SonarQube provides a service to inject those measures manually and allow you to benefit from other services: the Manual Measures service. The manual measures entered will be picked during the next analysis of the project and thereafter treated as "normal" measures.
diff --git a/server/sonar-docs/src/pages/housekeeping.md b/server/sonar-docs/src/pages/instance-administration/housekeeping.md
index e2b333382d5..bd11f3fd403 100644
--- a/server/sonar-docs/src/pages/housekeeping.md
+++ b/server/sonar-docs/src/pages/instance-administration/housekeeping.md
@@ -1,5 +1,6 @@
---
title: Housekeeping
+url: /instance-administration/housekeeping/
---
When you run a new analysis of your project, some data that was previously available is cleaned out of the database. For example the source code of the previous analysis, measures at directory and file levels, and so on are automatically removed at the end of a new analysis. Additionally, some old analysis snapshots are also removed.
diff --git a/server/sonar-docs/src/pages/look-and-feel.md b/server/sonar-docs/src/pages/instance-administration/look-and-feel.md
index d74542fd730..1008e54d7ec 100644
--- a/server/sonar-docs/src/pages/look-and-feel.md
+++ b/server/sonar-docs/src/pages/instance-administration/look-and-feel.md
@@ -1,6 +1,6 @@
---
title: Look and Feel
-scope: sonarqube
+url: /instance-administration/look-and-feel/
---
## Home logo
diff --git a/server/sonar-docs/src/pages/quality-profiles.md b/server/sonar-docs/src/pages/instance-administration/quality-profiles.md
index 1e9c03e95e6..db513e758ac 100644
--- a/server/sonar-docs/src/pages/quality-profiles.md
+++ b/server/sonar-docs/src/pages/instance-administration/quality-profiles.md
@@ -1,5 +1,6 @@
---
title: Quality Profiles
+url: /instance-administration/quality-profiles/
---
## Overview
diff --git a/server/sonar-docs/src/pages/integrations/index.md b/server/sonar-docs/src/pages/integrations/index.md
deleted file mode 100644
index 01fcb49fe8f..00000000000
--- a/server/sonar-docs/src/pages/integrations/index.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: Integrations
-scope: sonarcloud
----
-
-SonarCloud integrates with the following cloud services to help developers get the most out of their code:
-
-* [Integration with GitHub](/integrations/github)
-* [Integration with Bitbucket Cloud](/integrations/bitbucketcloud)
-* [Integration with VSTS](/integrations/vsts)
diff --git a/server/sonar-docs/src/pages/webhooks.md b/server/sonar-docs/src/pages/project-administration/webhooks.md
index 2c09225141f..96050491720 100644
--- a/server/sonar-docs/src/pages/webhooks.md
+++ b/server/sonar-docs/src/pages/project-administration/webhooks.md
@@ -1,5 +1,6 @@
---
title: Webhooks
+url: /project-administration/webhooks/
---
Webhooks notify external services when a project analysis is complete. An HTTP POST request including a JSON payload is sent to each URL. URLs may be specified at both the project and global levels. Project-level specification does not replace global-level webhooks. All hooks at both levels are called.
diff --git a/server/sonar-docs/src/pages/analyze-a-project.md b/server/sonar-docs/src/pages/sonarcloud/analyze-a-project.md
index 07f425a9740..113f8d502e8 100644
--- a/server/sonar-docs/src/pages/analyze-a-project.md
+++ b/server/sonar-docs/src/pages/sonarcloud/analyze-a-project.md
@@ -1,14 +1,14 @@
---
title: Analyze a Project
-scope: sonarcloud
+url: /analyze-a-project/
---
## Prepare your organization
-A project must belong to an [organization](/organizations/index). Create one if you intend to collaborate with your team mates, or use your personal organization for test purposes.
+A project must belong to an [organization](/organizations/overview/). Create one if you intend to collaborate with your team mates, or use your personal organization for test purposes.
[[info]]
-| ** Important note for private code:** Newly created organizations and personal organizations are under a free plan by default. This means projects analyzed on these organizations are public by default: the code will be browsable by anyone. If you want private projects, you should [upgrade your organization to a paid plan](/sonarcloud-pricing) in the "Administration > Billing" page of your organization.
+| ** Important note for private code:** Newly created organizations and personal organizations are under a free plan by default. This means projects analyzed on these organizations are public by default: the code will be browsable by anyone. If you want private projects, you should [upgrade your organization to a paid plan](/sonarcloud-pricing/) in the "Administration > Billing" page of your organization.
Find the key of your organization, you will need it at later stages. It can be found on the top right corner of your organization's header.
@@ -19,8 +19,8 @@ existing CI scripts.
Depending on which cloud solution you are using for your developments, you can rely on dedicated integrations to help you:
-* VSTS: [read our dedicated documentation](/integrations/vsts)
-* Bitbucket Cloud: [read our dedicated documentation](/integrations/bitbucketcloud)
-* GitHub: [read our dedicated documentation](/integrations/github)
+* VSTS: [read our dedicated documentation](/integrations/vsts/)
+* Bitbucket Cloud: [read our dedicated documentation](/integrations/bitbucketcloud/)
+* GitHub: [read our dedicated documentation](/integrations/github/)
If you are not using those solutions, you will have to find out what command to execute to run the analysis. Our [tutorial](/#sonarcloud#/onboarding) will help you on this.
diff --git a/server/sonar-docs/src/pages/integrations/bitbucketcloud.md b/server/sonar-docs/src/pages/sonarcloud/integrations/bitbucketcloud.md
index d547c0db84a..6006edcf435 100644
--- a/server/sonar-docs/src/pages/integrations/bitbucketcloud.md
+++ b/server/sonar-docs/src/pages/sonarcloud/integrations/bitbucketcloud.md
@@ -1,6 +1,6 @@
---
title: Integration with Bitbucket Cloud
-scope: sonarcloud
+url: /integrations/bitbucketcloud/
---
## Authentication
diff --git a/server/sonar-docs/src/pages/integrations/github.md b/server/sonar-docs/src/pages/sonarcloud/integrations/github.md
index 12034296f7e..c283c9689c6 100644
--- a/server/sonar-docs/src/pages/integrations/github.md
+++ b/server/sonar-docs/src/pages/sonarcloud/integrations/github.md
@@ -1,6 +1,6 @@
---
title: Integration with GitHub
-scope: sonarcloud
+url: /integrations/github/
---
## Authentication
diff --git a/server/sonar-docs/src/pages/integrations/vsts.md b/server/sonar-docs/src/pages/sonarcloud/integrations/vsts.md
index de94cd73ad1..448affcd709 100644
--- a/server/sonar-docs/src/pages/integrations/vsts.md
+++ b/server/sonar-docs/src/pages/sonarcloud/integrations/vsts.md
@@ -1,6 +1,6 @@
---
title: Integration with VSTS
-scope: sonarcloud
+url: /integrations/vsts/
---
diff --git a/server/sonar-docs/src/pages/organizations/index.md b/server/sonar-docs/src/pages/sonarcloud/organizations/index.md
index 7ddec3f8abe..b872a83ac19 100644
--- a/server/sonar-docs/src/pages/organizations/index.md
+++ b/server/sonar-docs/src/pages/sonarcloud/organizations/index.md
@@ -1,6 +1,6 @@
---
title: Organizations
-scope: sonarcloud
+url: /organizations/overview/
---
## Overview
@@ -9,8 +9,8 @@ An organization is a space where a team or a whole company can collaborate acros
An organization consists of:
* Projects, on which users collaborate
-* [Members](/organizations/manage-team), who can have different persmissions on the projects
-* [Quality Profiles](/quality-profiles) and [Quality Gates](/quality-gates), which can be customized and shared accross projects
+* [Members](/organizations/manage-team/), who can have different persmissions on the projects
+* [Quality Profiles](/instance-administration/quality-profiles/) and [Quality Gates](/user-guide/quality-gates/), which can be customized and shared accross projects
There are 2 kind of organizations:
* **Personal organizations**. Each account has a personal organization linked to it. This is typically where open-source developers host their personal projects. It is not possible to delete this kind of organization.
@@ -20,4 +20,4 @@ Organizations can be on:
* **Free plan**. This is the default plan. Every project in an organization on the free plan is public.
* **Paid plan**. This plan unlocks the ability to have private projects. Go to the "Billing" page of your organization to upgrade it to the paid plan.
-Depending on which plan the organization is in, its [visibility](/organizations/organization-visibility) will change.
+Depending on which plan the organization is in, its [visibility](/organizations/organization-visibility/) will change.
diff --git a/server/sonar-docs/src/pages/organizations/manage-team.md b/server/sonar-docs/src/pages/sonarcloud/organizations/manage-team.md
index 53d650f3746..8cbb162bcc1 100644
--- a/server/sonar-docs/src/pages/organizations/manage-team.md
+++ b/server/sonar-docs/src/pages/sonarcloud/organizations/manage-team.md
@@ -1,6 +1,6 @@
---
title: Manage a Team
-scope: sonarcloud
+url: /organizations/manage-team/
---
Members can collaborate on the projects in the organizations to which they belong. Depending on their permisssions within the organization, members can:
diff --git a/server/sonar-docs/src/pages/organizations/organization-visibility.md b/server/sonar-docs/src/pages/sonarcloud/organizations/organization-visibility.md
index c9e746dfa51..94c560580a4 100644
--- a/server/sonar-docs/src/pages/organizations/organization-visibility.md
+++ b/server/sonar-docs/src/pages/sonarcloud/organizations/organization-visibility.md
@@ -1,6 +1,6 @@
---
title: Organization Visibility
-scope: sonarcloud
+url: /organizations/organization-visibility/
---
## Free plan organization
diff --git a/server/sonar-docs/src/pages/privacy.md b/server/sonar-docs/src/pages/sonarcloud/privacy.md
index 3e122cf5c6a..a92e13c100a 100644
--- a/server/sonar-docs/src/pages/privacy.md
+++ b/server/sonar-docs/src/pages/sonarcloud/privacy.md
@@ -1,6 +1,6 @@
---
title: Privacy
-scope: sonarcloud
+url: /privacy/
---
The privacy policy specifies how data collected on this website is used. Thank you for visiting our website and your interest in our services and products. As the protection of your personal data is an important concern for us, we will explain below what information we collect during your visit to our website, as they are processed and whether or how these may be used.
diff --git a/server/sonar-docs/src/pages/security.md b/server/sonar-docs/src/pages/sonarcloud/security.md
index 1ec4590eb9c..89315038c6b 100644
--- a/server/sonar-docs/src/pages/security.md
+++ b/server/sonar-docs/src/pages/sonarcloud/security.md
@@ -1,6 +1,6 @@
---
title: SonarCloud Security
-scope: sonarcloud
+url: /security/
---
We know that your code is very important to you and your business. We also know that no one wants proven bugs or vulnerabilities found on their source code to be unveiled to third-parties. This is why we take security extremely seriously.
diff --git a/server/sonar-docs/src/pages/sonarcloud-pricing.md b/server/sonar-docs/src/pages/sonarcloud/sonarcloud-pricing.md
index e38c41a713a..fd0567412f4 100644
--- a/server/sonar-docs/src/pages/sonarcloud-pricing.md
+++ b/server/sonar-docs/src/pages/sonarcloud/sonarcloud-pricing.md
@@ -1,6 +1,6 @@
---
title: Pricing
-scope: sonarcloud
+url: /sonarcloud-pricing/
---
Subscribing to a paid plan on SonarCloud allows you to analyze unlimited private projects. You can make your code visible by members of your organization only.
diff --git a/server/sonar-docs/src/pages/fixing-the-water-leak.md b/server/sonar-docs/src/pages/user-guide/fixing-the-water-leak.md
index 6158b2ff23c..be0a6b446fd 100644
--- a/server/sonar-docs/src/pages/fixing-the-water-leak.md
+++ b/server/sonar-docs/src/pages/user-guide/fixing-the-water-leak.md
@@ -1,5 +1,6 @@
---
title: Fixing the Water Leak
+url: /user-guide/fixing-the-water-leak/
---
## What is the Water Leak
@@ -19,7 +20,7 @@ Typically in this traditional approach, just before release a periodic code qual
Instead, why not apply the same simple logic you use at home to the way you manage code quality? Fixing the leak means putting the focus on the “new” code, i.e. the code that was added or changed since the last release. Then things get much easier:
-* The [Quality Gate](/quality-gates) can be run every day, and passing it is achievable. There are no surprises at release time.
+* The [Quality Gate](/user-guide/quality-gates/) can be run every day, and passing it is achievable. There are no surprises at release time.
* It's pretty difficult for developers to push back on problems they introduced the previous day. Instead, they're generally happy to fix the problems while the code is still fresh.
* There is a clear ownership of code quality
* The criteria for go/no-go are consistent across applications, and are shared among teams. Indeed new code is new code, regardless of which application it is done in
@@ -32,5 +33,5 @@ As a bonus, the code that gets changed the most has the highest maintainability,
<!-- sonarqube -->SonarQube<!-- /sonarqube --><!-- sonarcloud -->SonarCloud<!-- /sonarcloud --> offers two main tools to help you find your leaks:
* New Code metrics show the variance in your measures between the current code and a specific point you choose in its history, typically the `previous_version`
-* New Code is primarily detected based on SCM "blame" data starting from the first analysis within your New Code Period (formerly the "Leak Period"), with fallback mechanisms when needed. See [SCM integration](/analysis/scm-integration) for more details.
-* [Quality Gates](/quality-gates) allow you to set boolean thresholds against which your code is measured. Use them with differential metrics to ensure that your code quality moves in the right direction over time.
+* New Code is primarily detected based on SCM "blame" data starting from the first analysis within your New Code Period (formerly the "Leak Period"), with fallback mechanisms when needed. See [SCM integration](/analysis/scm-integration/) for more details.
+* [Quality Gates](/user-guide/quality-gates/) allow you to set boolean thresholds against which your code is measured. Use them with differential metrics to ensure that your code quality moves in the right direction over time.
diff --git a/server/sonar-docs/src/pages/keyboard-shortcuts.md b/server/sonar-docs/src/pages/user-guide/keyboard-shortcuts.md
index 178ccff0999..e6fa54758c4 100644
--- a/server/sonar-docs/src/pages/keyboard-shortcuts.md
+++ b/server/sonar-docs/src/pages/user-guide/keyboard-shortcuts.md
@@ -1,6 +1,6 @@
---
title: Keyboard Shortcuts
-order: 99
+url: /user-guide/keyboard-shortcuts/
---
## Global
diff --git a/server/sonar-docs/src/pages/metric-definitions.md b/server/sonar-docs/src/pages/user-guide/metric-definitions.md
index 737b3e656db..9507636dfe4 100644
--- a/server/sonar-docs/src/pages/metric-definitions.md
+++ b/server/sonar-docs/src/pages/user-guide/metric-definitions.md
@@ -1,5 +1,6 @@
---
title: Metric Definitions
+url: /user-guide/metric-definitions/
---
## Table of Contents
diff --git a/server/sonar-docs/src/pages/quality-gates.md b/server/sonar-docs/src/pages/user-guide/quality-gates.md
index 9d1cdda2dc2..8d422fbc151 100644
--- a/server/sonar-docs/src/pages/quality-gates.md
+++ b/server/sonar-docs/src/pages/user-guide/quality-gates.md
@@ -1,5 +1,6 @@
---
title: Quality Gates
+url: /user-guide/quality-gates/
---
## Overview
@@ -23,7 +24,7 @@ Which is why you can define as many quality gates as you wish. Quality Gates are
## Use the Best Quality Gate Configuration
-The quality gate "Sonar way" is provided by SonarSource, activated by default and considered as built-in and so read-only. It represents our view of the best way to implement the [Fixing the Water Leak](/fixing-the-water-leak) concept. At each SonarQube release, we adjust automatically this default quality gate according to SonarQube's capabilities.
+The quality gate "Sonar way" is provided by SonarSource, activated by default and considered as built-in and so read-only. It represents our view of the best way to implement the [Fixing the Water Leak](/user-guide/fixing-the-water-leak/) concept. At each SonarQube release, we adjust automatically this default quality gate according to SonarQube's capabilities.
Three metrics allow you to enforce a given Rating of Reliability, Security and Maintainability, not just overall but also on new code. These metrics are recommended and come as part of the default quality gate. We strongly advise you to adjust your own quality gates to use them to make feedback more clear to your developers looking at their quality gate on their project page.
diff --git a/server/sonar-docs/src/pages/security-reports.md b/server/sonar-docs/src/pages/user-guide/security-reports.md
index 79d6372e5a4..f25d69c2aa1 100644
--- a/server/sonar-docs/src/pages/security-reports.md
+++ b/server/sonar-docs/src/pages/user-guide/security-reports.md
@@ -1,5 +1,6 @@
---
title: Security Reports
+url: /user-guide/security-reports/
---
## What do the Security Reports show?
diff --git a/server/sonar-docs/src/pages/user-account.md b/server/sonar-docs/src/pages/user-guide/user-account.md
index 43feacfed3f..935823eda08 100644
--- a/server/sonar-docs/src/pages/user-account.md
+++ b/server/sonar-docs/src/pages/user-guide/user-account.md
@@ -1,8 +1,9 @@
---
title: User Account
+url: /user-guide/user-account/
---
-As a <!-- sonarqube -->SonarQube<!-- /sonarqube --><!-- sonarcloud -->SonarCloud<!-- /sonarcloud --> user you have your own space where you can see the things that are relevant to you:
+As a {instance} user you have your own space where you can see the things that are relevant to you:
## Home Page
@@ -13,7 +14,7 @@ It gives you a summary of:
## Security
-In addition to being able to change your password, if your instance is not using a 3rd party authentication mechanism such as LDAP or any OAuth provider (GitHub, Google Account, ...), you can manage your own [authentication tokens](/user-token).
+In addition to being able to change your password, if your instance is not using a 3rd party authentication mechanism such as LDAP or any OAuth provider (GitHub, Google Account, ...), you can manage your own authentication tokens.
-You can create as many Token as you want. Once a Token is created, you can use it to publish analysis to a project where you have the [execute analysis](/security/authorization) permission.
+You can create as many Token as you want. Once a Token is created, you can use it to publish analysis to a project where you have the execute analysis permission.
diff --git a/server/sonar-docs/src/templates/page.js b/server/sonar-docs/src/templates/page.js
index 75b02494ed3..ad61a0fb70c 100644
--- a/server/sonar-docs/src/templates/page.js
+++ b/server/sonar-docs/src/templates/page.js
@@ -51,10 +51,11 @@ export default class Page extends React.PureComponent {
htmlWithInclusions = removeTableOfContents(htmlWithInclusions);
htmlWithInclusions = createAnchorForHeadings(htmlWithInclusions, realHeadingsList);
htmlWithInclusions = replaceDynamicLinks(htmlWithInclusions);
+ htmlWithInclusions = replaceInstanceTag(htmlWithInclusions);
return (
<div css={{ paddingTop: 24, paddingBottom: 24 }}>
- <Helmet title={page.frontmatter.title}>
+ <Helmet title={page.frontmatter.title || 'Documentation'}>
<html lang="en" />
</Helmet>
<HeaderList headers={realHeadingsList} />
@@ -99,6 +100,10 @@ export const query = graphql`
}
`;
+function replaceInstanceTag(content) {
+ return content.replace('{instance}', 'SonarQube');
+}
+
function replaceDynamicLinks(content) {
const version = process.env.GATSBY_DOCS_VERSION || '';
const usePrefix = process.env.GATSBY_USE_PREFIX === '1';
@@ -115,12 +120,6 @@ function replaceDynamicLinks(content) {
'<a href="http$1" target="_blank">$2</a>'
);
- // Add trailing slash to local link
- content = content.replace(
- /\<a href="(?!http)(.*)(?!\/)"\>(.*)\<\/a\>/gim,
- '<a href="$1/">$2</a>'
- );
-
return content.replace(
/\<a href="(.*)\/#(?:sonarqube|sonarcloud|sonarqube-admin)#.*"\>(.*)\<\/a\>/gim,
'$2'