Parcourir la source

SONAR-12500 Help section in the "Analysis scope" settings page should be more visible

tags/8.1.0.31237
Philippe Perrin il y a 4 ans
Parent
révision
a631b1a1a4

+ 18
- 32
server/sonar-docs/src/pages/project-administration/narrowing-the-focus.md Voir le fichier

@@ -14,6 +14,23 @@ If {instance}'s results aren't relevant, no one will want to use it. That's why

You can make these changes globally or at a project level. At both levels, the navigation path is the same: **Administration > General Settings > Analysis Scope**.

## Patterns

Paths are relative to the project base directory. The following wildcards can be used:

* `*` - Match zero or more characters
* `**` - Match zero or more directories
* `?` - Match a single character

Relative paths are based on the fully qualified name of the component.

Example|Matches|Does not match
----|----|----
`**/*Bean.java`|org/sonar.api/MyBean.java <br/> org/sonar/util/MyOtherBean.java|org/sonar/util/MyDTO.java
`**/*Bean?.java`|org/sonar/util/MyOtherBean1.java|org/sonar/util/MyOtherBean.java <br/> org/sonar.api/MyBean.java <br/> org/sonar/util/MyDTO.java
`org/sonar/*`|org/sonar/MyClass.java <br/> org/sonar/MyOtherClass.java|org/sonar/util/MyClassUtil.java
`org/sonar/**/*`|org/sonar/MyClass.java <br/> org/sonar/MyOtherClass.java <br/> org/sonar/util/MyClassUtil.java|

## Ignore Files
We recommend that you exclude generated code, source code from libraries, etc. There are four different ways to narrow your analysis to the source code that will be relevant to the development team. You can combine them all together to tune your analysis scope. Additionally, we automatically exclude from analysis the files described in your projects' `.gitignore` files. This behavior can be disabled. See `sonar.scm.exclusions.disabled` in the [Analysis Parameters](/analysis/analysis-parameters/) page for details.

@@ -116,35 +133,4 @@ To do so, go to **Administration > General Settings > Analysis Scope > Duplicati

You can prevent some files from being taken into account for code coverage by unit tests.

To do so, go to **Administration > General Settings > Analysis Scope > Code Coverage** and set the *Coverage Exclusions* property. See the Patterns section for more details on the syntax.

## Patterns

Paths are relative to the project base directory.

The following wildcards can be used:

* `*` - zero or more characters
* `**` - zero or more directories
* `?` - a single character

Relative paths are based on the fully qualified name of the component.

Examples:

`# Exclude all classes ending by "Bean"`
`# Matches org/sonar.api/MyBean.java, org/sonar/util/MyOtherBean.java, org/sonar/util/MyDTO.java, etc.`
`sonar.exclusions=**/*Bean.java,**/*DTO.java`

`# Exclude all classes in the "src/main/java/org/sonar" directory`
`# Matches src/main/java/org/sonar/MyClass.java, src/main/java/org/sonar/MyOtherClass.java`
`# But does not match src/main/java/org/sonar/util/MyClassUtil.java`
`sonar.exclusions=src/main/java/org/sonar/*`

`# Exclude all COBOL programs in the "bank" directory and its sub-directories`
`# Matches bank/ZTR00021.cbl, bank/data/CBR00354.cbl, bank/data/REM012345.cob`
`sonar.exclusions=bank/**/*`

`# Exclude all COBOL programs in the "bank" directory and its sub-directories whose extension is .cbl`
`# Matches bank/ZTR00021.cbl, bank/data/CBR00354.cbl`
`sonar.exclusions=bank/**/*.cbl`
To do so, go to **Administration > General Settings > Analysis Scope > Code Coverage** and set the *Coverage Exclusions* property. See the Patterns section for more details on the syntax.

+ 31
- 9
server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx Voir le fichier

@@ -20,19 +20,27 @@

