Explorar el Código

SONAR-13035 Group global ALM related settings into a single category

tags/8.2.0.32929
Wouter Admiraal hace 4 años
padre
commit
3c110148c7
Se han modificado 92 ficheros con 2407 adiciones y 1549 borrados
  1. 2
    1
      server/sonar-auth-github/src/main/java/org/sonar/auth/github/GitHubSettings.java
  2. 1
    1
      server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabSettings.java
  3. 0
    0
      server/sonar-web/src/main/js/api/alm-settings.ts
  4. 12
    0
      server/sonar-web/src/main/js/app/styles/init/misc.css
  5. 3
    3
      server/sonar-web/src/main/js/apps/create/project/CreateProjectPageSonarQube.tsx
  6. 2
    2
      server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketPersonalAccessTokenForm-test.tsx
  7. 2
    2
      server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx
  8. 2
    2
      server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx
  9. 4
    4
      server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPageSonarQube-test.tsx
  10. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreateRenderer-test.tsx.snap
  11. 9
    10
      server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx
  12. 1
    1
      server/sonar-web/src/main/js/apps/settings/components/AdditionalCategoryKeys.ts
  13. 5
    1
      server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx
  14. 4
    4
      server/sonar-web/src/main/js/apps/settings/components/__tests__/AppContainer-test.tsx
  15. 28
    1
      server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap
  16. 25
    23
      server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AppContainer-test.tsx.snap
  17. 12
    16
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx
  18. 5
    5
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx
  19. 16
    18
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx
  20. 43
    34
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx
  21. 16
    17
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionsTable.tsx
  22. 35
    12
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx
  23. 67
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationFeatureBox.tsx
  24. 185
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx
  25. 15
    5
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTab.tsx
  26. 160
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
  27. 5
    5
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx
  28. 25
    14
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureTab.tsx
  29. 7
    7
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx
  30. 114
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx
  31. 5
    5
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/DeleteModal.tsx
  32. 8
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
  33. 85
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubTab.tsx
  34. 5
    5
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx
  35. 80
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx
  36. 8
    7
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx
  37. 9
    4
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormField-test.tsx
  38. 6
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormModalRenderer-test.tsx
  39. 6
    6
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx
  40. 10
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionsTable-test.tsx
  41. 8
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx
  42. 39
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationFeatureBox-test.tsx
  43. 15
    11
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx
  44. 2
    2
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTab-test.tsx
  45. 18
    2
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTabRenderer-test.tsx
  46. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AzureForm-test.tsx
  47. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AzureTab-test.tsx
  48. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx
  49. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx
  50. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/DeleteModal-test.tsx
  51. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GithubForm-test.tsx
  52. 3
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GithubTab-test.tsx
  53. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabForm-test.tsx
  54. 3
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx
  55. 1
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionForm-test.tsx.snap
  56. 3
    3
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap
  57. 31
    15
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormModalRenderer-test.tsx.snap
  58. 161
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap
  59. 26
    26
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionsTable-test.tsx.snap
  60. 3
    1
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegration-test.tsx.snap
  61. 97
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationFeatureBox-test.tsx.snap
  62. 152
    74
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationRenderer-test.tsx.snap
  63. 0
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap
  64. 334
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
  65. 8
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap
  66. 42
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureTab-test.tsx.snap
  67. 12
    12
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
  68. 112
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
  69. 8
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/DeleteModal-test.tsx.snap
  70. 14
    14
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
  71. 84
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubTab-test.tsx.snap
  72. 8
    8
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap
  73. 68
    0
      server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap
  74. 0
    136
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTabRenderer.tsx
  75. 0
    57
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx
  76. 0
    57
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx
  77. 0
    51
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx
  78. 0
    186
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx
  79. 0
    121
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormRenderer-test.tsx.snap
  80. 0
    254
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
  81. 0
    28
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap
  82. 0
    40
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
  83. 0
    44
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap
  84. 0
    28
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap
  85. 12
    12
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx
  86. 3
    3
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx
  87. 10
    10
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx
  88. 9
    9
      server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
  89. 2
    2
      server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts
  90. 23
    23
      server/sonar-web/src/main/js/types/alm-settings.ts
  91. 63
    53
      sonar-core/src/main/resources/org/sonar/l10n/core.properties
  92. 5
    0
      sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java

+ 2
- 1
server/sonar-auth-github/src/main/java/org/sonar/auth/github/GitHubSettings.java Ver fichero

@@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.PropertyDefinition;