import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { LANGUAGES_CATEGORY, NEW_CODE_PERIOD_CATEGORY } from './AdditionalCategoryKeys';
import {
ANALYSIS_SCOPE_CATEGORY,
LANGUAGES_CATEGORY,
NEW_CODE_PERIOD_CATEGORY
} from './AdditionalCategoryKeys';
import { AnalysisScope } from './AnalysisScope';
import Languages from './Languages';
import NewCodePeriod from './NewCodePeriod';

export interface AdditionalCategoryComponentProps {
parentComponent: T.Component | undefined;
selectedCategory: string;
}

export interface AdditionalCategory {
key: string;
name: string;
renderComponent: (
parentComponent: T.Component | undefined,
selectedCategory: string
) => JSX.Element;
renderComponent: (props: AdditionalCategoryComponentProps) => JSX.Element;
availableGlobally: boolean;
availableForProject: boolean;
displayTab: boolean;
}

export const ADDITIONAL_CATEGORIES: AdditionalCategory[] = [
@@ -41,21 +49,35 @@ export const ADDITIONAL_CATEGORIES: AdditionalCategory[] = [
name: translate('property.category.languages'),
renderComponent: getLanguagesComponent,
availableGlobally: true,
availableForProject: true
availableForProject: true,
displayTab: true
},
{
key: NEW_CODE_PERIOD_CATEGORY,
name: translate('settings.new_code_period.category'),
renderComponent: getNewCodePeriodComponent,
availableGlobally: true,
availableForProject: false
availableForProject: false,
displayTab: true
},
{
key: ANALYSIS_SCOPE_CATEGORY,
name: translate('property.category.exclusions'),
renderComponent: getAnalysisScopeComponent,
availableGlobally: true,
availableForProject: true,
displayTab: false
}
];

function getLanguagesComponent(component: any, originalCategory: string) {
return <Languages component={component} selectedCategory={originalCategory} />;
function getLanguagesComponent(props: AdditionalCategoryComponentProps) {
return <Languages {...props} />;
}

function getNewCodePeriodComponent() {
return <NewCodePeriod />;
}

function getAnalysisScopeComponent(props: AdditionalCategoryComponentProps) {
return <AnalysisScope {...props} />;
}

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/AdditionalCategoryKeys.ts Voir le fichier

@@ -20,3 +20,4 @@

export const LANGUAGES_CATEGORY = 'languages';
export const NEW_CODE_PERIOD_CATEGORY = 'new_code_period';
export const ANALYSIS_SCOPE_CATEGORY = 'exclusions';

+ 7
- 5
server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx Voir le fichier

@@ -67,11 +67,13 @@ export class CategoriesList extends React.PureComponent<CategoriesListProps> {
name: getCategoryName(key)
}))
.concat(
this.props.component
? // Project settings
ADDITIONAL_CATEGORIES.filter(c => c.availableForProject)
: // Global settings
ADDITIONAL_CATEGORIES.filter(c => c.availableGlobally)
ADDITIONAL_CATEGORIES.filter(c => c.displayTab).filter(c =>
this.props.component
? // Project settings
c.availableForProject
: // Global settings
c.availableGlobally
)
);
const sortedCategories = sortBy(categoriesWithName, category => category.name.toLowerCase());
return (

+ 63
- 0
server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx Voir le fichier

@@ -0,0 +1,63 @@
/*
* 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.
*/

import * as React from 'react';
import { Link } from 'react-router';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { AdditionalCategoryComponentProps } from './AdditionalCategories';
import CategoryDefinitionsList from './CategoryDefinitionsList';

export function AnalysisScope(props: AdditionalCategoryComponentProps) {
const { parentComponent, selectedCategory } = props;

return (
<>
<p className="spacer-bottom">
{translate('settings.analysis_scope.wildcards.introduction')}
<Link
className="spacer-left"
to="/documentation/project-administration/narrowing-the-focus/">
{translate('learn_more')}
</Link>
</p>

<table className="data spacer-bottom">
<tbody>
<tr>
<td>*</td>
<td>{translate('settings.analysis_scope.wildcards.zero_more_char')}</td>
</tr>
<tr>
<td>**</td>
<td>{translate('settings.analysis_scope.wildcards.zero_more_dir')}</td>
</tr>
<tr>
<td>?</td>
<td>{translate('settings.analysis_scope.wildcards.single_char')}</td>
</tr>
</tbody>
</table>

<div className="settings-sub-category">
<CategoryDefinitionsList category={selectedCategory} component={parentComponent} />
</div>
</>
);
}

+ 4
- 5
server/sonar-web/src/main/js/apps/settings/components/AppContainer.tsx Voir le fichier

@@ -34,7 +34,6 @@ import AllCategoriesList from './AllCategoriesList';
import CategoryDefinitionsList from './CategoryDefinitionsList';
import { CATEGORY_OVERRIDES } from './CategoryOverrides';
import PageHeader from './PageHeader';
import WildcardsHelp from './WildcardsHelp';

interface Props {
component?: T.Component;
@@ -82,7 +81,6 @@ export class App extends React.PureComponent<Props & WithRouterProps, State> {
}

const { query } = this.props.location;

const originalCategory = (query.category as string) || this.props.defaultCategory;
const overriddenCategory = CATEGORY_OVERRIDES[originalCategory.toLowerCase()];
const selectedCategory = overriddenCategory || originalCategory;
@@ -110,15 +108,16 @@ export class App extends React.PureComponent<Props & WithRouterProps, State> {
</div>
<div className="side-tabs-main">
{foundAdditionalCategory && shouldRenderAdditionalCategory ? (
foundAdditionalCategory.renderComponent(this.props.component, originalCategory)
foundAdditionalCategory.renderComponent({
parentComponent: this.props.component,
selectedCategory: originalCategory
})
) : (
<CategoryDefinitionsList
category={selectedCategory}
component={this.props.component}
/>
)}

{selectedCategory === 'exclusions' && <WildcardsHelp />}
</div>
</div>
</div>

+ 0
- 122
server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.tsx Voir le fichier

@@ -1,122 +0,0 @@
/*
* 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.
*/
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';

export default function WildcardsHelp() {
return (
<div className="huge-spacer-top">
<h2 className="spacer-bottom">{translate('settings.wildcards')}</h2>
<p className="spacer-bottom">{translate('settings.wildcards.following_rules_are_applied')}</p>

<table className="data spacer-bottom">
<tbody>
<tr>
<td>*</td>
<td>{translate('settings.wildcards.zero_more_char')}</td>
</tr>
<tr>
<td>**</td>
<td>{translate('settings.wildcards.zero_more_dir')}</td>
</tr>
<tr>
<td>?</td>
<td>{translate('settings.wildcards.single_char')}</td>
</tr>
</tbody>
</table>

<table className="data zebra">
<thead>
<tr>
<th>{translate('example')}</th>
<th>{translate('settings.wildcards.matches')}</th>
<th>{translate('settings.wildcards.does_no_match')}</th>
</tr>
</thead>
<tbody>
<tr>
<td>**/foo/*.js</td>
<td>
<ul>
<li>src/foo/bar.js</li>
<li>lib/ui/foo/bar.js</li>
</ul>
</td>
<td>
<ul>
<li>src/bar.js</li>
<li>src/foo2/bar.js</li>
</ul>
</td>
</tr>
<tr>
<td>src/foo/*bar*.js</td>
<td>
<ul>
<li>src/foo/bar.js</li>
<li>src/foo/bar1.js</li>
<li>src/foo/bar123.js</li>
<li>src/foo/123bar123.js</li>
</ul>
</td>
<td>
<ul>
<li>src/foo/ui/bar.js</li>
<li>src/bar.js</li>
</ul>
</td>
</tr>
<tr>
<td>src/foo/**</td>
<td>
<ul>
<li>src/foo/bar.js</li>
<li>src/foo/ui/bar.js</li>
</ul>
</td>
<td>
<ul>
<li>src/bar/foo/bar.js</li>
<li>src/bar.js</li>
</ul>
</td>
</tr>
<tr>
<td>**/foo?.js</td>
<td>
<ul>
<li>src/foo1.js</li>
<li>src/bar/foo1.js</li>
</ul>
</td>
<td>
<ul>
<li>src/foo.js</li>
<li>src/foo12.js</li>
<li>src/12foo3.js</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
);
}

+ 14
- 3
server/sonar-web/src/main/js/apps/settings/components/__tests__/AllCategoriesList-test.tsx Voir le fichier

@@ -30,21 +30,32 @@ jest.mock('../AdditionalCategories', () => ({
name: 'CAT_1_NAME',
renderComponent: jest.fn(),
availableGlobally: true,
availableForProject: true
availableForProject: true,
displayTab: true
},
{
key: 'CAT_2',
name: 'CAT_2_NAME',
renderComponent: jest.fn(),
availableGlobally: true,
availableForProject: false
availableForProject: false,
displayTab: true
},
{
key: 'CAT_3',
name: 'CAT_3_NAME',
renderComponent: jest.fn(),
availableGlobally: false,
availableForProject: true
availableForProject: true,
displayTab: true
},
{
key: 'CAT_4',
name: 'CAT_4_NAME',
renderComponent: jest.fn(),
availableGlobally: true,
availableForProject: true,
displayTab: false
}
] as AdditionalCategory[]
}));

+ 32
- 0
server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx Voir le fichier

@@ -0,0 +1,32 @@
/*
* 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.
*/

import { shallow } from 'enzyme';
import * as React from 'react';
import { mockComponent } from '../../../../helpers/testMocks';
import { AnalysisScope } from '../AnalysisScope';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

function shallowRender() {
return shallow(<AnalysisScope parentComponent={mockComponent()} selectedCategory="TEST" />);
}

+ 24
- 4
server/sonar-web/src/main/js/apps/settings/components/__tests__/AppContainer-test.tsx Voir le fichier

@@ -19,26 +19,46 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockLocation, mockRouter } from '../../../../helpers/testMocks';
import { LANGUAGES_CATEGORY, NEW_CODE_PERIOD_CATEGORY } from '../AdditionalCategoryKeys';
import {
ANALYSIS_SCOPE_CATEGORY,
LANGUAGES_CATEGORY,
NEW_CODE_PERIOD_CATEGORY
} from '../AdditionalCategoryKeys';
import { App } from '../AppContainer';