@@ -42,7 +43,7 @@ public class GitHubSettings {

private static final String ORGANIZATIONS = "sonar.auth.github.organizations";

private static final String CATEGORY = "security";
private static final String CATEGORY = CoreProperties.CATEGORY_ALM_INTEGRATION;
private static final String SUBCATEGORY = "github";

private final Configuration configuration;

+ 1
- 1
server/sonar-auth-gitlab/src/main/java/org/sonar/auth/gitlab/GitLabSettings.java Ver fichero

@@ -38,7 +38,7 @@ public class GitLabSettings {
static final String GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP = "sonar.auth.gitlab.allowUsersToSignUp";
static final String GITLAB_AUTH_SYNC_USER_GROUPS = "sonar.auth.gitlab.groupsSync";

private static final String CATEGORY = CoreProperties.CATEGORY_SECURITY;
private static final String CATEGORY = CoreProperties.CATEGORY_ALM_INTEGRATION;
private static final String SUBCATEGORY = "gitlab";

private final Configuration configuration;

server/sonar-web/src/main/js/api/almSettings.ts → server/sonar-web/src/main/js/api/alm-settings.ts Ver fichero


+ 12
- 0
server/sonar-web/src/main/js/app/styles/init/misc.css Ver fichero

@@ -152,6 +152,14 @@ th.hide-overflow {
padding-top: calc(var(--gridSize) / 2) !important;
}

.big-padded-top {
padding-top: calc(2 * var(--gridSize));
}

.huge-padded-top {
padding-top: 40px;
}

td.little-spacer-left {
padding-left: 4px !important;
}
@@ -305,6 +313,10 @@ th.huge-spacer-right {
width: 600px !important;
}

.abs-height-100 {
height: 100% !important;
}

.max-height-100 {
max-height: 100% !important;
}

+ 3
- 3
server/sonar-web/src/main/js/apps/create/project/CreateProjectPageSonarQube.tsx Ver fichero

@@ -22,11 +22,11 @@ import { Helmet } from 'react-helmet-async';
import { WithRouterProps } from 'react-router';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages';
import { getAlmSettings } from '../../../api/almSettings';
import { getAlmSettings } from '../../../api/alm-settings';
import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
import { withAppState } from '../../../components/hoc/withAppState';
import { getProjectUrl } from '../../../helpers/urls';
import { AlmSettingsInstance, ALM_KEYS } from '../../../types/alm-settings';
import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
import BitbucketProjectCreate from './BitbucketProjectCreate';
import CreateProjectModeSelection from './CreateProjectModeSelection';
import ManualProjectCreate from './ManualProjectCreate';
@@ -81,7 +81,7 @@ export class CreateProjectPageSonarQube extends React.PureComponent<Props, State
.then(almSettings => {
if (this.mounted) {
this.setState({
bitbucketSettings: almSettings.filter(s => s.alm === ALM_KEYS.BITBUCKET),
bitbucketSettings: almSettings.filter(s => s.alm === AlmKeys.Bitbucket),
loading: false
});
}

+ 2
- 2
server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketPersonalAccessTokenForm-test.tsx Ver fichero

@@ -23,7 +23,7 @@ import * as React from 'react';
import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
import { change, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
import { ALM_KEYS } from '../../../../types/alm-settings';
import { AlmKeys } from '../../../../types/alm-settings';
import BitbucketPersonalAccessTokenForm, {
BitbucketPersonalAccessTokenFormProps
} from '../BitbucketPersonalAccessTokenForm';
@@ -54,7 +54,7 @@ function shallowRender(props: Partial<BitbucketPersonalAccessTokenFormProps> = {
return shallow<BitbucketPersonalAccessTokenFormProps>(
<BitbucketPersonalAccessTokenForm
bitbucketSetting={mockAlmSettingsInstance({
alm: ALM_KEYS.BITBUCKET,
alm: AlmKeys.Bitbucket,
url: 'http://www.example.com'
})}
onPersonalAccessTokenCreate={jest.fn()}

+ 2
- 2
server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx Ver fichero

@@ -31,7 +31,7 @@ import {
import { mockBitbucketRepository } from '../../../../helpers/mocks/alm-integrations';
import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
import { mockLocation } from '../../../../helpers/testMocks';
import { ALM_KEYS } from '../../../../types/alm-settings';
import { AlmKeys } from '../../../../types/alm-settings';
import { BitbucketProjectCreate } from '../BitbucketProjectCreate';

jest.mock('../../../../api/alm-integrations', () => {
@@ -129,7 +129,7 @@ it('should correctly import a repo', async () => {
function shallowRender(props: Partial<BitbucketProjectCreate['props']> = {}) {
return shallow<BitbucketProjectCreate>(
<BitbucketProjectCreate
bitbucketSettings={[mockAlmSettingsInstance({ alm: ALM_KEYS.BITBUCKET, key: 'foo' })]}
bitbucketSettings={[mockAlmSettingsInstance({ alm: AlmKeys.Bitbucket, key: 'foo' })]}
loadingBindings={false}
location={mockLocation()}
onProjectCreate={jest.fn()}

+ 2
- 2
server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx Ver fichero

@@ -25,7 +25,7 @@ import {
mockBitbucketRepository
} from '../../../../helpers/mocks/alm-integrations';
import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
import { ALM_KEYS } from '../../../../types/alm-settings';
import { AlmKeys } from '../../../../types/alm-settings';
import BitbucketProjectCreateRenderer, {
BitbucketProjectCreateRendererProps
} from '../BitbucketProjectCreateRenderer';
@@ -49,7 +49,7 @@ it('should render correctly', () => {
function shallowRender(props: Partial<BitbucketProjectCreateRendererProps> = {}) {
return shallow<BitbucketProjectCreateRendererProps>(
<BitbucketProjectCreateRenderer
bitbucketSetting={mockAlmSettingsInstance({ alm: ALM_KEYS.BITBUCKET })}
bitbucketSetting={mockAlmSettingsInstance({ alm: AlmKeys.Bitbucket })}
importing={false}
loading={false}
onImportRepository={jest.fn()}

+ 4
- 4
server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPageSonarQube-test.tsx Ver fichero

@@ -21,14 +21,14 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { addWhitePageClass } from 'sonar-ui-common/helpers/pages';
import { getAlmSettings } from '../../../../api/almSettings';
import { getAlmSettings } from '../../../../api/alm-settings';
import { mockLocation, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks';
import { ALM_KEYS } from '../../../../types/alm-settings';
import { AlmKeys } from '../../../../types/alm-settings';
import { CreateProjectPageSonarQube } from '../CreateProjectPageSonarQube';
import { CreateProjectModes } from '../types';

jest.mock('../../../../api/almSettings', () => ({
getAlmSettings: jest.fn().mockResolvedValue([{ alm: ALM_KEYS.BITBUCKET, key: 'foo' }])
jest.mock('../../../../api/alm-settings', () => ({
getAlmSettings: jest.fn().mockResolvedValue([{ alm: AlmKeys.Bitbucket, key: 'foo' }])
}));

jest.mock('sonar-ui-common/helpers/pages', () => ({

+ 1
- 1
server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreateRenderer-test.tsx.snap Ver fichero

@@ -179,7 +179,7 @@ exports[`should render correctly: invalid config, admin user 1`] = `
Object {
"pathname": "/admin/settings",
"query": Object {
"category": "pull_request_decoration",
"category": "almintegration",
},
}
}

+ 9
- 10
server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx Ver fichero

@@ -20,16 +20,16 @@
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import {
ALM_INTEGRATION,
ANALYSIS_SCOPE_CATEGORY,
LANGUAGES_CATEGORY,
NEW_CODE_PERIOD_CATEGORY,
PULL_REQUEST_DECORATION_BINDING_CATEGORY,
PULL_REQUEST_DECORATION_CATEGORY
PULL_REQUEST_DECORATION_BINDING_CATEGORY
} from './AdditionalCategoryKeys';
import AlmIntegration from './almIntegration/AlmIntegration';
import { AnalysisScope } from './AnalysisScope';
import Languages from './Languages';
import NewCodePeriod from './NewCodePeriod';
import PullRequestDecoration from './pullRequestDecoration/PullRequestDecoration';
import PullRequestDecorationBinding from './pullRequestDecorationBinding/PRDecorationBinding';

export interface AdditionalCategoryComponentProps {
@@ -73,13 +73,12 @@ export const ADDITIONAL_CATEGORIES: AdditionalCategory[] = [
displayTab: false
},
{
key: PULL_REQUEST_DECORATION_CATEGORY,
name: translate('settings.pr_decoration.category'),
renderComponent: getPullRequestDecorationComponent,
key: ALM_INTEGRATION,
name: translate('property.category.almintegration'),
renderComponent: getAlmIntegrationComponent,
availableGlobally: true,
availableForProject: false,
displayTab: true,
requiresBranchesEnabled: true
displayTab: false
},
{
key: PULL_REQUEST_DECORATION_BINDING_CATEGORY,
@@ -104,8 +103,8 @@ function getAnalysisScopeComponent(props: AdditionalCategoryComponentProps) {
return <AnalysisScope {...props} />;
}

function getPullRequestDecorationComponent() {
return <PullRequestDecoration />;
function getAlmIntegrationComponent(props: AdditionalCategoryComponentProps) {
return <AlmIntegration {...props} />;
}

function getPullRequestDecorationBindingComponent(props: AdditionalCategoryComponentProps) {

+ 1
- 1
server/sonar-web/src/main/js/apps/settings/components/AdditionalCategoryKeys.ts Ver fichero

@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
export const ALM_INTEGRATION = 'almintegration';
export const ANALYSIS_SCOPE_CATEGORY = 'exclusions';
export const LANGUAGES_CATEGORY = 'languages';
export const NEW_CODE_PERIOD_CATEGORY = 'new_code_period';
export const PULL_REQUEST_DECORATION_CATEGORY = 'pull_request_decoration';
export const PULL_REQUEST_DECORATION_BINDING_CATEGORY = 'pull_request_decoration_binding';

+ 5
- 1
server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx Ver fichero

@@ -28,6 +28,7 @@ interface Props {
component?: T.Component;
fetchValues: Function;
settings: Array<T.Setting & { definition: T.SettingCategoryDefinition }>;
subCategory?: string;
}

export default class SubCategoryDefinitionsList extends React.PureComponent<Props> {
@@ -66,9 +67,12 @@ export default class SubCategoryDefinitionsList extends React.PureComponent<Prop
const sortedSubCategories = sortBy(subCategories, subCategory =>
subCategory.name.toLowerCase()
);
const filteredSubCategories = this.props.subCategory
? sortedSubCategories.filter(c => c.key === this.props.subCategory)
: sortedSubCategories;
return (
<ul className="settings-sub-categories-list">
{sortedSubCategories.map(subCategory => (
{filteredSubCategories.map(subCategory => (
<li key={subCategory.key}>
<h2 className="settings-sub-category-name">{subCategory.name}</h2>
{subCategory.description != null && (

+ 4
- 4
server/sonar-web/src/main/js/apps/settings/components/__tests__/AppContainer-test.tsx Ver fichero

@@ -22,11 +22,11 @@ import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockLocation, mockRouter } from '../../../../helpers/testMocks';
import {
ALM_INTEGRATION,
ANALYSIS_SCOPE_CATEGORY,
LANGUAGES_CATEGORY,
NEW_CODE_PERIOD_CATEGORY,
PULL_REQUEST_DECORATION_BINDING_CATEGORY,
PULL_REQUEST_DECORATION_CATEGORY
PULL_REQUEST_DECORATION_BINDING_CATEGORY
} from '../AdditionalCategoryKeys';
import { App } from '../AppContainer';

@@ -64,9 +64,9 @@ it('should render analysis scope correctly', async () => {
expect(wrapper).toMatchSnapshot();
});

it('should render pull request decoration correctly', async () => {
it('should render ALM integration correctly', async () => {
const wrapper = shallowRender({
location: mockLocation({ query: { category: PULL_REQUEST_DECORATION_CATEGORY } })
location: mockLocation({ query: { category: ALM_INTEGRATION } })
});

await waitAndUpdate(wrapper);

+ 28
- 1
server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap Ver fichero

@@ -60,7 +60,34 @@ exports[`should render additional categories component correctly 3`] = `
/>
`;

exports[`should render additional categories component correctly 4`] = `<PullRequestDecoration />`;
exports[`should render additional categories component correctly 4`] = `
<Connect(withAppState(AlmIntegration))
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 [],
}
}
selectedCategory="TEST"
/>
`;

exports[`should render additional categories component correctly 5`] = `
<PRDecorationBinding

+ 25
- 23
server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AppContainer-test.tsx.snap Ver fichero

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

exports[`should render analysis scope correctly 1`] = `
exports[`should render ALM integration correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
@@ -22,21 +22,21 @@ exports[`should render analysis scope correctly 1`] = `
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="exclusions"
selectedCategory="almintegration"
/>
</div>
<div
className="side-tabs-main"
>
<AnalysisScope
selectedCategory="exclusions"
<Connect(withAppState(AlmIntegration))
selectedCategory="almintegration"
/>
</div>
</div>
</div>
`;

exports[`should render default view correctly 1`] = `
exports[`should render analysis scope correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
@@ -58,21 +58,21 @@ exports[`should render default view correctly 1`] = `
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="general"
selectedCategory="exclusions"
/>
</div>
<div
className="side-tabs-main"
>
<Connect(SubCategoryDefinitionsList)
category="general"
<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"
@@ -94,21 +94,21 @@ exports[`should render languages correctly 1`] = `
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="languages"
selectedCategory="general"
/>
</div>
<div
className="side-tabs-main"
>
<withRouter(Connect(Languages))
selectedCategory="languages"
<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"
@@ -130,19 +130,21 @@ exports[`should render newCodePeriod correctly 1`] = `
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="new_code_period"
selectedCategory="languages"
/>
</div>
<div
className="side-tabs-main"
>
<NewCodePeriod />
<withRouter(Connect(Languages))
selectedCategory="languages"
/>
</div>
</div>
</div>
`;

exports[`should render pull request decoration binding correctly 1`] = `
exports[`should render newCodePeriod correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
@@ -164,21 +166,19 @@ exports[`should render pull request decoration binding correctly 1`] = `
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="pull_request_decoration_binding"
selectedCategory="new_code_period"
/>
</div>
<div
className="side-tabs-main"
>
<Connect(SubCategoryDefinitionsList)
category="pull_request_decoration_binding"
/>
<NewCodePeriod />
</div>
</div>
</div>
`;

exports[`should render pull request decoration correctly 1`] = `
exports[`should render pull request decoration binding correctly 1`] = `
<div
className="page page-limited"
id="settings-page"
@@ -200,13 +200,15 @@ exports[`should render pull request decoration correctly 1`] = `
>
<Connect(CategoriesList)
defaultCategory="general"
selectedCategory="pull_request_decoration"
selectedCategory="pull_request_decoration_binding"
/>
</div>
<div
className="side-tabs-main"
>
<PullRequestDecoration />
<Connect(SubCategoryDefinitionsList)
category="pull_request_decoration_binding"
/>
</div>
</div>
</div>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationForm.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx Ver fichero

@@ -19,11 +19,11 @@
*/
import { isEqual, omit } from 'lodash';
import * as React from 'react';
import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
import AlmPRDecorationFormModalRenderer from './AlmPRDecorationFormModalRenderer';
import AlmPRDecorationFormRenderer from './AlmPRDecorationFormRenderer';
import { AlmBindingDefinition } from '../../../../types/alm-settings';
import AlmBindingDefinitionFormModalRenderer from './AlmBindingDefinitionFormModalRenderer';
import AlmBindingDefinitionFormRenderer from './AlmBindingDefinitionFormRenderer';

export interface AlmPRDecorationFormChildrenProps<B> {
export interface AlmBindingDefinitionFormChildrenProps<B> {
formData: B;
hideKeyField?: boolean;
onFieldChange: (fieldId: keyof B, value: string) => void;
@@ -31,9 +31,8 @@ export interface AlmPRDecorationFormChildrenProps<B> {
}

interface Props<B> {
alm: ALM_KEYS;
bindingDefinition: B;
children: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode;
children: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode;
help?: React.ReactNode;
hideKeyField?: boolean;
loading?: boolean;
@@ -51,10 +50,9 @@ interface State<B> {
touched: boolean;
}

export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends React.PureComponent<
Props<B>,
State<B>
> {
export default class AlmBindingDefinitionForm<
B extends AlmBindingDefinition
> extends React.PureComponent<Props<B>, State<B>> {
constructor(props: Props<B>) {
super(props);
this.state = { formData: props.bindingDefinition, touched: false };
@@ -115,7 +113,6 @@ export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends R

render() {
const {
alm,
bindingDefinition,
children,
help,
@@ -132,9 +129,8 @@ export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends R
const showDelete = showEdit && this.props.onDelete !== undefined;

return showInModal ? (
<AlmPRDecorationFormModalRenderer
<AlmBindingDefinitionFormModalRenderer
action={bindingDefinition.key ? 'edit' : 'create'}
alm={alm}
canSubmit={this.canSubmit}
help={help}
onCancel={this.handleCancel}
@@ -143,9 +139,9 @@ export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends R
formData,
onFieldChange: this.handleFieldChange
})}
</AlmPRDecorationFormModalRenderer>
</AlmBindingDefinitionFormModalRenderer>
) : (
<AlmPRDecorationFormRenderer
<AlmBindingDefinitionFormRenderer
canSubmit={this.canSubmit}
help={help}
loading={loading}
@@ -160,7 +156,7 @@ export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends R
onFieldChange: this.handleFieldChange,
readOnly
})}
</AlmPRDecorationFormRenderer>
</AlmBindingDefinitionFormRenderer>
);
}
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmDefinitionFormField.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx Ver fichero

@@ -20,9 +20,9 @@
import * as React from 'react';
import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { AlmSettingsBinding } from '../../../../types/alm-settings';
import { AlmBindingDefinition } from '../../../../types/alm-settings';

export interface AlmDefinitionFormFieldProps<B extends AlmSettingsBinding> {
export interface AlmBindingDefinitionFormFieldProps<B extends AlmBindingDefinition> {
autoFocus?: boolean;
help?: React.ReactNode;
id: string;
@@ -34,8 +34,8 @@ export interface AlmDefinitionFormFieldProps<B extends AlmSettingsBinding> {
value: string;
}

export function AlmDefinitionFormField<B extends AlmSettingsBinding>(
props: AlmDefinitionFormFieldProps<B>
export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>(
props: AlmBindingDefinitionFormFieldProps<B>
) {
const {
autoFocus,
@@ -52,7 +52,7 @@ export function AlmDefinitionFormField<B extends AlmSettingsBinding>(
return (
<div className="modal-field">
<label className="display-flex-center" htmlFor={id}>
{translate('settings.pr_decoration.form', id)}
{translate('settings.almintegration.form', id)}
<em className="mandatory spacer-right">*</em>
{help && <HelpTooltip overlay={help} placement="right" />}
</label>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModalRenderer.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormModalRenderer.tsx Ver fichero

@@ -23,11 +23,9 @@ import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { ALM_KEYS } from '../../../../types/alm-settings';

export interface AlmPRDecorationFormModalProps {
export interface AlmBindingDefinitionFormModalProps {
action: 'edit' | 'create';
alm: ALM_KEYS;
canSubmit: () => boolean;
children: React.ReactNode;
help?: React.ReactNode;
@@ -35,14 +33,11 @@ export interface AlmPRDecorationFormModalProps {
onSubmit: () => void;
}

export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationFormModalProps) {
const { alm, action, children, help } = props;
const header = translate(
'settings',
alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration',
'form.header',
action
);
export default function AlmBindingDefinitionFormModalRenderer(
props: AlmBindingDefinitionFormModalProps
) {
const { action, children, help } = props;
const header = translate('settings.almintegration.form.header', action);

return (
<SimpleModal header={header} onClose={props.onCancel} onSubmit={props.onSubmit} size="medium">
@@ -53,18 +48,21 @@ export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationF
</div>

<div className="modal-body modal-container">
{help && (
<Alert className="big-spacer-bottom" variant="info">
{help}
</Alert>
)}
{children}
<div className="display-flex-start">
<div className="flex-1">{children}</div>

{help && (
<Alert className="huge-spacer-left flex-1" variant="info">
{help}
</Alert>
)}
</div>
</div>

<div className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
<SubmitButton disabled={submitting || !props.canSubmit()}>
{translate('settings.pr_decoration.form.save')}
{translate('settings.almintegration.form.save')}
</SubmitButton>
<ResetButtonLink onClick={onCloseClick}>{translate('cancel')}</ResetButtonLink>
</div>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormRenderer.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx Ver fichero

@@ -24,7 +24,7 @@ import { Alert } from 'sonar-ui-common/components/ui/Alert';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';

export interface AlmPRDecorationFormRendererProps {
export interface AlmBindingDefinitionFormRendererProps {
canSubmit: () => boolean;
children: React.ReactNode;
help?: React.ReactNode;
@@ -36,7 +36,9 @@ export interface AlmPRDecorationFormRendererProps {
success: boolean;
}

export default function AlmPRDecorationFormRenderer(props: AlmPRDecorationFormRendererProps) {
export default function AlmBindingDefinitionFormRenderer(
props: AlmBindingDefinitionFormRendererProps
) {
const { children, help, loading, success } = props;

return (
@@ -47,40 +49,47 @@ export default function AlmPRDecorationFormRenderer(props: AlmPRDecorationFormRe
e.preventDefault();
props.onSubmit();
}}>
{help && (
<Alert className="big-spacer-bottom" variant="info">
{help}
</Alert>
)}
<div className="display-flex-start">
<div className="flex-1">
{children}

{children}
<div className="display-flex-center">
{props.onEdit === undefined ? (
<SubmitButton disabled={loading || !props.canSubmit()}>
{translate('settings.almintegration.form.save')}
</SubmitButton>
) : (
<Button disabled={loading} onClick={props.onEdit}>
{translate('edit')}
</Button>
)}
{props.onDelete && (
<Button
className="button-red spacer-left"
disabled={loading}
onClick={props.onDelete}>
{translate('delete')}
</Button>
)}
{props.onCancel && (
<ResetButtonLink className="spacer-left" onClick={props.onCancel}>
{translate('cancel')}
</ResetButtonLink>
)}
{loading && <DeferredSpinner className="spacer-left" />}
{!loading && success && (
<span className="text-success spacer-left">
<AlertSuccessIcon className="spacer-right" />
{translate('settings.state.saved')}
</span>
)}
</div>
</div>

<div className="display-flex-center">
{props.onEdit === undefined ? (
<SubmitButton disabled={loading || !props.canSubmit()}>
{translate('settings.pr_decoration.form.save')}
</SubmitButton>
) : (
<Button disabled={loading} onClick={props.onEdit}>
{translate('edit')}
</Button>
)}
{props.onDelete && (
<Button className="button-red spacer-left" disabled={loading} onClick={props.onDelete}>
{translate('delete')}
</Button>
)}
{props.onCancel && (
<ResetButtonLink className="spacer-left" onClick={props.onCancel}>
{translate('cancel')}
</ResetButtonLink>
)}
{loading && <DeferredSpinner className="spacer-left" />}
{!loading && success && (
<span className="text-success spacer-left">
<AlertSuccessIcon className="spacer-right" />
{translate('settings.state.saved')}
</span>
{help && (
<Alert className="huge-spacer-left flex-1" variant="info">
{help}
</Alert>
)}
</div>
</form>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationTable.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionsTable.tsx Ver fichero

@@ -21,11 +21,12 @@ import * as React from 'react';
import { Button, ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons';
import EditIcon from 'sonar-ui-common/components/icons/EditIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { ALM_KEYS } from '../../../../types/alm-settings';
import { AlmKeys } from '../../../../types/alm-settings';

export interface AlmPRDecorationTableProps {
export interface AlmBindingDefinitionsTableProps {
additionalColumnsHeaders: Array<string>;
alm: ALM_KEYS;
additionalTableInfo?: React.ReactNode;
alm: AlmKeys;
definitions: Array<{
key: string;
additionalColumns: Array<string>;
@@ -35,36 +36,34 @@ export interface AlmPRDecorationTableProps {
onEdit: (definitionKey: string) => void;
}

export default function AlmPRDecorationTable(props: AlmPRDecorationTableProps) {
const { additionalColumnsHeaders, alm, definitions } = props;
export default function AlmBindingDefinitionsTable(props: AlmBindingDefinitionsTableProps) {
const { additionalColumnsHeaders, additionalTableInfo, alm, definitions } = props;

return (
<>
<div className="spacer-top big-spacer-bottom display-flex-space-between">
<h4 className="display-inline">
{translate(
'settings',
alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration',
'table.title'
)}
</h4>
<h2 className="settings-sub-category-name">
{translate('settings.almintegration.table.title')}
</h2>
<Button data-test="settings__alm-create" onClick={props.onCreate}>
{translate('settings.pr_decoration.table.create')}
{translate('settings.almintegration.table.create')}
</Button>
</div>

{additionalTableInfo}

<table className="data zebra fixed spacer-bottom">
<thead>
<tr>
<th>{translate('settings.pr_decoration.table.column.name')}</th>
<th>{translate('settings.almintegration.table.column.name')}</th>
{additionalColumnsHeaders.map(h => (
<th key={h}>{h}</th>
))}
<th className="action-small text-center">
{translate('settings.pr_decoration.table.column.edit')}
{translate('settings.almintegration.table.column.edit')}
</th>
<th className="action text-center">
{translate('settings.pr_decoration.table.column.delete')}
{translate('settings.almintegration.table.column.delete')}
</th>
</tr>
</thead>
@@ -72,7 +71,7 @@ export default function AlmPRDecorationTable(props: AlmPRDecorationTableProps) {
{definitions.length === 0 ? (
<tr data-test="settings__alm-empty-table">
<td colSpan={3 + additionalColumnsHeaders.length}>
{translate('settings.pr_decoration.table.empty', alm)}
{translate('settings.almintegration.table.empty', alm)}
</td>
</tr>
) : (

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegration.tsx Ver fichero

@@ -22,27 +22,33 @@ import {
countBindedProjects,
deleteConfiguration,
getAlmDefinitions
} from '../../../../api/almSettings';
import { AlmSettingsBindingDefinitions, ALM_KEYS } from '../../../../types/alm-settings';
import PRDecorationTabs from './PRDecorationTabs';
} from '../../../../api/alm-settings';
import { withAppState } from '../../../../components/hoc/withAppState';
import { AlmKeys, AlmSettingsBindingDefinitions } from '../../../../types/alm-settings';
import AlmIntegrationRenderer from './AlmIntegrationRenderer';

interface Props {
appState: Pick<T.AppState, 'branchesEnabled' | 'multipleAlmEnabled'>;
component?: T.Component;
}

interface State {
currentAlm: ALM_KEYS;
currentAlm: AlmKeys;
definitionKeyForDeletion?: string;
definitions: AlmSettingsBindingDefinitions;
loading: boolean;
projectCount?: number;
}

export default class PullRequestDecoration extends React.PureComponent<{}, State> {
export class AlmIntegration extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
currentAlm: ALM_KEYS.GITHUB,
currentAlm: AlmKeys.GitHub,
definitions: {
[ALM_KEYS.AZURE]: [],
[ALM_KEYS.BITBUCKET]: [],
[ALM_KEYS.GITHUB]: [],
[ALM_KEYS.GITLAB]: []
[AlmKeys.Azure]: [],
[AlmKeys.Bitbucket]: [],
[AlmKeys.GitHub]: [],
[AlmKeys.GitLab]: []
},
loading: true
};
@@ -67,6 +73,14 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State
};

fetchPullRequestDecorationSetting = () => {
const {
appState: { branchesEnabled }
} = this.props;

if (!branchesEnabled) {
return Promise.resolve();
}

this.setState({ loading: true });
return getAlmDefinitions()
.then(definitions => {
@@ -84,7 +98,7 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State
});
};

handleSelectAlm = (currentAlm: ALM_KEYS) => {
handleSelectAlm = (currentAlm: AlmKeys) => {
this.setState({ currentAlm });
};

@@ -112,8 +126,15 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State
};

render() {
const {
appState: { branchesEnabled, multipleAlmEnabled },
component
} = this.props;
return (
<PRDecorationTabs
<AlmIntegrationRenderer
branchesEnabled={Boolean(branchesEnabled)}
component={component}
multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onCancel={this.handleCancel}
onConfirmDelete={this.deleteConfiguration}
onDelete={this.handleDelete}
@@ -124,3 +145,5 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State
);
}
}

export default withAppState(AlmIntegration);

+ 67
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationFeatureBox.tsx Ver fichero

@@ -0,0 +1,67 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 classNames from 'classnames';
import * as React from 'react';
import CheckIcon from 'sonar-ui-common/components/icons/CheckIcon';
import ClearIcon from 'sonar-ui-common/components/icons/ClearIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { colors } from '../../../../app/theme';

export interface AlmIntegrationFeatureBoxProps {
active: boolean;
description: React.ReactNode;
inactiveReason?: React.ReactNode;
name: React.ReactNode;
}

export default function AlmIntegrationFeatureBox(props: AlmIntegrationFeatureBoxProps) {
const { active, description, inactiveReason, name } = props;

return (
<div
className={classNames(
'boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered',
{
'bg-muted': !active
}
)}>
{active ? (
<CheckIcon className="little-spacer-top spacer-right" fill={colors.green} />
) : (
<ClearIcon className="little-spacer-top spacer-right" fill={colors.gray60} />
)}
<div className="display-flex-column abs-height-100">
<h4>{name}</h4>

<div className="spacer-top flex-1">{description}</div>

<div className="spacer-top">
{active ? (
<em className="text-success">{translate('settings.almintegration.feature.enabled')}</em>
) : (
<em className="text-muted">
{inactiveReason || translate('settings.almintegration.feature.disabled')}
</em>
)}
</div>
</div>
</div>
);
}

+ 185
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmIntegrationRenderer.tsx Ver fichero

@@ -0,0 +1,185 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
import { AlmKeys, AlmSettingsBindingDefinitions } from '../../../../types/alm-settings';
import AzureTab from './AzureTab';
import BitbucketTab from './BitbucketTab';
import DeleteModal from './DeleteModal';
import GithubTab from './GithubTab';
import GitlabTab from './GitlabTab';

export interface AlmIntegrationRendererProps {
branchesEnabled: boolean;
component?: T.Component;
currentAlm: AlmKeys;
definitionKeyForDeletion?: string;
definitions: AlmSettingsBindingDefinitions;
loading: boolean;
multipleAlmEnabled: boolean;
onCancel: () => void;
onConfirmDelete: (definitionKey: string) => void;
onDelete: (definitionKey: string) => void;
onSelectAlm: (alm: AlmKeys) => void;
onUpdateDefinitions: () => void;
projectCount?: number;
}

const tabs = [
{
key: AlmKeys.GitHub,
label: (
<>
<img
alt="github"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/github.svg`}
/>
GitHub
</>
)
},
{
key: AlmKeys.Bitbucket,
label: (
<>
<img
alt="bitbucket"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/bitbucket.svg`}
/>
Bitbucket Server
</>
),
requiresBranchesEnabled: true
},
{
key: AlmKeys.Azure,
label: (
<>
<img
alt="azure"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/azure.svg`}
/>
Azure DevOps Server
</>
),
requiresBranchesEnabled: true
},
{
key: AlmKeys.GitLab,
label: (
<>
<img
alt="gitlab"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/gitlab.svg`}
/>
GitLab
</>
)
}
];

export default function AlmIntegrationRenderer(props: AlmIntegrationRendererProps) {
const {
component,
definitionKeyForDeletion,
definitions,
currentAlm,
loading,
branchesEnabled,
multipleAlmEnabled,
projectCount
} = props;

return (
<>
<header className="page-header">
<h1 className="page-title">{translate('settings.almintegration.title')}</h1>
</header>

<div className="markdown small spacer-top big-spacer-bottom">
{translate('settings.almintegration.description')}
</div>
<BoxedTabs
onSelect={props.onSelectAlm}
selected={currentAlm}
tabs={tabs.filter(tab => !(tab.requiresBranchesEnabled && !branchesEnabled))}
/>

{currentAlm === AlmKeys.Azure && (
<AzureTab
definitions={definitions.azure}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
{currentAlm === AlmKeys.Bitbucket && (
<BitbucketTab
definitions={definitions.bitbucket}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
{currentAlm === AlmKeys.GitHub && (
<GithubTab
branchesEnabled={branchesEnabled}
component={component}
definitions={definitions.github}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
{currentAlm === AlmKeys.GitLab && (
<GitlabTab
branchesEnabled={branchesEnabled}
definitions={definitions.gitlab}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}

{definitionKeyForDeletion && (
<DeleteModal
id={definitionKeyForDeletion}
onCancel={props.onCancel}
onDelete={props.onConfirmDelete}
projectCount={projectCount}
/>
)}
</>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTab.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTab.tsx Ver fichero

@@ -18,18 +18,22 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
import { AlmPRDecorationFormChildrenProps } from './AlmPRDecorationForm';
import { AlmBindingDefinition, AlmKeys } from '../../../../types/alm-settings';
import { AlmBindingDefinitionFormChildrenProps } from './AlmBindingDefinitionForm';
import { AlmIntegrationFeatureBoxProps } from './AlmIntegrationFeatureBox';
import AlmTabRenderer from './AlmTabRenderer';

interface Props<B> {
alm: ALM_KEYS;
alm: AlmKeys;
additionalColumnsHeaders?: string[];
additionalColumnsKeys?: Array<keyof B>;
additionalTableInfo?: React.ReactNode;
createConfiguration: (data: B) => Promise<void>;
defaultBinding: B;
definitions: B[];
form: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode;
features?: AlmIntegrationFeatureBoxProps[];
form: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode;
help?: React.ReactNode;
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
@@ -43,7 +47,7 @@ interface State<B> {
success: boolean;
}

export default class AlmTab<B extends AlmSettingsBinding> extends React.PureComponent<
export default class AlmTab<B extends AlmBindingDefinition> extends React.PureComponent<
Props<B>,
State<B>
> {
@@ -100,10 +104,13 @@ export default class AlmTab<B extends AlmSettingsBinding> extends React.PureComp
const {
additionalColumnsHeaders = [],
additionalColumnsKeys = [],
additionalTableInfo,
alm,
defaultBinding,
definitions,
features,
form,
help,
loading,
multipleAlmEnabled
} = this.props;
@@ -113,11 +120,14 @@ export default class AlmTab<B extends AlmSettingsBinding> extends React.PureComp
<AlmTabRenderer
additionalColumnsHeaders={additionalColumnsHeaders}
additionalColumnsKeys={additionalColumnsKeys}
additionalTableInfo={additionalTableInfo}
alm={alm}
defaultBinding={defaultBinding}
definitions={definitions}
editedDefinition={editedDefinition}
features={features}
form={form}
help={help}
loading={loading || submitting}
multipleAlmEnabled={multipleAlmEnabled}
onCancel={this.handleCancel}

+ 160
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx Ver fichero

@@ -0,0 +1,160 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 { FormattedMessage } from 'react-intl';
import { Link } from 'react-router';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { AlmBindingDefinition, AlmKeys } from '../../../../types/alm-settings';
import AlmBindingDefinitionForm, {
AlmBindingDefinitionFormChildrenProps
} from './AlmBindingDefinitionForm';
import AlmBindingDefinitionsTable from './AlmBindingDefinitionsTable';
import AlmIntegrationFeatureBox, {
AlmIntegrationFeatureBoxProps
} from './AlmIntegrationFeatureBox';

export interface AlmTabRendererProps<B> {
additionalColumnsHeaders: string[];
additionalColumnsKeys: Array<keyof B>;
additionalTableInfo?: React.ReactNode;
alm: AlmKeys;
editedDefinition?: B;
defaultBinding: B;
definitions: B[];
features?: AlmIntegrationFeatureBoxProps[];
form: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode;
help?: React.ReactNode;
loading: boolean;
multipleAlmEnabled: boolean;
onCancel: () => void;
onCreate: () => void;
onDelete: (definitionKey: string) => void;
onEdit: (definitionKey: string) => void;
onSubmit: (config: B, originalKey: string) => void;
success: boolean;
}

export default function AlmTabRenderer<B extends AlmBindingDefinition>(
props: AlmTabRendererProps<B>
) {
const {
additionalColumnsHeaders,
additionalColumnsKeys,
additionalTableInfo,
alm,
defaultBinding,
definitions,
editedDefinition,
features = [],
form,
loading,
multipleAlmEnabled,
success,
help = (
<FormattedMessage
defaultMessage={translate(`settings.almintegration.${alm}.info`)}
id={`settings.almintegration.${alm}.info`}
values={{
link: (
<Link target="_blank" to="/documentation/analysis/pr-decoration/">
{translate('learn_more')}
</Link>
)
}}
/>
)
} = props;

let definition: B | undefined;
let mappedDefinitions: Array<{ key: string; additionalColumns: string[] }> = [];
let showEdit: boolean | undefined;

if (!multipleAlmEnabled) {
definition = editedDefinition;
if (definition === undefined && definitions.length > 0) {
definition = definitions[0];
}
showEdit = definition && editedDefinition === undefined;
} else {
mappedDefinitions = definitions.map(({ key, ...properties }) => {
const additionalColumns = additionalColumnsKeys.map(k => (properties as any)[k]);
return {
key,
additionalColumns
};
});
}

return (
<div className="big-padded">
{multipleAlmEnabled ? (
<DeferredSpinner loading={loading}>
<AlmBindingDefinitionsTable
additionalColumnsHeaders={additionalColumnsHeaders}
additionalTableInfo={additionalTableInfo}
alm={alm}
definitions={mappedDefinitions}
onCreate={props.onCreate}
onDelete={props.onDelete}
onEdit={props.onEdit}
/>

{editedDefinition && (
<AlmBindingDefinitionForm
bindingDefinition={editedDefinition}
help={help}
onCancel={props.onCancel}
onSubmit={props.onSubmit}
showInModal={true}>
{form}
</AlmBindingDefinitionForm>
)}
</DeferredSpinner>
) : (
<AlmBindingDefinitionForm
bindingDefinition={definition || defaultBinding}
help={help}
hideKeyField={true}
loading={loading}
onCancel={props.onCancel}
onDelete={definition ? props.onDelete : undefined}
onEdit={showEdit ? props.onEdit : undefined}
onSubmit={props.onSubmit}
readOnly={showEdit}
success={success}>
{form}
</AlmBindingDefinitionForm>
)}

{features.length > 0 && (
<div className="big-spacer-top big-padded-top bordered-top">
<h3 className="big-spacer-bottom">{translate('settings.almintegration.features')}</h3>

<div className="display-flex-wrap">
{features.map((feature, i) => (
<AlmIntegrationFeatureBox key={i} {...feature} />
))}
</div>
</div>
)}
</div>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureForm.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx Ver fichero

@@ -20,7 +20,7 @@
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { AzureBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';

export interface AzureFormProps {
formData: AzureBindingDefinition;
@@ -35,9 +35,9 @@ export default function AzureForm(props: AzureFormProps) {
return (
<>
{!hideKeyField && (
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help={translate('settings.pr_decoration.form.name.azure.help')}
help={translate('settings.almintegration.form.name.azure.help')}
id="name.azure"
onFieldChange={onFieldChange}
propKey="key"
@@ -45,8 +45,8 @@ export default function AzureForm(props: AzureFormProps) {
value={formData.key}
/>
)}
<AlmDefinitionFormField
help={translate('settings.pr_decoration.form.personal_access_token.azure.help')}
<AlmBindingDefinitionFormField
help={translate('settings.almintegration.form.personal_access_token.azure.help')}
id="personal_access_token"
isTextArea={true}
onFieldChange={onFieldChange}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTab.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureTab.tsx Ver fichero

@@ -18,8 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { createAzureConfiguration, updateAzureConfiguration } from '../../../../api/almSettings';
import { ALM_KEYS, AzureBindingDefinition } from '../../../../types/alm-settings';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { createAzureConfiguration, updateAzureConfiguration } from '../../../../api/alm-settings';
import { AlmKeys, AzureBindingDefinition } from '../../../../types/alm-settings';
import AlmTab from './AlmTab';
import AzureForm from './AzureForm';

@@ -35,17 +36,27 @@ export default function AzureTab(props: AzureTabProps) {
const { multipleAlmEnabled, definitions, loading } = props;

return (
<AlmTab
alm={ALM_KEYS.AZURE}
createConfiguration={createAzureConfiguration}
defaultBinding={{ key: '', personalAccessToken: '' }}
definitions={definitions}
form={childProps => <AzureForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateAzureConfiguration}
/>
<div className="bordered">
<AlmTab
alm={AlmKeys.Azure}
createConfiguration={createAzureConfiguration}
defaultBinding={{ key: '', personalAccessToken: '' }}
definitions={definitions}
features={[
{
name: translate('settings.almintegration.feature.pr_decoration.title'),
active: definitions.length > 0,
description: translate('settings.almintegration.feature.pr_decoration.description'),
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding')
}
]}
form={childProps => <AzureForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateAzureConfiguration}
/>
</div>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketForm.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx Ver fichero

@@ -21,7 +21,7 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { BitbucketBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';

export interface BitbucketFormProps {
formData: BitbucketBindingDefinition;
@@ -36,9 +36,9 @@ export default function BitbucketForm(props: BitbucketFormProps) {
return (
<>
{!hideKeyField && (
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help={translate('settings.pr_decoration.form.name.bitbucket.help')}
help={translate('settings.almintegration.form.name.bitbucket.help')}
id="name.bitbucket"
maxLength={100}
onFieldChange={onFieldChange}
@@ -47,11 +47,11 @@ export default function BitbucketForm(props: BitbucketFormProps) {
value={formData.key}
/>
)}
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
help={
<FormattedMessage
defaultMessage={translate('settings.pr_decoration.form.url.bitbucket.help')}
id="settings.pr_decoration.form.url.bitbucket.help"
defaultMessage={translate('settings.almintegration.form.url.bitbucket.help')}
id="settings.almintegration.form.url.bitbucket.help"
values={{ example: 'https://bitbucket-server.your-company.com' }}
/>
}
@@ -62,7 +62,7 @@ export default function BitbucketForm(props: BitbucketFormProps) {
readOnly={readOnly}
value={formData.url}
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="personal_access_token"
isTextArea={true}
onFieldChange={onFieldChange}

+ 114
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketTab.tsx Ver fichero

@@ -0,0 +1,114 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 { FormattedMessage } from 'react-intl';
import { Link } from 'react-router';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import {
createBitbucketConfiguration,
updateBitbucketConfiguration
} from '../../../../api/alm-settings';
import { AlmKeys, BitbucketBindingDefinition } from '../../../../types/alm-settings';
import AlmTab from './AlmTab';
import BitbucketForm from './BitbucketForm';

export interface BitbucketTabProps {
definitions: BitbucketBindingDefinition[];
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}

export default function BitbucketTab(props: BitbucketTabProps) {
const { multipleAlmEnabled, definitions, loading } = props;

return (
<div className="bordered">
<AlmTab
additionalColumnsHeaders={[translate('settings.almintegration.table.column.bitbucket.url')]}
additionalColumnsKeys={['url']}
additionalTableInfo={
<Alert className="big-spacer-bottom width-50" variant="info">
<FormattedMessage
defaultMessage={translate(
'settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances'
)}
id="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances"
values={{
feature: (
<em>{translate('settings.almintegration.feature.alm_repo_import.title')}</em>
)
}}
/>
</Alert>
}
alm={AlmKeys.Bitbucket}
createConfiguration={createBitbucketConfiguration}
defaultBinding={{ key: '', url: '', personalAccessToken: '' }}
definitions={definitions}
features={[
{
name: translate('settings.almintegration.feature.pr_decoration.title'),
active: definitions.length > 0,
description: translate('settings.almintegration.feature.pr_decoration.description'),
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding')
},
{
name: translate('settings.almintegration.feature.alm_repo_import.title'),
active: definitions.length === 1,
description: translate('settings.almintegration.feature.alm_repo_import.description'),
inactiveReason: translateWithParameters(
'onboarding.create_project.too_many_bbs_instances_X',
definitions.length
)
}
]}
form={childProps => <BitbucketForm {...childProps} />}
help={
<>
<h3>{translate('onboarding.create_project.pat_help.title')}</h3>

<p className="big-spacer-top">
{translate('settings.almintegration.bitbucket.help_1')}
</p>

<ul className="big-spacer-top list-styled">
<li>{translate('settings.almintegration.bitbucket.help_2')}</li>
<li>{translate('settings.almintegration.bitbucket.help_3')}</li>
</ul>

<p className="big-spacer-top big-spacer-bottom">
<Link target="_blank" to="/documentation/analysis/pr-decoration/">
{translate('learn_more')}
</Link>
</p>
</>
}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateBitbucketConfiguration}
/>
</div>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/DeleteModal.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/DeleteModal.tsx Ver fichero

@@ -31,11 +31,11 @@ export interface DeleteModalProps {

function showProjectCountWarning(projectCount?: number) {
if (projectCount === undefined) {
return <p>{translate('settings.pr_decoration.delete.no_info')}</p>;
return <p>{translate('settings.almintegration.delete.no_info')}</p>;
}

return projectCount ? (
<p>{translateWithParameters('settings.pr_decoration.delete.info', projectCount)} </p>
<p>{translateWithParameters('settings.almintegration.delete.info', projectCount)} </p>
) : null;
}

@@ -44,15 +44,15 @@ export default function DeleteModal({ id, onDelete, onCancel, projectCount }: De
<ConfirmModal
confirmButtonText={translate('delete')}
confirmData={id}
header={translate('settings.pr_decoration.delete.header')}
header={translate('settings.almintegration.delete.header')}
isDestructive={true}
onClose={onCancel}
onConfirm={onDelete}>
<>
<p className="spacer-bottom">
<FormattedMessage
defaultMessage={translate('settings.pr_decoration.delete.message')}
id="settings.pr_decoration.delete.message"
defaultMessage={translate('settings.almintegration.delete.message')}
id="settings.almintegration.delete.message"
values={{ id: <b>{id}</b> }}
/>
</p>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubForm.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx Ver fichero

@@ -20,7 +20,7 @@
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { GithubBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';

export interface GithubFormProps {
formData: GithubBindingDefinition;
@@ -35,9 +35,9 @@ export default function GithubForm(props: GithubFormProps) {
return (
<>
{!hideKeyField && (
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help={translate('settings.pr_decoration.form.name.github.help')}
help={translate('settings.almintegration.form.name.github.help')}
id="name.github"
onFieldChange={onFieldChange}
propKey="key"
@@ -45,15 +45,15 @@ export default function GithubForm(props: GithubFormProps) {
value={formData.key}
/>
)}
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
help={
<>
{translate('settings.pr_decoration.form.url.github.help1')}
{translate('settings.almintegration.form.url.github.help1')}
<br />
<em>https://github.company.com/api/v3</em>
<br />
<br />
{translate('settings.pr_decoration.form.url.github.help2')}
{translate('settings.almintegration.form.url.github.help2')}
<br />
<em>https://api.github.com/</em>
</>
@@ -65,7 +65,7 @@ export default function GithubForm(props: GithubFormProps) {
readOnly={readOnly}
value={formData.url}
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="app_id"
maxLength={80}
onFieldChange={onFieldChange}
@@ -73,7 +73,7 @@ export default function GithubForm(props: GithubFormProps) {
readOnly={readOnly}
value={formData.appId}
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="private_key"
isTextArea={true}
onFieldChange={onFieldChange}

+ 85
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubTab.tsx Ver fichero

@@ -0,0 +1,85 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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';
import { createGithubConfiguration, updateGithubConfiguration } from '../../../../api/alm-settings';
import { AlmKeys, GithubBindingDefinition } from '../../../../types/alm-settings';
import { ALM_INTEGRATION } from '../AdditionalCategoryKeys';
import CategoryDefinitionsList from '../CategoryDefinitionsList';
import AlmTab from './AlmTab';
import GithubForm from './GithubForm';

export interface GithubTabProps {
branchesEnabled: boolean;
component?: T.Component;
definitions: GithubBindingDefinition[];
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}

export default function GithubTab(props: GithubTabProps) {
const { branchesEnabled, component, multipleAlmEnabled, definitions, loading } = props;

return (
<div className="bordered">
{branchesEnabled && (
<>
<AlmTab
additionalColumnsHeaders={[
translate('settings.almintegration.table.column.github.url'),
translate('settings.almintegration.table.column.app_id')
]}
additionalColumnsKeys={['appId', 'url']}
alm={AlmKeys.GitHub}
createConfiguration={createGithubConfiguration}
defaultBinding={{ key: '', appId: '', url: '', privateKey: '' }}
definitions={definitions}
features={[
{
name: translate('settings.almintegration.feature.pr_decoration.title'),
active: definitions.length > 0,
description: translate('settings.almintegration.feature.pr_decoration.description'),
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding')
}
]}
form={childProps => <GithubForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGithubConfiguration}
/>

<div className="huge-spacer-top huge-spacer-bottom bordered-top" />
</>
)}

<div className="big-padded">
<CategoryDefinitionsList
category={ALM_INTEGRATION}
component={component}
subCategory={AlmKeys.GitHub}
/>
</div>
</div>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabForm.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx Ver fichero

@@ -20,7 +20,7 @@
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { GitlabBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';

export interface GitlabFormProps {
formData: GitlabBindingDefinition;
@@ -35,9 +35,9 @@ export default function GitlabForm(props: GitlabFormProps) {
return (
<>
{!hideKeyField && (
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help={translate('settings.pr_decoration.form.name.gitlab.help')}
help={translate('settings.almintegration.form.name.gitlab.help')}
id="name.gitlab"
onFieldChange={onFieldChange}
propKey="key"
@@ -45,8 +45,8 @@ export default function GitlabForm(props: GitlabFormProps) {
value={formData.key}
/>
)}
<AlmDefinitionFormField
help={translate('settings.pr_decoration.form.personal_access_token.gitlab.help')}
<AlmBindingDefinitionFormField
help={translate('settings.almintegration.form.personal_access_token.gitlab.help')}
id="personal_access_token"
isTextArea={true}
onFieldChange={onFieldChange}

+ 80
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx Ver fichero

@@ -0,0 +1,80 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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';
import { createGitlabConfiguration, updateGitlabConfiguration } from '../../../../api/alm-settings';
import { AlmKeys, GitlabBindingDefinition } from '../../../../types/alm-settings';
import { ALM_INTEGRATION } from '../AdditionalCategoryKeys';
import CategoryDefinitionsList from '../CategoryDefinitionsList';
import AlmTab from './AlmTab';
import GitlabForm from './GitlabForm';

export interface GitlabTabProps {
branchesEnabled: boolean;
component?: T.Component;
definitions: GitlabBindingDefinition[];
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}

export default function GitlabTab(props: GitlabTabProps) {
const { branchesEnabled, component, multipleAlmEnabled, definitions, loading } = props;

return (
<div className="bordered">
{branchesEnabled && (
<>
<AlmTab
alm={AlmKeys.GitLab}
createConfiguration={createGitlabConfiguration}
defaultBinding={{ key: '', personalAccessToken: '' }}
definitions={definitions}
features={[
{
name: translate('settings.almintegration.feature.mr_decoration.title'),
active: definitions.length > 0,
description: translate('settings.almintegration.feature.mr_decoration.description'),
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding')
}
]}
form={childProps => <GitlabForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGitlabConfiguration}
/>

<div className="huge-spacer-top huge-spacer-bottom bordered-top" />
</>
)}

<div className="big-padded">
<CategoryDefinitionsList
category={ALM_INTEGRATION}
component={component}
subCategory={AlmKeys.GitLab}
/>
</div>
</div>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationForm-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx Ver fichero

@@ -21,8 +21,8 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings';
import { ALM_KEYS, GithubBindingDefinition } from '../../../../../types/alm-settings';
import AlmPRDecorationForm from '../AlmPRDecorationForm';
import { GithubBindingDefinition } from '../../../../../types/alm-settings';
import AlmBindingDefinitionForm from '../AlmBindingDefinitionForm';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
@@ -121,15 +121,16 @@ it('should (dis)allow submit by validating its state', () => {
expect(wrapper.instance().canSubmit()).toBe(true);
});

function shallowRender(props: Partial<AlmPRDecorationForm<GithubBindingDefinition>['props']> = {}) {
return shallow<AlmPRDecorationForm<GithubBindingDefinition>>(
<AlmPRDecorationForm
alm={ALM_KEYS.GITHUB}
function shallowRender(
props: Partial<AlmBindingDefinitionForm<GithubBindingDefinition>['props']> = {}
) {
return shallow<AlmBindingDefinitionForm<GithubBindingDefinition>>(
<AlmBindingDefinitionForm
bindingDefinition={{ appId: '', key: '', privateKey: '', url: '' }}
onCancel={jest.fn()}
onSubmit={jest.fn()}
{...props}>
{() => null}
</AlmPRDecorationForm>
</AlmBindingDefinitionForm>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmDefinitionFormField-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormField-test.tsx Ver fichero

@@ -19,8 +19,11 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { AlmSettingsBinding } from '../../../../../types/alm-settings';
import { AlmDefinitionFormField, AlmDefinitionFormFieldProps } from '../AlmDefinitionFormField';
import { AlmBindingDefinition } from '../../../../../types/alm-settings';
import {
AlmBindingDefinitionFormField,
AlmBindingDefinitionFormFieldProps
} from '../AlmBindingDefinitionFormField';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
@@ -42,9 +45,11 @@ it('should call onFieldChange', () => {
expect(onTextAreaChange).toBeCalled();
});

function shallowRender(props: Partial<AlmDefinitionFormFieldProps<AlmSettingsBinding>> = {}) {
function shallowRender(
props: Partial<AlmBindingDefinitionFormFieldProps<AlmBindingDefinition>> = {}
) {
return shallow(
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="key"
isTextArea={false}
maxLength={40}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModalRenderer-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormModalRenderer-test.tsx Ver fichero

@@ -19,26 +19,24 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { ALM_KEYS } from '../../../../../types/alm-settings';
import AlmPRDecorationFormModalRenderer, {
AlmPRDecorationFormModalProps
} from '../AlmPRDecorationFormModalRenderer';
import AlmBindingDefinitionFormModalRenderer, {
AlmBindingDefinitionFormModalProps
} from '../AlmBindingDefinitionFormModalRenderer';

it('should render correctly', () => {
expect(shallowRender().dive()).toMatchSnapshot();
expect(shallowRender({ help: <span>Help me</span> }).dive()).toMatchSnapshot();
});

function shallowRender(props: Partial<AlmPRDecorationFormModalProps> = {}) {
function shallowRender(props: Partial<AlmBindingDefinitionFormModalProps> = {}) {
return shallow(
<AlmPRDecorationFormModalRenderer
<AlmBindingDefinitionFormModalRenderer
action="create"
alm={ALM_KEYS.GITHUB}
canSubmit={jest.fn()}
onCancel={jest.fn()}
onSubmit={jest.fn()}
{...props}>
{() => null}
</AlmPRDecorationFormModalRenderer>
</AlmBindingDefinitionFormModalRenderer>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormRenderer-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx Ver fichero

@@ -21,9 +21,9 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
import { submit } from 'sonar-ui-common/helpers/testUtils';
import AlmPRDecorationFormRenderer, {
AlmPRDecorationFormRendererProps
} from '../AlmPRDecorationFormRenderer';
import AlmBindingDefinitionFormRenderer, {
AlmBindingDefinitionFormRendererProps
} from '../AlmBindingDefinitionFormRenderer';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
@@ -54,15 +54,15 @@ it('should correctly submit the form', () => {
expect(onSubmit).toBeCalled();
});

function shallowRender(props: Partial<AlmPRDecorationFormRendererProps> = {}) {
function shallowRender(props: Partial<AlmBindingDefinitionFormRendererProps> = {}) {
return shallow(
<AlmPRDecorationFormRenderer
<AlmBindingDefinitionFormRenderer
canSubmit={jest.fn()}
loading={false}
onSubmit={jest.fn()}
success={false}
{...props}>
{() => null}
</AlmPRDecorationFormRenderer>
</AlmBindingDefinitionFormRenderer>
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationTable-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionsTable-test.tsx Ver fichero

@@ -19,22 +19,24 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { ALM_KEYS } from '../../../../../types/alm-settings';
import AlmPRDecorationTable, { AlmPRDecorationTableProps } from '../AlmPRDecorationTable';
import { AlmKeys } from '../../../../../types/alm-settings';
import AlmBindingDefinitionsTable, {
AlmBindingDefinitionsTableProps
} from '../AlmBindingDefinitionsTable';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(
shallowRender({
additionalColumnsHeaders: ['additional1', 'additional2'],
alm: ALM_KEYS.GITHUB,
alm: AlmKeys.GitHub,
definitions: [
{ key: 'definition1', additionalColumns: ['def1-v1', 'def1-v2'] },
{ key: 'definition2', additionalColumns: ['def2-v1', 'def2-v2'] }
]
})
).toMatchSnapshot('additional columns');
expect(shallowRender({ alm: ALM_KEYS.GITHUB })).toMatchSnapshot('title adjusts for GitLab');
expect(shallowRender({ alm: AlmKeys.GitLab })).toMatchSnapshot('title adjusts for GitLab');
});

it('should correctly trigger create, delete, and edit', () => {
@@ -44,7 +46,7 @@ it('should correctly trigger create, delete, and edit', () => {

const wrapper = shallowRender({
additionalColumnsHeaders: [],
alm: ALM_KEYS.BITBUCKET,
alm: AlmKeys.Bitbucket,
definitions: [{ key: 'defKey', additionalColumns: [] }],
onCreate,
onDelete,
@@ -61,11 +63,11 @@ it('should correctly trigger create, delete, and edit', () => {
expect(onEdit).toBeCalledWith('defKey');
});

function shallowRender(props: Partial<AlmPRDecorationTableProps> = {}) {
function shallowRender(props: Partial<AlmBindingDefinitionsTableProps> = {}) {
return shallow(
<AlmPRDecorationTable
<AlmBindingDefinitionsTable
additionalColumnsHeaders={[]}
alm={ALM_KEYS.AZURE}
alm={AlmKeys.Azure}
definitions={[]}
onCreate={jest.fn()}
onDelete={jest.fn()}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PullRequestDecoration-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegration-test.tsx Ver fichero

@@ -24,11 +24,11 @@ import {
countBindedProjects,
deleteConfiguration,
getAlmDefinitions
} from '../../../../../api/almSettings';
import { ALM_KEYS } from '../../../../../types/alm-settings';
import PullRequestDecoration from '../PullRequestDecoration';
} from '../../../../../api/alm-settings';
import { AlmKeys } from '../../../../../types/alm-settings';
import { AlmIntegration } from '../AlmIntegration';

jest.mock('../../../../../api/almSettings', () => ({
jest.mock('../../../../../api/alm-settings', () => ({
countBindedProjects: jest.fn().mockResolvedValue(0),
deleteConfiguration: jest.fn().mockResolvedValue(undefined),
getAlmDefinitions: jest.fn().mockResolvedValue({ github: [] })
@@ -45,13 +45,13 @@ it('should render correctly', () => {
it('should handle alm selection', async () => {
const wrapper = shallowRender();

wrapper.setState({ currentAlm: ALM_KEYS.AZURE });
wrapper.setState({ currentAlm: AlmKeys.Azure });

wrapper.instance().handleSelectAlm(ALM_KEYS.GITHUB);
wrapper.instance().handleSelectAlm(AlmKeys.GitHub);

await waitAndUpdate(wrapper);

expect(wrapper.state().currentAlm).toBe(ALM_KEYS.GITHUB);
expect(wrapper.state().currentAlm).toBe(AlmKeys.GitHub);
});

it('should handle delete', async () => {
@@ -90,5 +90,5 @@ it('should fetch settings', async () => {
});

function shallowRender() {
return shallow<PullRequestDecoration>(<PullRequestDecoration />);
return shallow<AlmIntegration>(<AlmIntegration appState={{ branchesEnabled: true }} />);
}

+ 39
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationFeatureBox-test.tsx Ver fichero

@@ -0,0 +1,39 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 AlmIntegrationFeatureBox, {
AlmIntegrationFeatureBoxProps
} from '../AlmIntegrationFeatureBox';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default');
expect(shallowRender({ active: false })).toMatchSnapshot('inactive');
expect(shallowRender({ active: false, inactiveReason: "Bar is foo'd" })).toMatchSnapshot(
'inactive, with reason'
);
});

function shallowRender(props: Partial<AlmIntegrationFeatureBoxProps> = {}) {
return shallow<AlmIntegrationFeatureBoxProps>(
<AlmIntegrationFeatureBox active={true} description="Foo bar..." name="Foo" {...props} />
);
}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmIntegrationRenderer-test.tsx Ver fichero

@@ -19,24 +19,28 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { ALM_KEYS } from '../../../../../types/alm-settings';
import { PRDecorationTabs, PRDecorationTabsProps } from '../PRDecorationTabs';
import { AlmKeys } from '../../../../../types/alm-settings';
import AlmIntegrationRenderer, { AlmIntegrationRendererProps } from '../AlmIntegrationRenderer';

it('should render correctly', () => {
expect(shallowRender({ loading: true })).toMatchSnapshot();
expect(shallowRender({ definitionKeyForDeletion: 'keyToDelete' })).toMatchSnapshot();
expect(shallowRender({ currentAlm: ALM_KEYS.AZURE })).toMatchSnapshot();
expect(shallowRender({ currentAlm: ALM_KEYS.BITBUCKET })).toMatchSnapshot();
expect(shallowRender({ currentAlm: ALM_KEYS.GITLAB })).toMatchSnapshot();
expect(shallowRender()).toMatchSnapshot('default');
expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
expect(shallowRender({ definitionKeyForDeletion: 'keyToDelete' })).toMatchSnapshot(
'delete modal'
);
expect(shallowRender({ currentAlm: AlmKeys.Azure })).toMatchSnapshot('azure');
expect(shallowRender({ currentAlm: AlmKeys.Bitbucket })).toMatchSnapshot('bitbucket');
expect(shallowRender({ currentAlm: AlmKeys.GitLab })).toMatchSnapshot('gitlab');
});

function shallowRender(props: Partial<PRDecorationTabsProps> = {}) {
function shallowRender(props: Partial<AlmIntegrationRendererProps> = {}) {
return shallow(
<PRDecorationTabs
appState={{ multipleAlmEnabled: false }}
currentAlm={ALM_KEYS.GITHUB}
<AlmIntegrationRenderer
branchesEnabled={true}
currentAlm={AlmKeys.GitHub}
definitions={{ azure: [], bitbucket: [], github: [], gitlab: [] }}
loading={false}
multipleAlmEnabled={false}
onCancel={jest.fn()}
onConfirmDelete={jest.fn()}
onDelete={jest.fn()}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTab-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTab-test.tsx Ver fichero

@@ -21,7 +21,7 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings';
import { ALM_KEYS, AzureBindingDefinition } from '../../../../../types/alm-settings';
import { AlmKeys, AzureBindingDefinition } from '../../../../../types/alm-settings';
import AlmTab from '../AlmTab';

const DEFAULT_BINDING = {
@@ -93,7 +93,7 @@ it('should update config', async () => {
function shallowRender(props: Partial<AlmTab<AzureBindingDefinition>['props']> = {}) {
return shallow<AlmTab<AzureBindingDefinition>>(
<AlmTab
alm={ALM_KEYS.AZURE}
alm={AlmKeys.Azure}
createConfiguration={jest.fn()}
defaultBinding={DEFAULT_BINDING}
definitions={[mockAzureDefinition()]}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTabRenderer-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmTabRenderer-test.tsx Ver fichero

@@ -20,7 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings';
import { ALM_KEYS, GithubBindingDefinition } from '../../../../../types/alm-settings';
import { AlmKeys, GithubBindingDefinition } from '../../../../../types/alm-settings';
import AlmTabRenderer, { AlmTabRendererProps } from '../AlmTabRenderer';

it('should render correctly for multi-ALM binding', () => {
@@ -29,6 +29,22 @@ it('should render correctly for multi-ALM binding', () => {
expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot(
'editing a definition'
);
expect(
shallowRender({
features: [
{
active: true,
name: 'Foo',
description: 'Bar'
},
{
active: false,
name: 'Baz',
description: 'Bim'
}
]
})
).toMatchSnapshot('with features');
});

it('should render correctly for single-ALM binding', () => {
@@ -44,7 +60,7 @@ function shallowRender(props: Partial<AlmTabRendererProps<GithubBindingDefinitio
<AlmTabRenderer
additionalColumnsHeaders={['url', 'app_id']}
additionalColumnsKeys={['url', 'appId']}
alm={ALM_KEYS.GITHUB}
alm={AlmKeys.GitHub}
defaultBinding={mockGithubDefinition()}
definitions={[mockGithubDefinition()]}
form={jest.fn()}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureForm-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AzureForm-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTab-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AzureTab-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketForm-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketForm-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/BitbucketTab-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/DeleteModal-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/DeleteModal-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubForm-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GithubForm-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTab-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GithubTab-test.tsx Ver fichero

@@ -23,12 +23,14 @@ import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'
import GithubTab, { GithubTabProps } from '../GithubTab';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender()).toMatchSnapshot('with branch support');
expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support');
});

function shallowRender(props: Partial<GithubTabProps> = {}) {
return shallow(
<GithubTab
branchesEnabled={true}
definitions={[mockGithubDefinition()]}
loading={false}
multipleAlmEnabled={true}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabForm-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabForm-test.tsx Ver fichero


server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTab-test.tsx → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx Ver fichero

@@ -23,12 +23,14 @@ import { mockGitlabDefinition } from '../../../../../helpers/mocks/alm-settings'
import GitlabTab, { GitlabTabProps } from '../GitlabTab';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender()).toMatchSnapshot('with branch support');
expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support');
});

function shallowRender(props: Partial<GitlabTabProps> = {}) {
return shallow(
<GitlabTab
branchesEnabled={true}
definitions={[mockGitlabDefinition()]}
loading={false}
multipleAlmEnabled={true}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationForm-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionForm-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<AlmPRDecorationFormRenderer
<AlmBindingDefinitionFormRenderer
canSubmit={[Function]}
loading={false}
onCancel={[Function]}

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmDefinitionFormField-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap Ver fichero

@@ -8,7 +8,7 @@ exports[`should render correctly 1`] = `
className="display-flex-center"
htmlFor="key"
>
settings.pr_decoration.form.key
settings.almintegration.form.key
<em
className="mandatory spacer-right"
>
@@ -37,7 +37,7 @@ exports[`should render correctly 2`] = `
className="display-flex-center"
htmlFor="key"
>
settings.pr_decoration.form.key
settings.almintegration.form.key
<em
className="mandatory spacer-right"
>
@@ -70,7 +70,7 @@ exports[`should render correctly 3`] = `
className="display-flex-center"
htmlFor="key"
>
settings.pr_decoration.form.key
settings.almintegration.form.key
<em
className="mandatory spacer-right"
>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModalRenderer-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormModalRenderer-test.tsx.snap Ver fichero

@@ -2,7 +2,7 @@

exports[`should render correctly 1`] = `
<Modal
contentLabel="settings.pr_decoration.form.header.create"
contentLabel="settings.almintegration.form.header.create"
onRequestClose={[MockFunction]}
size="medium"
>
@@ -14,13 +14,21 @@ exports[`should render correctly 1`] = `
className="modal-head"
>
<h2>
settings.pr_decoration.form.header.create
settings.almintegration.form.header.create
</h2>
</div>
<div
className="modal-body modal-container"
>
<Component />
<div
className="display-flex-start"
>
<div
className="flex-1"
>
<Component />
</div>
</div>
</div>
<div
className="modal-foot"
@@ -33,7 +41,7 @@ exports[`should render correctly 1`] = `
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
settings.almintegration.form.save
</SubmitButton>
<ResetButtonLink
onClick={[Function]}
@@ -47,7 +55,7 @@ exports[`should render correctly 1`] = `

exports[`should render correctly 2`] = `
<Modal
contentLabel="settings.pr_decoration.form.header.create"
contentLabel="settings.almintegration.form.header.create"
onRequestClose={[MockFunction]}
size="medium"
>
@@ -59,21 +67,29 @@ exports[`should render correctly 2`] = `
className="modal-head"
>
<h2>
settings.pr_decoration.form.header.create
settings.almintegration.form.header.create
</h2>
</div>
<div
className="modal-body modal-container"
>
<Alert
className="big-spacer-bottom"
variant="info"
<div
className="display-flex-start"
>
<span>
Help me
</span>
</Alert>
<Component />
<div
className="flex-1"
>
<Component />
</div>
<Alert
className="huge-spacer-left flex-1"
variant="info"
>
<span>
Help me
</span>
</Alert>
</div>
</div>
<div
className="modal-foot"
@@ -86,7 +102,7 @@ exports[`should render correctly 2`] = `
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
settings.almintegration.form.save
</SubmitButton>
<ResetButtonLink
onClick={[Function]}

+ 161
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<div
className="display-flex-start"
>
<div
className="flex-1"
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.almintegration.form.save
</SubmitButton>
</div>
</div>
</div>
</form>
`;

exports[`should render correctly 2`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<div
className="display-flex-start"
>
<div
className="flex-1"
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.almintegration.form.save
</SubmitButton>
<ResetButtonLink
className="spacer-left"
onClick={[MockFunction]}
>
cancel
</ResetButtonLink>
</div>
</div>
</div>
</form>
`;

exports[`should render correctly 3`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<div
className="display-flex-start"
>
<div
className="flex-1"
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.almintegration.form.save
</SubmitButton>
<Button
className="button-red spacer-left"
disabled={false}
onClick={[MockFunction]}
>
delete
</Button>
</div>
</div>
</div>
</form>
`;

exports[`should render correctly 4`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<div
className="display-flex-start"
>
<div
className="flex-1"
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.almintegration.form.save
</SubmitButton>
<span
className="text-success spacer-left"
>
<AlertSuccessIcon
className="spacer-right"
/>
settings.state.saved
</span>
</div>
</div>
</div>
</form>
`;

exports[`should render correctly 5`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<div
className="display-flex-start"
>
<div
className="flex-1"
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.almintegration.form.save
</SubmitButton>
<DeferredSpinner
className="spacer-left"
timeout={100}
/>
</div>
</div>
</div>
</form>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationTable-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionsTable-test.tsx.snap Ver fichero

@@ -5,16 +5,16 @@ exports[`should render correctly 1`] = `
<div
className="spacer-top big-spacer-bottom display-flex-space-between"
>
<h4
className="display-inline"
<h2
className="settings-sub-category-name"
>
settings.pr_decoration.table.title
</h4>
settings.almintegration.table.title
</h2>
<Button
data-test="settings__alm-create"
onClick={[MockFunction]}
>
settings.pr_decoration.table.create
settings.almintegration.table.create
</Button>
</div>
<table
@@ -23,17 +23,17 @@ exports[`should render correctly 1`] = `
<thead>
<tr>
<th>
settings.pr_decoration.table.column.name
settings.almintegration.table.column.name
</th>
<th
className="action-small text-center"
>
settings.pr_decoration.table.column.edit
settings.almintegration.table.column.edit
</th>
<th
className="action text-center"
>
settings.pr_decoration.table.column.delete
settings.almintegration.table.column.delete
</th>
</tr>
</thead>
@@ -44,7 +44,7 @@ exports[`should render correctly 1`] = `
<td
colSpan={3}
>
settings.pr_decoration.table.empty.azure
settings.almintegration.table.empty.azure
</td>
</tr>
</tbody>
@@ -57,16 +57,16 @@ exports[`should render correctly: additional columns 1`] = `
<div
className="spacer-top big-spacer-bottom display-flex-space-between"
>
<h4
className="display-inline"
<h2
className="settings-sub-category-name"
>
settings.pr_decoration.table.title
</h4>
settings.almintegration.table.title
</h2>
<Button
data-test="settings__alm-create"
onClick={[MockFunction]}
>
settings.pr_decoration.table.create
settings.almintegration.table.create
</Button>
</div>
<table
@@ -75,7 +75,7 @@ exports[`should render correctly: additional columns 1`] = `
<thead>
<tr>
<th>
settings.pr_decoration.table.column.name
settings.almintegration.table.column.name
</th>
<th
key="additional1"
@@ -90,12 +90,12 @@ exports[`should render correctly: additional columns 1`] = `
<th
className="action-small text-center"
>
settings.pr_decoration.table.column.edit
settings.almintegration.table.column.edit
</th>
<th
className="action text-center"
>
settings.pr_decoration.table.column.delete
settings.almintegration.table.column.delete
</th>
</tr>
</thead>
@@ -196,16 +196,16 @@ exports[`should render correctly: title adjusts for GitLab 1`] = `
<div
className="spacer-top big-spacer-bottom display-flex-space-between"
>
<h4
className="display-inline"
<h2
className="settings-sub-category-name"
>
settings.pr_decoration.table.title
</h4>
settings.almintegration.table.title
</h2>
<Button
data-test="settings__alm-create"
onClick={[MockFunction]}
>
settings.pr_decoration.table.create
settings.almintegration.table.create
</Button>
</div>
<table
@@ -214,17 +214,17 @@ exports[`should render correctly: title adjusts for GitLab 1`] = `
<thead>
<tr>
<th>
settings.pr_decoration.table.column.name
settings.almintegration.table.column.name
</th>
<th
className="action-small text-center"
>
settings.pr_decoration.table.column.edit
settings.almintegration.table.column.edit
</th>
<th
className="action text-center"
>
settings.pr_decoration.table.column.delete
settings.almintegration.table.column.delete
</th>
</tr>
</thead>
@@ -235,7 +235,7 @@ exports[`should render correctly: title adjusts for GitLab 1`] = `
<td
colSpan={3}
>
settings.pr_decoration.table.empty.github
settings.almintegration.table.empty.gitlab
</td>
</tr>
</tbody>

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegration-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<Connect(withAppState(PRDecorationTabs))
<AlmIntegrationRenderer
branchesEnabled={true}
currentAlm="github"
definitions={
Object {
@@ -12,6 +13,7 @@ exports[`should render correctly 1`] = `
}
}
loading={true}
multipleAlmEnabled={false}
onCancel={[Function]}
onConfirmDelete={[Function]}
onDelete={[Function]}

+ 97
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationFeatureBox-test.tsx.snap Ver fichero

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

exports[`should render correctly: default 1`] = `
<div
className="boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered"
>
<CheckIcon
className="little-spacer-top spacer-right"
fill="#00aa00"
/>
<div
className="display-flex-column abs-height-100"
>
<h4>
Foo
</h4>
<div
className="spacer-top flex-1"
>
Foo bar...
</div>
<div
className="spacer-top"
>
<em
className="text-success"
>
settings.almintegration.feature.enabled
</em>
</div>
</div>
</div>
`;

exports[`should render correctly: inactive 1`] = `
<div
className="boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered bg-muted"
>
<ClearIcon
className="little-spacer-top spacer-right"
fill="#999"
/>
<div
className="display-flex-column abs-height-100"
>
<h4>
Foo
</h4>
<div
className="spacer-top flex-1"
>
Foo bar...
</div>
<div
className="spacer-top"
>
<em
className="text-muted"
>
settings.almintegration.feature.disabled
</em>
</div>
</div>
</div>
`;

exports[`should render correctly: inactive, with reason 1`] = `
<div
className="boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered bg-muted"
>
<ClearIcon
className="little-spacer-top spacer-right"
fill="#999"
/>
<div
className="display-flex-column abs-height-100"
>
<h4>
Foo
</h4>
<div
className="spacer-top flex-1"
>
Foo bar...
</div>
<div
className="spacer-top"
>
<em
className="text-muted"
>
Bar is foo'd
</em>
</div>
</div>
</div>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmIntegrationRenderer-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
exports[`should render correctly: azure 1`] = `
<Fragment>
<header
className="page-header"
@@ -8,17 +8,17 @@ exports[`should render correctly 1`] = `
<h1
className="page-title"
>
settings.pr_decoration.title
settings.almintegration.title
</h1>
</header>
<div
className="markdown small spacer-top big-spacer-bottom"
>
settings.pr_decoration.description
settings.almintegration.description
</div>
<BoxedTabs
onSelect={[MockFunction]}
selected="github"
selected="azure"
tabs={
Array [
Object {
@@ -44,6 +44,7 @@ exports[`should render correctly 1`] = `
/>
Bitbucket Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "azure",
@@ -56,6 +57,7 @@ exports[`should render correctly 1`] = `
/>
Azure DevOps Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "gitlab",
@@ -72,21 +74,17 @@ exports[`should render correctly 1`] = `
]
}
/>
<div
className="boxed-group boxed-group-inner"
>
<GithubTab
definitions={Array []}
loading={true}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</div>
<AzureTab
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</Fragment>
`;

exports[`should render correctly 2`] = `
exports[`should render correctly: bitbucket 1`] = `
<Fragment>
<header
className="page-header"
@@ -94,17 +92,17 @@ exports[`should render correctly 2`] = `
<h1
className="page-title"
>
settings.pr_decoration.title
settings.almintegration.title
</h1>
</header>
<div
className="markdown small spacer-top big-spacer-bottom"
>
settings.pr_decoration.description
settings.almintegration.description
</div>
<BoxedTabs
onSelect={[MockFunction]}
selected="github"
selected="bitbucket"
tabs={
Array [
Object {
@@ -130,6 +128,7 @@ exports[`should render correctly 2`] = `
/>
Bitbucket Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "azure",
@@ -142,6 +141,7 @@ exports[`should render correctly 2`] = `
/>
Azure DevOps Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "gitlab",
@@ -158,26 +158,17 @@ exports[`should render correctly 2`] = `
]
}
/>
<div
className="boxed-group boxed-group-inner"
>
<GithubTab
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</div>
<DeleteModal
id="keyToDelete"
onCancel={[MockFunction]}
<BitbucketTab
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</Fragment>
`;

exports[`should render correctly 3`] = `
exports[`should render correctly: default 1`] = `
<Fragment>
<header
className="page-header"
@@ -185,17 +176,17 @@ exports[`should render correctly 3`] = `
<h1
className="page-title"
>
settings.pr_decoration.title
settings.almintegration.title
</h1>
</header>
<div
className="markdown small spacer-top big-spacer-bottom"
>
settings.pr_decoration.description
settings.almintegration.description
</div>
<BoxedTabs
onSelect={[MockFunction]}
selected="azure"
selected="github"
tabs={
Array [
Object {
@@ -221,6 +212,7 @@ exports[`should render correctly 3`] = `
/>
Bitbucket Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "azure",
@@ -233,6 +225,7 @@ exports[`should render correctly 3`] = `
/>
Azure DevOps Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "gitlab",
@@ -249,21 +242,18 @@ exports[`should render correctly 3`] = `
]
}
/>
<div
className="boxed-group boxed-group-inner"
>
<AzureTab
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</div>
<GithubTab
branchesEnabled={true}
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</Fragment>
`;

exports[`should render correctly 4`] = `
exports[`should render correctly: delete modal 1`] = `
<Fragment>
<header
className="page-header"
@@ -271,17 +261,17 @@ exports[`should render correctly 4`] = `
<h1
className="page-title"
>
settings.pr_decoration.title
settings.almintegration.title
</h1>
</header>
<div
className="markdown small spacer-top big-spacer-bottom"
>
settings.pr_decoration.description
settings.almintegration.description
</div>
<BoxedTabs
onSelect={[MockFunction]}
selected="bitbucket"
selected="github"
tabs={
Array [
Object {
@@ -307,6 +297,7 @@ exports[`should render correctly 4`] = `
/>
Bitbucket Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "azure",
@@ -319,6 +310,7 @@ exports[`should render correctly 4`] = `
/>
Azure DevOps Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "gitlab",
@@ -335,21 +327,23 @@ exports[`should render correctly 4`] = `
]
}
/>
<div
className="boxed-group boxed-group-inner"
>
<BitbucketTab
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</div>
<GithubTab
branchesEnabled={true}
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
<DeleteModal
id="keyToDelete"
onCancel={[MockFunction]}
onDelete={[MockFunction]}
/>
</Fragment>
`;

exports[`should render correctly 5`] = `
exports[`should render correctly: gitlab 1`] = `
<Fragment>
<header
className="page-header"
@@ -357,13 +351,13 @@ exports[`should render correctly 5`] = `
<h1
className="page-title"
>
settings.pr_decoration.title
settings.almintegration.title
</h1>
</header>
<div
className="markdown small spacer-top big-spacer-bottom"
>
settings.pr_decoration.description
settings.almintegration.description
</div>
<BoxedTabs
onSelect={[MockFunction]}
@@ -393,6 +387,7 @@ exports[`should render correctly 5`] = `
/>
Bitbucket Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "azure",
@@ -405,6 +400,7 @@ exports[`should render correctly 5`] = `
/>
Azure DevOps Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "gitlab",
@@ -421,16 +417,98 @@ exports[`should render correctly 5`] = `
]
}
/>
<GitlabTab
branchesEnabled={true}
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</Fragment>
`;

exports[`should render correctly: loading 1`] = `
<Fragment>
<header
className="page-header"
>
<h1
className="page-title"
>
settings.almintegration.title
</h1>
</header>
<div
className="boxed-group boxed-group-inner"
className="markdown small spacer-top big-spacer-bottom"
>
<GitlabTab
definitions={Array []}
loading={false}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
settings.almintegration.description
</div>
<BoxedTabs
onSelect={[MockFunction]}
selected="github"
tabs={
Array [
Object {
"key": "github",
"label": <React.Fragment>
<img
alt="github"
className="spacer-right"
height={16}
src="/images/alm/github.svg"
/>
GitHub
</React.Fragment>,
},
Object {
"key": "bitbucket",
"label": <React.Fragment>
<img
alt="bitbucket"
className="spacer-right"
height={16}
src="/images/alm/bitbucket.svg"
/>
Bitbucket Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "azure",
"label": <React.Fragment>
<img
alt="azure"
className="spacer-right"
height={16}
src="/images/alm/azure.svg"
/>
Azure DevOps Server
</React.Fragment>,
"requiresBranchesEnabled": true,
},
Object {
"key": "gitlab",
"label": <React.Fragment>
<img
alt="gitlab"
className="spacer-right"
height={16}
src="/images/alm/gitlab.svg"
/>
GitLab
</React.Fragment>,
},
]
}
/>
<GithubTab
branchesEnabled={true}
definitions={Array []}
loading={true}
multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
</Fragment>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTab-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTab-test.tsx.snap Ver fichero


+ 334
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap Ver fichero

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

exports[`should render correctly for multi-ALM binding: editing a definition 1`] = `
<div
className="big-padded"
>
<DeferredSpinner
loading={false}
timeout={100}
>
<AlmBindingDefinitionsTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
<AlmBindingDefinitionForm
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.almintegration.github.info"
id="settings.almintegration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
onCancel={[MockFunction]}
onSubmit={[MockFunction]}
showInModal={true}
>
<Component />
</AlmBindingDefinitionForm>
</DeferredSpinner>
</div>
`;

exports[`should render correctly for multi-ALM binding: loaded 1`] = `
<div
className="big-padded"
>
<DeferredSpinner
loading={false}
timeout={100}
>
<AlmBindingDefinitionsTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
</DeferredSpinner>
</div>
`;

exports[`should render correctly for multi-ALM binding: loading 1`] = `
<div
className="big-padded"
>
<DeferredSpinner
loading={true}
timeout={100}
>
<AlmBindingDefinitionsTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
</DeferredSpinner>
</div>
`;

exports[`should render correctly for multi-ALM binding: with features 1`] = `
<div
className="big-padded"
>
<DeferredSpinner
loading={false}
timeout={100}
>
<AlmBindingDefinitionsTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
</DeferredSpinner>
<div
className="big-spacer-top big-padded-top bordered-top"
>
<h3
className="big-spacer-bottom"
>
settings.almintegration.features
</h3>
<div
className="display-flex-wrap"
>
<AlmIntegrationFeatureBox
active={true}
description="Bar"
key="0"
name="Foo"
/>
<AlmIntegrationFeatureBox
active={false}
description="Bim"
key="1"
name="Baz"
/>
</div>
</div>
</div>
`;

exports[`should render correctly for single-ALM binding 1`] = `
<div
className="big-padded"
>
<AlmBindingDefinitionForm
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.almintegration.github.info"
id="settings.almintegration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
hideKeyField={true}
loading={true}
onCancel={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
onSubmit={[MockFunction]}
readOnly={true}
success={false}
>
<Component />
</AlmBindingDefinitionForm>
</div>
`;

exports[`should render correctly for single-ALM binding 2`] = `
<div
className="big-padded"
>
<AlmBindingDefinitionForm
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.almintegration.github.info"
id="settings.almintegration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
hideKeyField={true}
loading={false}
onCancel={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
onSubmit={[MockFunction]}
readOnly={true}
success={false}
>
<Component />
</AlmBindingDefinitionForm>
</div>
`;

exports[`should render correctly for single-ALM binding 3`] = `
<div
className="big-padded"
>
<AlmBindingDefinitionForm
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.almintegration.github.info"
id="settings.almintegration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
hideKeyField={true}
loading={false}
onCancel={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
onSubmit={[MockFunction]}
readOnly={true}
success={false}
>
<Component />
</AlmBindingDefinitionForm>
</div>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureForm-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap Ver fichero

@@ -2,16 +2,16 @@

exports[`should render correctly 1`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.azure.help"
help="settings.almintegration.form.name.azure.help"
id="name.azure"
onFieldChange={[MockFunction]}
propKey="key"
value=""
/>
<AlmDefinitionFormField
help="settings.pr_decoration.form.personal_access_token.azure.help"
<AlmBindingDefinitionFormField
help="settings.almintegration.form.personal_access_token.azure.help"
id="personal_access_token"
isTextArea={true}
onFieldChange={[MockFunction]}
@@ -23,16 +23,16 @@ exports[`should render correctly 1`] = `

exports[`should render correctly 2`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.azure.help"
help="settings.almintegration.form.name.azure.help"
id="name.azure"
onFieldChange={[MockFunction]}
propKey="key"
value="key"
/>
<AlmDefinitionFormField
help="settings.pr_decoration.form.personal_access_token.azure.help"
<AlmBindingDefinitionFormField
help="settings.almintegration.form.personal_access_token.azure.help"
id="personal_access_token"
isTextArea={true}
onFieldChange={[MockFunction]}

+ 42
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureTab-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<div
className="bordered"
>
<AlmTab
alm="azure"
createConfiguration={[Function]}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
}
}
definitions={
Array [
Object {
"key": "key",
"personalAccessToken": "asdf1234",
},
]
}
features={
Array [
Object {
"active": true,
"description": "settings.almintegration.feature.pr_decoration.description",
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding",
"name": "settings.almintegration.feature.pr_decoration.title",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
</div>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap Ver fichero

@@ -2,20 +2,20 @@

exports[`should render correctly 1`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.bitbucket.help"
help="settings.almintegration.form.name.bitbucket.help"
id="name.bitbucket"
maxLength={100}
onFieldChange={[MockFunction]}
propKey="key"
value=""
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
help={
<FormattedMessage
defaultMessage="settings.pr_decoration.form.url.bitbucket.help"
id="settings.pr_decoration.form.url.bitbucket.help"
defaultMessage="settings.almintegration.form.url.bitbucket.help"
id="settings.almintegration.form.url.bitbucket.help"
values={
Object {
"example": "https://bitbucket-server.your-company.com",
@@ -29,7 +29,7 @@ exports[`should render correctly 1`] = `
propKey="url"
value=""
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="personal_access_token"
isTextArea={true}
onFieldChange={[MockFunction]}
@@ -41,20 +41,20 @@ exports[`should render correctly 1`] = `

exports[`should render correctly 2`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.bitbucket.help"
help="settings.almintegration.form.name.bitbucket.help"
id="name.bitbucket"
maxLength={100}
onFieldChange={[MockFunction]}
propKey="key"
value="key"
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
help={
<FormattedMessage
defaultMessage="settings.pr_decoration.form.url.bitbucket.help"
id="settings.pr_decoration.form.url.bitbucket.help"
defaultMessage="settings.almintegration.form.url.bitbucket.help"
id="settings.almintegration.form.url.bitbucket.help"
values={
Object {
"example": "https://bitbucket-server.your-company.com",
@@ -68,7 +68,7 @@ exports[`should render correctly 2`] = `
propKey="url"
value="http://bbs.enterprise.com"
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="personal_access_token"
isTextArea={true}
onFieldChange={[MockFunction]}

+ 112
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<div
className="bordered"
>
<AlmTab
additionalColumnsHeaders={
Array [
"settings.almintegration.table.column.bitbucket.url",
]
}
additionalColumnsKeys={
Array [
"url",
]
}
additionalTableInfo={
<Alert
className="big-spacer-bottom width-50"
variant="info"
>
<FormattedMessage
defaultMessage="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances"
id="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances"
values={
Object {
"feature": <em>
settings.almintegration.feature.alm_repo_import.title
</em>,
}
}
/>
</Alert>
}
alm="bitbucket"
createConfiguration={[Function]}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
"url": "",
}
}
definitions={
Array [
Object {
"key": "key",
"personalAccessToken": "asdf1234",
"url": "http://bbs.enterprise.com",
},
]
}
features={
Array [
Object {
"active": true,
"description": "settings.almintegration.feature.pr_decoration.description",
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding",
"name": "settings.almintegration.feature.pr_decoration.title",
},
Object {
"active": true,
"description": "settings.almintegration.feature.alm_repo_import.description",
"inactiveReason": "onboarding.create_project.too_many_bbs_instances_X.1",
"name": "settings.almintegration.feature.alm_repo_import.title",
},
]
}
form={[Function]}
help={
<React.Fragment>
<h3>
onboarding.create_project.pat_help.title
</h3>
<p
className="big-spacer-top"
>
settings.almintegration.bitbucket.help_1
</p>
<ul
className="big-spacer-top list-styled"
>
<li>
settings.almintegration.bitbucket.help_2
</li>
<li>
settings.almintegration.bitbucket.help_3
</li>
</ul>
<p
className="big-spacer-top big-spacer-bottom"
>
<Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>
</p>
</React.Fragment>
}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
</div>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/DeleteModal-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/DeleteModal-test.tsx.snap Ver fichero

@@ -4,7 +4,7 @@ exports[`should render correctly 1`] = `
<ConfirmModal
confirmButtonText="delete"
confirmData="1"
header="settings.pr_decoration.delete.header"
header="settings.almintegration.delete.header"
isDestructive={true}
onClose={[MockFunction]}
onConfirm={[MockFunction]}
@@ -13,8 +13,8 @@ exports[`should render correctly 1`] = `
className="spacer-bottom"
>
<FormattedMessage
defaultMessage="settings.pr_decoration.delete.message"
id="settings.pr_decoration.delete.message"
defaultMessage="settings.almintegration.delete.message"
id="settings.almintegration.delete.message"
values={
Object {
"id": <b>
@@ -25,7 +25,7 @@ exports[`should render correctly 1`] = `
/>
</p>
<p>
settings.pr_decoration.delete.info.4
settings.almintegration.delete.info.4
</p>
</ConfirmModal>
@@ -35,7 +35,7 @@ exports[`should render correctly 2`] = `
<ConfirmModal
confirmButtonText="delete"
confirmData="1"
header="settings.pr_decoration.delete.header"
header="settings.almintegration.delete.header"
isDestructive={true}
onClose={[MockFunction]}
onConfirm={[MockFunction]}
@@ -44,8 +44,8 @@ exports[`should render correctly 2`] = `
className="spacer-bottom"
>
<FormattedMessage
defaultMessage="settings.pr_decoration.delete.message"
id="settings.pr_decoration.delete.message"
defaultMessage="settings.almintegration.delete.message"
id="settings.almintegration.delete.message"
values={
Object {
"id": <b>
@@ -56,7 +56,7 @@ exports[`should render correctly 2`] = `
/>
</p>
<p>
settings.pr_decoration.delete.no_info
settings.almintegration.delete.no_info
</p>
</ConfirmModal>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubForm-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap Ver fichero

@@ -2,25 +2,25 @@

exports[`should render correctly 1`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.github.help"
help="settings.almintegration.form.name.github.help"
id="name.github"
onFieldChange={[MockFunction]}
propKey="key"
value=""
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
help={
<React.Fragment>
settings.pr_decoration.form.url.github.help1
settings.almintegration.form.url.github.help1
<br />
<em>
https://github.company.com/api/v3
</em>
<br />
<br />
settings.pr_decoration.form.url.github.help2
settings.almintegration.form.url.github.help2
<br />
<em>
https://api.github.com/
@@ -33,14 +33,14 @@ exports[`should render correctly 1`] = `
propKey="url"
value=""
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="app_id"
maxLength={80}
onFieldChange={[MockFunction]}
propKey="appId"
value=""
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="private_key"
isTextArea={true}
onFieldChange={[MockFunction]}
@@ -52,25 +52,25 @@ exports[`should render correctly 1`] = `

exports[`should render correctly 2`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.github.help"
help="settings.almintegration.form.name.github.help"
id="name.github"
onFieldChange={[MockFunction]}
propKey="key"
value="key"
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
help={
<React.Fragment>
settings.pr_decoration.form.url.github.help1
settings.almintegration.form.url.github.help1
<br />
<em>
https://github.company.com/api/v3
</em>
<br />
<br />
settings.pr_decoration.form.url.github.help2
settings.almintegration.form.url.github.help2
<br />
<em>
https://api.github.com/
@@ -83,14 +83,14 @@ exports[`should render correctly 2`] = `
propKey="url"
value="http://github.enterprise.com"
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="app_id"
maxLength={80}
onFieldChange={[MockFunction]}
propKey="appId"
value="123456"
/>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
id="private_key"
isTextArea={true}
onFieldChange={[MockFunction]}

+ 84
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubTab-test.tsx.snap Ver fichero

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

exports[`should render correctly: with branch support 1`] = `
<div
className="bordered"
>
<AlmTab
additionalColumnsHeaders={
Array [
"settings.almintegration.table.column.github.url",
"settings.almintegration.table.column.app_id",
]
}
additionalColumnsKeys={
Array [
"appId",
"url",
]
}
alm="github"
createConfiguration={[Function]}
defaultBinding={
Object {
"appId": "",
"key": "",
"privateKey": "",
"url": "",
}
}
definitions={
Array [
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
},
]
}
features={
Array [
Object {
"active": true,
"description": "settings.almintegration.feature.pr_decoration.description",
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding",
"name": "settings.almintegration.feature.pr_decoration.title",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
<div
className="huge-spacer-top huge-spacer-bottom bordered-top"
/>
<div
className="big-padded"
>
<Connect(SubCategoryDefinitionsList)
category="almintegration"
subCategory="github"
/>
</div>
</div>
`;

exports[`should render correctly: without branch support 1`] = `
<div
className="bordered"
>
<div
className="big-padded"
>
<Connect(SubCategoryDefinitionsList)
category="almintegration"
subCategory="github"
/>
</div>
</div>
`;

server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabForm-test.tsx.snap → server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap Ver fichero

@@ -2,16 +2,16 @@

exports[`should render correctly 1`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.gitlab.help"
help="settings.almintegration.form.name.gitlab.help"
id="name.gitlab"
onFieldChange={[MockFunction]}
propKey="key"
value=""
/>
<AlmDefinitionFormField
help="settings.pr_decoration.form.personal_access_token.gitlab.help"
<AlmBindingDefinitionFormField
help="settings.almintegration.form.personal_access_token.gitlab.help"
id="personal_access_token"
isTextArea={true}
onFieldChange={[MockFunction]}
@@ -23,16 +23,16 @@ exports[`should render correctly 1`] = `

exports[`should render correctly 2`] = `
<Fragment>
<AlmDefinitionFormField
<AlmBindingDefinitionFormField
autoFocus={true}
help="settings.pr_decoration.form.name.gitlab.help"
help="settings.almintegration.form.name.gitlab.help"
id="name.gitlab"
onFieldChange={[MockFunction]}
propKey="key"
value="foo"
/>
<AlmDefinitionFormField
help="settings.pr_decoration.form.personal_access_token.gitlab.help"
<AlmBindingDefinitionFormField
help="settings.almintegration.form.personal_access_token.gitlab.help"
id="personal_access_token"
isTextArea={true}
onFieldChange={[MockFunction]}

+ 68
- 0
server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap Ver fichero

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

exports[`should render correctly: with branch support 1`] = `
<div
className="bordered"
>
<AlmTab
alm="gitlab"
createConfiguration={[Function]}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
}
}
definitions={
Array [
Object {
"key": "foo",
"personalAccessToken": "foobar",
},
]
}
features={
Array [
Object {
"active": true,
"description": "settings.almintegration.feature.mr_decoration.description",
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding",
"name": "settings.almintegration.feature.mr_decoration.title",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
<div
className="huge-spacer-top huge-spacer-bottom bordered-top"
/>
<div
className="big-padded"
>
<Connect(SubCategoryDefinitionsList)
category="almintegration"
subCategory="gitlab"
/>
</div>
</div>
`;

exports[`should render correctly: without branch support 1`] = `
<div
className="bordered"
>
<div
className="big-padded"
>
<Connect(SubCategoryDefinitionsList)
category="almintegration"
subCategory="gitlab"
/>
</div>
</div>
`;

+ 0
- 136
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTabRenderer.tsx Ver fichero

@@ -1,136 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 { FormattedMessage } from 'react-intl';
import { Link } from 'react-router';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
import AlmPRDecorationForm, { AlmPRDecorationFormChildrenProps } from './AlmPRDecorationForm';
import AlmPRDecorationTable from './AlmPRDecorationTable';

export interface AlmTabRendererProps<B> {
additionalColumnsHeaders: string[];
additionalColumnsKeys: Array<keyof B>;
alm: ALM_KEYS;
editedDefinition?: B;
defaultBinding: B;
definitions: B[];
form: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode;
loading: boolean;
multipleAlmEnabled: boolean;
onCancel: () => void;
onCreate: () => void;
onDelete: (definitionKey: string) => void;
onEdit: (definitionKey: string) => void;
onSubmit: (config: B, originalKey: string) => void;
success: boolean;
}

export default function AlmTabRenderer<B extends AlmSettingsBinding>(
props: AlmTabRendererProps<B>
) {
const {
additionalColumnsHeaders,
additionalColumnsKeys,
alm,
defaultBinding,
definitions,
editedDefinition,
form,
loading,
multipleAlmEnabled,
success
} = props;

let definition: B | undefined;
let mappedDefinitions: Array<{ key: string; additionalColumns: string[] }> = [];
let showEdit: boolean | undefined;

if (!multipleAlmEnabled) {
definition = editedDefinition;
if (definition === undefined && definitions.length > 0) {
definition = definitions[0];
}
showEdit = definition && editedDefinition === undefined;
} else {
mappedDefinitions = definitions.map(({ key, ...properties }) => {
const additionalColumns = additionalColumnsKeys.map(k => (properties as any)[k]);
return {
key,
additionalColumns
};
});
}

const help = (
<FormattedMessage
defaultMessage={translate(`settings.pr_decoration.${alm}.info`)}
id={`settings.pr_decoration.${alm}.info`}
values={{
link: (
<Link target="_blank" to="/documentation/analysis/pr-decoration/">
{translate('learn_more')}
</Link>
)
}}
/>
);

return multipleAlmEnabled ? (
<DeferredSpinner loading={loading}>
<AlmPRDecorationTable
additionalColumnsHeaders={additionalColumnsHeaders}
alm={alm}
definitions={mappedDefinitions}
onCreate={props.onCreate}
onDelete={props.onDelete}
onEdit={props.onEdit}
/>

{editedDefinition && (
<AlmPRDecorationForm
alm={alm}
bindingDefinition={editedDefinition}
help={help}
onCancel={props.onCancel}
onSubmit={props.onSubmit}
showInModal={true}>
{form}
</AlmPRDecorationForm>
)}
</DeferredSpinner>
) : (
<AlmPRDecorationForm
alm={alm}
bindingDefinition={definition || defaultBinding}
help={help}
hideKeyField={true}
loading={loading}
onCancel={props.onCancel}
onDelete={definition ? props.onDelete : undefined}
onEdit={showEdit ? props.onEdit : undefined}
onSubmit={props.onSubmit}
readOnly={showEdit}
success={success}>
{form}
</AlmPRDecorationForm>
);
}

+ 0
- 57
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx Ver fichero

@@ -1,57 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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';
import {
createBitbucketConfiguration,
updateBitbucketConfiguration
} from '../../../../api/almSettings';
import { ALM_KEYS, BitbucketBindingDefinition } from '../../../../types/alm-settings';
import AlmTab from './AlmTab';
import BitbucketForm from './BitbucketForm';

export interface BitbucketTabProps {
definitions: BitbucketBindingDefinition[];
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}

export default function BitbucketTab(props: BitbucketTabProps) {
const { multipleAlmEnabled, definitions, loading } = props;

return (
<AlmTab
additionalColumnsHeaders={[translate('settings.pr_decoration.table.column.bitbucket.url')]}
additionalColumnsKeys={['url']}
alm={ALM_KEYS.BITBUCKET}
createConfiguration={createBitbucketConfiguration}
defaultBinding={{ key: '', url: '', personalAccessToken: '' }}
definitions={definitions}
form={childProps => <BitbucketForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateBitbucketConfiguration}
/>
);
}

+ 0
- 57
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx Ver fichero

@@ -1,57 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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';
import { createGithubConfiguration, updateGithubConfiguration } from '../../../../api/almSettings';
import { ALM_KEYS, GithubBindingDefinition } from '../../../../types/alm-settings';
import AlmTab from './AlmTab';
import GithubForm from './GithubForm';

export interface GithubTabProps {
definitions: GithubBindingDefinition[];
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}

export default function GithubTab(props: GithubTabProps) {
const { multipleAlmEnabled, definitions, loading } = props;

return (
<AlmTab
additionalColumnsHeaders={[
translate('settings.pr_decoration.table.column.github.url'),
translate('settings.pr_decoration.table.column.app_id')
]}
additionalColumnsKeys={['appId', 'url']}
alm={ALM_KEYS.GITHUB}
createConfiguration={createGithubConfiguration}
defaultBinding={{ key: '', appId: '', url: '', privateKey: '' }}
definitions={definitions}
form={childProps => <GithubForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGithubConfiguration}
/>
);
}

+ 0
- 51
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx Ver fichero

@@ -1,51 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 { createGitlabConfiguration, updateGitlabConfiguration } from '../../../../api/almSettings';
import { ALM_KEYS, GitlabBindingDefinition } from '../../../../types/alm-settings';
import AlmTab from './AlmTab';
import GitlabForm from './GitlabForm';

export interface GitlabTabProps {
definitions: GitlabBindingDefinition[];
loading: boolean;
multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}

export default function GitlabTab(props: GitlabTabProps) {
const { multipleAlmEnabled, definitions, loading } = props;

return (
<AlmTab
alm={ALM_KEYS.GITLAB}
createConfiguration={createGitlabConfiguration}
defaultBinding={{ key: '', personalAccessToken: '' }}
definitions={definitions}
form={childProps => <GitlabForm {...childProps} />}
loading={loading}
multipleAlmEnabled={multipleAlmEnabled}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
updateConfiguration={updateGitlabConfiguration}
/>
);
}

+ 0
- 186
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx Ver fichero

@@ -1,186 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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 BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
import { withAppState } from '../../../../components/hoc/withAppState';
import { AlmSettingsBindingDefinitions, ALM_KEYS } from '../../../../types/alm-settings';
import AzureTab from './AzureTab';
import BitbucketTab from './BitbucketTab';
import DeleteModal from './DeleteModal';
import GithubTab from './GithubTab';
import GitlabTab from './GitlabTab';

export interface PRDecorationTabsProps {
appState: Pick<T.AppState, 'multipleAlmEnabled'>;
currentAlm: ALM_KEYS;
definitionKeyForDeletion?: string;
definitions: AlmSettingsBindingDefinitions;
loading: boolean;
onCancel: () => void;
onConfirmDelete: (definitionKey: string) => void;
onDelete: (definitionKey: string) => void;
onSelectAlm: (alm: ALM_KEYS) => void;
onUpdateDefinitions: () => void;
projectCount?: number;
}

export const almName = {
[ALM_KEYS.AZURE]: 'Azure DevOps Server',
[ALM_KEYS.BITBUCKET]: 'Bitbucket Server',
[ALM_KEYS.GITHUB]: 'GitHub',
[ALM_KEYS.GITLAB]: 'GitLab'
};

export function PRDecorationTabs(props: PRDecorationTabsProps) {
const {
appState: { multipleAlmEnabled },
definitionKeyForDeletion,
definitions,
currentAlm,
loading,
projectCount
} = props;

return (
<>
<header className="page-header">
<h1 className="page-title">{translate('settings.pr_decoration.title')}</h1>
</header>

<div className="markdown small spacer-top big-spacer-bottom">
{translate('settings.pr_decoration.description')}
</div>
<BoxedTabs
onSelect={props.onSelectAlm}
selected={currentAlm}
tabs={[
{
key: ALM_KEYS.GITHUB,
label: (
<>
<img
alt="github"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/github.svg`}
/>
{almName[ALM_KEYS.GITHUB]}
</>
)
},
{
key: ALM_KEYS.BITBUCKET,
label: (
<>
<img
alt="bitbucket"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/bitbucket.svg`}
/>
{almName[ALM_KEYS.BITBUCKET]}
</>
)
},
{
key: ALM_KEYS.AZURE,
label: (
<>
<img
alt="azure"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/azure.svg`}
/>
{almName[ALM_KEYS.AZURE]}
</>
)
},
{
key: ALM_KEYS.GITLAB,
label: (
<>
<img
alt="gitlab"
className="spacer-right"
height={16}
src={`${getBaseUrl()}/images/alm/gitlab.svg`}
/>
{almName[ALM_KEYS.GITLAB]}
</>
)
}
]}
/>

<div className="boxed-group boxed-group-inner">
{currentAlm === ALM_KEYS.AZURE && (
<AzureTab
definitions={definitions.azure}
loading={loading}
multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
{currentAlm === ALM_KEYS.BITBUCKET && (
<BitbucketTab
definitions={definitions.bitbucket}
loading={loading}
multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
{currentAlm === ALM_KEYS.GITHUB && (
<GithubTab
definitions={definitions.github}
loading={loading}
multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
{currentAlm === ALM_KEYS.GITLAB && (
<GitlabTab
definitions={definitions.gitlab}
loading={loading}
multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
)}
</div>

{definitionKeyForDeletion && (
<DeleteModal
id={definitionKeyForDeletion}
onCancel={props.onCancel}
onDelete={props.onConfirmDelete}
projectCount={projectCount}
/>
)}
</>
);
}

export default withAppState(PRDecorationTabs);

+ 0
- 121
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormRenderer-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
</SubmitButton>
</div>
</form>
`;

exports[`should render correctly 2`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
</SubmitButton>
<ResetButtonLink
className="spacer-left"
onClick={[MockFunction]}
>
cancel
</ResetButtonLink>
</div>
</form>
`;

exports[`should render correctly 3`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
</SubmitButton>
<Button
className="button-red spacer-left"
disabled={false}
onClick={[MockFunction]}
>
delete
</Button>
</div>
</form>
`;

exports[`should render correctly 4`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
</SubmitButton>
<span
className="text-success spacer-left"
>
<AlertSuccessIcon
className="spacer-right"
/>
settings.state.saved
</span>
</div>
</form>
`;

exports[`should render correctly 5`] = `
<form
className="views-form"
data-test="settings__alm-form"
onSubmit={[Function]}
>
<Component />
<div
className="display-flex-center"
>
<SubmitButton
disabled={true}
>
settings.pr_decoration.form.save
</SubmitButton>
<DeferredSpinner
className="spacer-left"
timeout={100}
/>
</div>
</form>
`;

+ 0
- 254
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap Ver fichero

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

exports[`should render correctly for multi-ALM binding: editing a definition 1`] = `
<DeferredSpinner
loading={false}
timeout={100}
>
<AlmPRDecorationTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
<AlmPRDecorationForm
alm="github"
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.pr_decoration.github.info"
id="settings.pr_decoration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
onCancel={[MockFunction]}
onSubmit={[MockFunction]}
showInModal={true}
>
<Component />
</AlmPRDecorationForm>
</DeferredSpinner>
`;

exports[`should render correctly for multi-ALM binding: loaded 1`] = `
<DeferredSpinner
loading={false}
timeout={100}
>
<AlmPRDecorationTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
</DeferredSpinner>
`;

exports[`should render correctly for multi-ALM binding: loading 1`] = `
<DeferredSpinner
loading={true}
timeout={100}
>
<AlmPRDecorationTable
additionalColumnsHeaders={
Array [
"url",
"app_id",
]
}
alm="github"
definitions={
Array [
Object {
"additionalColumns": Array [
"http://github.enterprise.com",
"123456",
],
"key": "key",
},
]
}
onCreate={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
/>
</DeferredSpinner>
`;

exports[`should render correctly for single-ALM binding 1`] = `
<AlmPRDecorationForm
alm="github"
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.pr_decoration.github.info"
id="settings.pr_decoration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
hideKeyField={true}
loading={true}
onCancel={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
onSubmit={[MockFunction]}
readOnly={true}
success={false}
>
<Component />
</AlmPRDecorationForm>
`;

exports[`should render correctly for single-ALM binding 2`] = `
<AlmPRDecorationForm
alm="github"
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.pr_decoration.github.info"
id="settings.pr_decoration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
hideKeyField={true}
loading={false}
onCancel={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
onSubmit={[MockFunction]}
readOnly={true}
success={false}
>
<Component />
</AlmPRDecorationForm>
`;

exports[`should render correctly for single-ALM binding 3`] = `
<AlmPRDecorationForm
alm="github"
bindingDefinition={
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
}
}
help={
<FormattedMessage
defaultMessage="settings.pr_decoration.github.info"
id="settings.pr_decoration.github.info"
values={
Object {
"link": <Link
onlyActiveOnIndex={false}
style={Object {}}
target="_blank"
to="/documentation/analysis/pr-decoration/"
>
learn_more
</Link>,
}
}
/>
}
hideKeyField={true}
loading={false}
onCancel={[MockFunction]}
onDelete={[MockFunction]}
onEdit={[MockFunction]}
onSubmit={[MockFunction]}
readOnly={true}
success={false}
>
<Component />
</AlmPRDecorationForm>
`;

+ 0
- 28
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<AlmTab
alm="azure"
createConfiguration={[Function]}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
}
}
definitions={
Array [
Object {
"key": "key",
"personalAccessToken": "asdf1234",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
`;

+ 0
- 40
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<AlmTab
additionalColumnsHeaders={
Array [
"settings.pr_decoration.table.column.bitbucket.url",
]
}
additionalColumnsKeys={
Array [
"url",
]
}
alm="bitbucket"
createConfiguration={[Function]}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
"url": "",
}
}
definitions={
Array [
Object {
"key": "key",
"personalAccessToken": "asdf1234",
"url": "http://bbs.enterprise.com",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
`;

+ 0
- 44
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<AlmTab
additionalColumnsHeaders={
Array [
"settings.pr_decoration.table.column.github.url",
"settings.pr_decoration.table.column.app_id",
]
}
additionalColumnsKeys={
Array [
"appId",
"url",
]
}
alm="github"
createConfiguration={[Function]}
defaultBinding={
Object {
"appId": "",
"key": "",
"privateKey": "",
"url": "",
}
}
definitions={
Array [
Object {
"appId": "123456",
"key": "key",
"privateKey": "asdf1234",
"url": "http://github.enterprise.com",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
`;

+ 0
- 28
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap Ver fichero

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

exports[`should render correctly 1`] = `
<AlmTab
alm="gitlab"
createConfiguration={[Function]}
defaultBinding={
Object {
"key": "",
"personalAccessToken": "",
}
}
definitions={
Array [
Object {
"key": "foo",
"personalAccessToken": "foobar",
},
]
}
form={[Function]}
loading={false}
multipleAlmEnabled={true}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
updateConfiguration={[Function]}
/>
`;

+ 12
- 12
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx Ver fichero

@@ -26,9 +26,9 @@ import {
setProjectBitbucketBinding,
setProjectGithubBinding,
setProjectGitlabBinding
} from '../../../../api/almSettings';
} from '../../../../api/alm-settings';
import throwGlobalError from '../../../../app/utils/throwGlobalError';
import { AlmSettingsInstance, ALM_KEYS, ProjectAlmBinding } from '../../../../types/alm-settings';
import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings';
import PRDecorationBindingRenderer from './PRDecorationBindingRenderer';

interface Props {
@@ -45,11 +45,11 @@ interface State {
success: boolean;
}

const FIELDS_BY_ALM: { [almKey in ALM_KEYS]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>> } = {
[ALM_KEYS.AZURE]: [],
[ALM_KEYS.BITBUCKET]: ['repository', 'slug'],
[ALM_KEYS.GITHUB]: ['repository'],
[ALM_KEYS.GITLAB]: []
const FIELDS_BY_ALM: { [almKey in AlmKeys]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>> } = {
[AlmKeys.Azure]: [],
[AlmKeys.Bitbucket]: ['repository', 'slug'],
[AlmKeys.GitHub]: ['repository'],
[AlmKeys.GitLab]: []
};

export default class PRDecorationBinding extends React.PureComponent<Props, State> {
@@ -133,7 +133,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
};

submitProjectAlmBinding(
alm: ALM_KEYS,
alm: AlmKeys,
key: string,
almSpecificFields?: T.Omit<ProjectAlmBinding, 'key'>
): Promise<void> {
@@ -141,12 +141,12 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
const project = this.props.component.key;

switch (alm) {
case ALM_KEYS.AZURE:
case AlmKeys.Azure:
return setProjectAzureBinding({
almSetting,
project
});
case ALM_KEYS.BITBUCKET: {
case AlmKeys.Bitbucket: {
if (!almSpecificFields) {
return Promise.reject();
}
@@ -158,7 +158,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
slug
});
}
case ALM_KEYS.GITHUB: {
case AlmKeys.GitHub: {
const repository = almSpecificFields && almSpecificFields.repository;
if (!repository) {
return Promise.reject();
@@ -170,7 +170,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
});
}

case ALM_KEYS.GITLAB:
case AlmKeys.GitLab:
return setProjectGitlabBinding({
almSetting,
project

+ 3
- 3
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx Ver fichero

@@ -27,7 +27,7 @@ import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon'
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { AlmSettingsInstance, ALM_KEYS, ProjectAlmBinding } from '../../../../types/alm-settings';
import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings';

export interface PRDecorationBindingRendererProps {
formData: ProjectAlmBinding;
@@ -179,7 +179,7 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe
/>
</div>

{alm === ALM_KEYS.BITBUCKET && (
{alm === AlmKeys.Bitbucket && (
<>
{renderField({
help: true,
@@ -216,7 +216,7 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe
</>
)}

{alm === ALM_KEYS.GITHUB &&
{alm === AlmKeys.GitHub &&
renderField({
help: true,
helpParams: { example: 'SonarSource/sonarqube' },

+ 10
- 10
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx Ver fichero

@@ -27,12 +27,12 @@ import {
setProjectAzureBinding,
setProjectBitbucketBinding,
setProjectGithubBinding
} from '../../../../../api/almSettings';
} from '../../../../../api/alm-settings';
import { mockComponent } from '../../../../../helpers/testMocks';
import { ALM_KEYS } from '../../../../../types/alm-settings';
import { AlmKeys } from '../../../../../types/alm-settings';
import PRDecorationBinding from '../PRDecorationBinding';

jest.mock('../../../../../api/almSettings', () => ({
jest.mock('../../../../../api/alm-settings', () => ({
getAlmSettings: jest.fn().mockResolvedValue([]),
getProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
setProjectAzureBinding: jest.fn().mockResolvedValue(undefined),
@@ -53,7 +53,7 @@ it('should render correctly', () => {

it('should fill selects and fill formdata', async () => {
const url = 'github.com';
const instances = [{ key: 'instance1', url, alm: ALM_KEYS.GITHUB }];
const instances = [{ key: 'instance1', url, alm: AlmKeys.GitHub }];
const formdata = {
key: 'instance1',
repository: 'account/repo'
@@ -89,9 +89,9 @@ it('should handle reset', async () => {

describe('handleSubmit', () => {
const instances = [
{ key: 'github', alm: ALM_KEYS.GITHUB },
{ key: 'azure', alm: ALM_KEYS.AZURE },
{ key: 'bitbucket', alm: ALM_KEYS.BITBUCKET }
{ key: 'github', alm: AlmKeys.GitHub },
{ key: 'azure', alm: AlmKeys.Azure },
{ key: 'bitbucket', alm: AlmKeys.Bitbucket }
];

it('should work for github', async () => {
@@ -195,9 +195,9 @@ it('should validate form', async () => {

wrapper.setState({
instances: [
{ key: 'azure', alm: ALM_KEYS.AZURE },
{ key: 'bitbucket', alm: ALM_KEYS.BITBUCKET },
{ key: 'github', alm: ALM_KEYS.GITHUB }
{ key: 'azure', alm: AlmKeys.Azure },
{ key: 'bitbucket', alm: AlmKeys.Bitbucket },
{ key: 'github', alm: AlmKeys.GitHub }
]
});
expect(wrapper.instance().validateForm({ key: 'azure' })).toBe(true);

+ 9
- 9
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx Ver fichero

@@ -21,7 +21,7 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import Select from 'sonar-ui-common/components/controls/Select';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { ALM_KEYS } from '../../../../../types/alm-settings';
import { AlmKeys } from '../../../../../types/alm-settings';
import PRDecorationBindingRenderer, {
PRDecorationBindingRendererProps
} from '../PRDecorationBindingRenderer';
@@ -35,7 +35,7 @@ it('should render single instance correctly', () => {
const singleInstance = {
key: 'single',
url: 'http://single.url',
alm: ALM_KEYS.GITHUB
alm: AlmKeys.GitHub
};
expect(
shallowRender({
@@ -49,22 +49,22 @@ it('should render multiple instances correctly', () => {
const urls = ['http://github.enterprise.com', 'http://bbs.enterprise.com'];
const instances = [
{
alm: ALM_KEYS.GITHUB,
alm: AlmKeys.GitHub,
key: 'i1',
url: urls[0]
},
{
alm: ALM_KEYS.GITHUB,
alm: AlmKeys.GitHub,
key: 'i2',
url: urls[0]
},
{
alm: ALM_KEYS.BITBUCKET,
alm: AlmKeys.Bitbucket,
key: 'i3',
url: urls[1]
},
{
alm: ALM_KEYS.AZURE,
alm: AlmKeys.Azure,
key: 'i4'
}
];
@@ -96,7 +96,7 @@ it('should render multiple instances correctly', () => {

it('should display action state correctly', () => {
const urls = ['http://url.com'];
const instances = [{ key: 'key', url: urls[0], alm: ALM_KEYS.GITHUB }];
const instances = [{ key: 'key', url: urls[0], alm: AlmKeys.GitHub }];

expect(shallowRender({ instances, loading: false, saving: true })).toMatchSnapshot();
expect(shallowRender({ instances, loading: false, success: true })).toMatchSnapshot();
@@ -112,11 +112,11 @@ it('should display action state correctly', () => {
it('should render select options correctly', async () => {
const instances = [
{
alm: ALM_KEYS.AZURE,
alm: AlmKeys.Azure,
key: 'azure'
},
{
alm: ALM_KEYS.GITHUB,
alm: AlmKeys.GitHub,
key: 'github',
url: 'gh.url.com'
}

+ 2
- 2
server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts Ver fichero

@@ -18,8 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import {
AlmKeys,
AlmSettingsInstance,
ALM_KEYS,
AzureBindingDefinition,
BitbucketBindingDefinition,
GithubBindingDefinition,
@@ -30,7 +30,7 @@ export function mockAlmSettingsInstance(
overrides: Partial<AlmSettingsInstance> = {}
): AlmSettingsInstance {
return {
alm: ALM_KEYS.GITHUB,
alm: AlmKeys.GitHub,
key: 'key',
...overrides
};

+ 23
- 23
server/sonar-web/src/main/js/types/alm-settings.ts Ver fichero

@@ -17,46 +17,33 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
export const enum ALM_KEYS {
AZURE = 'azure',
BITBUCKET = 'bitbucket',
GITHUB = 'github',
GITLAB = 'gitlab'
export const enum AlmKeys {
Azure = 'azure',
Bitbucket = 'bitbucket',
GitHub = 'github',
GitLab = 'gitlab'
}

export interface AlmSettingsBinding {
export interface AlmBindingDefinition {
key: string;
}

export interface AlmSettingsInstance {
alm: ALM_KEYS;
key: string;
url?: string;
}

export interface AlmSettingsBindingDefinitions {
azure: AzureBindingDefinition[];
bitbucket: BitbucketBindingDefinition[];
github: GithubBindingDefinition[];
gitlab: GitlabBindingDefinition[];
}

export interface AzureBindingDefinition extends AlmSettingsBinding {
export interface AzureBindingDefinition extends AlmBindingDefinition {
personalAccessToken: string;
}

export interface BitbucketBindingDefinition extends AlmSettingsBinding {
export interface BitbucketBindingDefinition extends AlmBindingDefinition {
personalAccessToken: string;
url: string;
}

export interface GithubBindingDefinition extends AlmSettingsBinding {
export interface GithubBindingDefinition extends AlmBindingDefinition {
appId: string;
privateKey: string;
url: string;
}

export interface GitlabBindingDefinition extends AlmSettingsBinding {
export interface GitlabBindingDefinition extends AlmBindingDefinition {
personalAccessToken: string;
}

@@ -88,3 +75,16 @@ export interface GitlabProjectAlmBinding {
almSetting: string;
project: string;
}

export interface AlmSettingsInstance {
alm: AlmKeys;
key: string;
url?: string;
}

export interface AlmSettingsBindingDefinitions {
azure: AzureBindingDefinition[];
bitbucket: BitbucketBindingDefinition[];
github: GithubBindingDefinition[];
gitlab: GitlabBindingDefinition[];
}

+ 63
- 53
sonar-core/src/main/resources/org/sonar/l10n/core.properties Ver fichero

@@ -1016,55 +1016,64 @@ settings.new_code_period.description2=This setting is the default for all projec

settings.languages.select_a_language_placeholder=Select a language

settings.pr_decoration.category=Pull Request Decoration
settings.pr_decoration.title=Pull Request Decoration
settings.pr_decoration.description=Pull Request Decoration adds SonarQube analysis and a Quality Gate to your Pull Requests directly in your ALM provider's interface.
settings.pr_decoration.manage_instances=Manage instances
settings.pr_decoration.azure.info=Accounts that will be used to decorate Pull Requests need Code: Read & Write permission. {link}
settings.pr_decoration.bitbucket.info=Accounts that will be used to decorate Pull Requests need write permission. {link}
settings.pr_decoration.github.info=You need to install a GitHub App with specific settings and permissions to enable Pull Request Decoration on your Organization or Repository. {link}
settings.pr_decoration.gitlab.info=Accounts that will be used to decorate Merge Requests need comment permissions on projects. The personal key needs the API scope permission. {link}
settings.pr_decoration.table.title=Pull Request Decoration configurations
settings.mr_decoration.table.title=Merge Request Decoration configurations
settings.pr_decoration.table.empty.azure=Create your first Azure DevOps configuration to enable Pull Request Decoration on your projects.
settings.pr_decoration.table.empty.bitbucket=Create your first Bitbucket configuration to enable Pull Request Decoration on your projects.
settings.pr_decoration.table.empty.github=Create your first GitHub configuration to enable Pull Request Decoration on your organization or repository.
settings.pr_decoration.table.empty.gitlab=Create your first GitLab configuration to enable Merge Request Decoration on your repository.
settings.pr_decoration.table.create=Create configuration
settings.pr_decoration.table.column.name=Name
settings.pr_decoration.table.column.bitbucket.url=Bitbucket Server URL
settings.pr_decoration.table.column.github.url=GitHub Enterprise or GitHub.com URL
settings.pr_decoration.table.column.app_id=App ID
settings.pr_decoration.table.column.edit=Edit
settings.pr_decoration.table.column.delete=Delete
settings.pr_decoration.delete.header=Delete configuration
settings.pr_decoration.delete.message=Are you sure you want to delete the {id} configuration?
settings.pr_decoration.delete.info={0} projects will no longer get Pull Request Decorations.
settings.pr_decoration.delete.no_info=An unknown number of projects will no longer get Pull Request Decorations.
settings.pr_decoration.form.header.create=Create a Pull Request Decoration configuration
settings.mr_decoration.form.header.create=Create a Merge Request Decoration configuration
settings.pr_decoration.form.header.edit=Edit the Pull Request Decoration configuration
settings.mr_decoration.form.header.edit=Edit the Merge Request Decoration configuration
settings.pr_decoration.form.name.azure=Configuration name
settings.pr_decoration.form.name.azure.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Azure instance for a project.
settings.pr_decoration.form.name.bitbucket=Configuration name
settings.pr_decoration.form.name.bitbucket.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Bitbucket instance for a project.
settings.pr_decoration.form.name.github=Configuration name
settings.pr_decoration.form.name.github.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitHub App for a project.
settings.pr_decoration.form.name.gitlab=Configuration name
settings.pr_decoration.form.name.gitlab.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitLab instance for a project.
settings.pr_decoration.form.url.bitbucket=Bitbucket Server URL
settings.pr_decoration.form.url.bitbucket.help=Example: {example}
settings.pr_decoration.form.url.github=GitHub URL
settings.pr_decoration.form.url.github.help1=Example for Github Enterprise:
settings.pr_decoration.form.url.github.help2=If using GitHub.com:
settings.pr_decoration.form.app_id=GitHub App ID
settings.pr_decoration.form.private_key=Private Key
settings.pr_decoration.form.personal_access_token=Personal Access token
settings.pr_decoration.form.personal_access_token.azure.help=Token of the user that will be used to decorate the Pull Requests. Needs authorized scope: "Code (read and write)".
settings.pr_decoration.form.personal_access_token.gitlab.help=Token of the user that will be used to decorate the Merge Requests. Needs API scope authorization.
settings.pr_decoration.form.save=Save configuration
settings.pr_decoration.form.cancel=Cancel
settings.almintegration.title=Integration configurations
settings.almintegration.description=ALM integrations allow SonarQube to interact with your ALM. This enables things like authentication, or providing analysis details and a Quality Gate to your Pull Requests directly in your ALM provider's interface.
settings.almintegration.manage_instances=Manage instances
settings.almintegration.azure.info=Accounts that will be used to decorate Pull Requests need Code: Read & Write permission. {link}
settings.almintegration.github.info=You need to install a GitHub App with specific settings and permissions to enable Pull Request Decoration on your Organization or Repository. {link}
settings.almintegration.gitlab.info=Accounts that will be used to decorate Merge Requests need comment permissions on projects. The personal key needs the API scope permission. {link}
settings.almintegration.bitbucket.help_1=SonarQube needs a Personal Access Token to communicate with Bitbucket Server. This token will be used to decorate Pull Requests.
settings.almintegration.bitbucket.help_2=The account used for integration needs write permission.
settings.almintegration.bitbucket.help_3=We recommend to integrate with SonarQube using a Bitbucket Server Service Account.
settings.almintegration.table.title=ALM integration configurations
settings.almintegration.table.empty.azure=Create your first Azure DevOps configuration to enable Pull Request Decoration on your projects.
settings.almintegration.table.empty.bitbucket=Create your first Bitbucket configuration to enable Pull Request Decoration on your projects.
settings.almintegration.table.empty.github=Create your first GitHub configuration to enable Pull Request Decoration on your organization or repository.
settings.almintegration.table.empty.gitlab=Create your first GitLab configuration to enable Merge Request Decoration on your repository.
settings.almintegration.table.create=Create configuration
settings.almintegration.table.column.name=Name
settings.almintegration.table.column.bitbucket.url=Bitbucket Server URL
settings.almintegration.table.column.github.url=GitHub Enterprise or GitHub.com URL
settings.almintegration.table.column.app_id=App ID
settings.almintegration.table.column.edit=Edit
settings.almintegration.table.column.delete=Delete
settings.almintegration.delete.header=Delete configuration
settings.almintegration.delete.message=Are you sure you want to delete the {id} configuration?
settings.almintegration.delete.info={0} projects will no longer get Pull Request Decorations.
settings.almintegration.delete.no_info=An unknown number of projects will no longer get Pull Request Decorations.
settings.almintegration.form.header.create=Create a configuration
settings.almintegration.form.header.edit=Edit the configuration
settings.almintegration.form.name.azure=Configuration name
settings.almintegration.form.name.azure.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Azure instance for a project.
settings.almintegration.form.name.bitbucket=Configuration name
settings.almintegration.form.name.bitbucket.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Bitbucket instance for a project.
settings.almintegration.form.name.github=Configuration name
settings.almintegration.form.name.github.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitHub App for a project.
settings.almintegration.form.name.gitlab=Configuration name
settings.almintegration.form.name.gitlab.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitLab instance for a project.
settings.almintegration.form.url.bitbucket=Bitbucket Server URL
settings.almintegration.form.url.bitbucket.help=Example: {example}
settings.almintegration.form.url.github=GitHub URL
settings.almintegration.form.url.github.help1=Example for Github Enterprise:
settings.almintegration.form.url.github.help2=If using GitHub.com:
settings.almintegration.form.app_id=GitHub App ID
settings.almintegration.form.private_key=Private Key
settings.almintegration.form.personal_access_token=Personal Access token
settings.almintegration.form.personal_access_token.azure.help=Token of the user that will be used to decorate the Pull Requests. Needs authorized scope: "Code (read and write)".
settings.almintegration.form.personal_access_token.gitlab.help=Token of the user that will be used to decorate the Merge Requests. Needs API scope authorization.
settings.almintegration.form.save=Save configuration
settings.almintegration.form.cancel=Cancel
settings.almintegration.features=ALM integration features
settings.almintegration.feature.enabled=This feature is enabled
settings.almintegration.feature.disabled=This feature is currently disabled
settings.almintegration.feature.need_at_least_1_binding=You need to have at least 1 binding configured to use this feature
settings.almintegration.feature.pr_decoration.title=Pull Request Decoration
settings.almintegration.feature.pr_decoration.description=Add analysis and a Quality Gate to your Pull Requests directly in your ALM provider's interface.
settings.almintegration.feature.mr_decoration.title=Merge Request Decoration
settings.almintegration.feature.mr_decoration.description=Add analysis and a Quality Gate to your Merge Requests directly in your ALM provider's interface.
settings.almintegration.feature.alm_repo_import.title=Import repositories from your ALM
settings.almintegration.feature.alm_repo_import.description=Select repositories from your ALM, and import them into SonarQube.
settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances=Connecting to multiple Bitbucket Server instances will deactivate the {feature} feature. Projects will have to be set up manually.

settings.pr_decoration.binding.category=Pull Request Decoration
settings.pr_decoration.binding.no_bindings=This feature must first be enabled in the global settings. {link}
@@ -1088,13 +1097,14 @@ property.category.general.databaseCleaner=Database Cleaner
property.category.general.looknfeel=Look & Feel
property.category.general.issues=Issues
property.category.general.subProjects=Sub-projects
property.category.almintegration=ALM Integrations
property.category.almintegration.github=GitHub Authentication
property.category.almintegration.github.description=In order to enable authentication on GitHub.com or GitHub Enterprise:<ul><li>SonarQube must be publicly accessible through HTTPS only</li><li>The property 'sonar.core.serverBaseURL' must be set to this public HTTPS URL</li><li>In your GitHub profile, you need to create a Developer Application for which the 'Authorization callback URL' must be set to <code>'&lt;value_of_sonar.core.serverBaseURL_property&gt;/oauth2/callback'</code>.</li></ul>
property.category.almintegration.gitlab=GitLab Authentication
property.category.almintegration.gitlab.description=In order to enable GitLab authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL
property.category.organizations=Organizations
property.category.security=Security
property.category.security.encryption=Encryption
property.category.security.github=GitHub
property.category.security.github.description=In order to enable authentication on GitHub.com or GitHub Enterprise:<ul><li>SonarQube must be publicly accessible through HTTPS only</li><li>The property 'sonar.core.serverBaseURL' must be set to this public HTTPS URL</li><li>In your GitHub profile, you need to create a Developer Application for which the 'Authorization callback URL' must be set to <code>'&lt;value_of_sonar.core.serverBaseURL_property&gt;/oauth2/callback'</code>.</li></ul>
property.category.security.gitlab=Gitlab
property.category.security.gitlab.description=In order to enable Gitlab authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL
property.category.security.saml=SAML
property.category.security.saml.description=In order to enable SAML authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL
property.category.java=Java

+ 5
- 0
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java Ver fichero

@@ -56,6 +56,11 @@ public interface CoreProperties {
*/
String SUBCATEGORY_DUPLICATIONS = "duplications";

/**
* @since 8.2
*/
String CATEGORY_ALM_INTEGRATION = "almintegration";

/**
* @since 8.1
*/

Cargando…
Cancelar
Guardar