it('should render correctly', () => {
it('should render default view correctly', async () => {
const wrapper = shallowRender();

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});

it('should render newCodePeriod correctly', () => {
it('should render newCodePeriod correctly', async () => {
const wrapper = shallowRender({
location: mockLocation({ query: { category: NEW_CODE_PERIOD_CATEGORY } })
});

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});

it('should render languages correctly', () => {
it('should render languages correctly', async () => {
const wrapper = shallowRender({
location: mockLocation({ query: { category: LANGUAGES_CATEGORY } })
});

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});

it('should render analysis scope correctly', async () => {
const wrapper = shallowRender({
location: mockLocation({ query: { category: ANALYSIS_SCOPE_CATEGORY } })
});

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});


+ 79
- 0
server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap Voir le fichier

@@ -0,0 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<Fragment>
<p
className="spacer-bottom"
>
settings.analysis_scope.wildcards.introduction
<Link
className="spacer-left"
onlyActiveOnIndex={false}
style={Object {}}
to="/documentation/project-administration/narrowing-the-focus/"
>
learn_more
</Link>
</p>
<table
className="data spacer-bottom"
>
<tbody>
<tr>
<td>
*
</td>
<td>
settings.analysis_scope.wildcards.zero_more_char
</td>
</tr>
<tr>
<td>
**
</td>
<td>
settings.analysis_scope.wildcards.zero_more_dir
</td>
</tr>
<tr>
<td>
?
</td>
<td>
settings.analysis_scope.wildcards.single_char
</td>
</tr>
</tbody>
</table>
<div
className="settings-sub-category"
>
<Connect(SubCategoryDefinitionsList)
category="TEST"
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "MyProject",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
/>
</div>
</Fragment>
`;

+ 139
- 3
server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AppContainer-test.tsx.snap Voir le fichier

@@ -1,7 +1,143 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `""`;
exports[`should render analysis scope correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
>
<Suggestions
suggestions="settings"
/>
<HelmetWrapper
defer={true}
encodeSpecialCharacters={true}
title="settings.page"
/>
<PageHeader />
<div
className="side-tabs-layout settings-layout"
>
<div
className="side-tabs-side"
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="exclusions"
/>
</div>
<div
className="side-tabs-main"
>
<AnalysisScope
selectedCategory="exclusions"
/>
</div>
</div>
</div>
`;

exports[`should render languages correctly 1`] = `""`;
exports[`should render default view correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
>
<Suggestions
suggestions="settings"
/>
<HelmetWrapper
defer={true}
encodeSpecialCharacters={true}
title="settings.page"
/>
<PageHeader />
<div
className="side-tabs-layout settings-layout"
>
<div
className="side-tabs-side"
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="general"
/>
</div>
<div
className="side-tabs-main"
>
<Connect(SubCategoryDefinitionsList)
category="general"
/>
</div>
</div>
</div>
`;

exports[`should render newCodePeriod correctly 1`] = `""`;
exports[`should render languages correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
>
<Suggestions
suggestions="settings"
/>
<HelmetWrapper
defer={true}
encodeSpecialCharacters={true}
title="settings.page"
/>
<PageHeader />
<div
className="side-tabs-layout settings-layout"
>
<div
className="side-tabs-side"
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="languages"
/>
</div>
<div
className="side-tabs-main"
>
<withRouter(Connect(Languages))
selectedCategory="languages"
/>
</div>
</div>
</div>
`;

exports[`should render newCodePeriod correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
>
<Suggestions
suggestions="settings"
/>
<HelmetWrapper
defer={true}
encodeSpecialCharacters={true}
title="settings.page"
/>
<PageHeader />
<div
className="side-tabs-layout settings-layout"
>
<div
className="side-tabs-side"
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="new_code_period"
/>
</div>
<div
className="side-tabs-main"
>
<NewCodePeriod />
</div>
</div>
</div>
`;

+ 5
- 7
sonar-core/src/main/resources/org/sonar/l10n/core.properties Voir le fichier

@@ -907,13 +907,11 @@ settings.default.complex_value=<complex value>
settings.default.password=<password>
settings.reset_confirm.title=Reset Setting
settings.reset_confirm.description=Are you sure that you want to reset this setting?
settings.wildcards=Wildcards
settings.wildcards.following_rules_are_applied=Following rules are applied:
settings.wildcards.zero_more_char=Match zero or more characters
settings.wildcards.zero_more_dir=Match zero or more directories
settings.wildcards.single_char=Match a single character
settings.wildcards.matches=Matches
settings.wildcards.does_no_match=Does not match

settings.analysis_scope.wildcards.introduction=You can use the following wildcards.
settings.analysis_scope.wildcards.zero_more_char=Match zero or more characters
settings.analysis_scope.wildcards.zero_more_dir=Match zero or more directories
settings.analysis_scope.wildcards.single_char=Match a single character

settings.new_code_period.category=New Code Period
settings.new_code_period.title=Default New Code Period behavior

Chargement…
Annuler
Enregistrer