diff options
author | Jay <jeremy.davis@sonarsource.com> | 2020-08-14 09:23:44 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2020-08-17 20:06:23 +0000 |
commit | 5930b958a17fca7cc0f0294966a23f291d09d372 (patch) | |
tree | 29313b9bbf06cf2d2b980e61b4c822b100a2d045 | |
parent | a94690921be591240c7bc97a287a2a0046fc58b9 (diff) | |
download | sonarqube-5930b958a17fca7cc0f0294966a23f291d09d372.tar.gz sonarqube-5930b958a17fca7cc0f0294966a23f291d09d372.zip |
SONAR-13749 make URL mandatory
SONAR-13749 make URL mandatory
10 files changed, 237 insertions, 45 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavPlus.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavPlus.tsx index 65eb8c75bfe..414500684cb 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavPlus.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavPlus.tsx @@ -28,7 +28,7 @@ import { Router, withRouter } from '../../../../components/hoc/withRouter'; import { getExtensionStart } from '../../../../helpers/extensions'; import { getPortfolioAdminUrl, getPortfolioUrl } from '../../../../helpers/urls'; import { hasGlobalPermission } from '../../../../helpers/users'; -import { AlmKeys } from '../../../../types/alm-settings'; +import { AlmKeys, AlmSettingsInstance } from '../../../../types/alm-settings'; import { ComponentQualifier } from '../../../../types/component'; import GlobalNavPlusMenu from './GlobalNavPlusMenu'; @@ -49,6 +49,13 @@ interface State { */ const IMPORT_COMPATIBLE_ALMS = [AlmKeys.Bitbucket, AlmKeys.GitHub, AlmKeys.GitLab]; +const almSettingsValidators = { + [AlmKeys.Azure]: (_: AlmSettingsInstance) => true, + [AlmKeys.Bitbucket]: (_: AlmSettingsInstance) => true, + [AlmKeys.GitHub]: (_: AlmSettingsInstance) => true, + [AlmKeys.GitLab]: (settings: AlmSettingsInstance) => !!settings.url +}; + export class GlobalNavPlus extends React.PureComponent<Props, State> { mounted = false; state: State = { boundAlms: [], governanceReady: false }; @@ -78,6 +85,10 @@ export class GlobalNavPlus extends React.PureComponent<Props, State> { this.setState({ creatingComponent: undefined }); }; + almSettingIsValid = (settings: AlmSettingsInstance) => { + return almSettingsValidators[settings.alm](settings); + }; + fetchAlmBindings = async () => { const { appState: { branchesEnabled }, @@ -94,8 +105,8 @@ export class GlobalNavPlus extends React.PureComponent<Props, State> { // Import is only available if exactly one binding is configured const boundAlms = IMPORT_COMPATIBLE_ALMS.filter(key => { - const count = almSettings.filter(s => s.alm === key).length; - return count === 1; + const currentAlmSettings = almSettings.filter(s => s.alm === key); + return currentAlmSettings.length === 1 && this.almSettingIsValid(currentAlmSettings[0]); }); if (this.mounted) { diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavPlus-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavPlus-test.tsx index 8d74d544510..9a58c0b2fc6 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavPlus-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavPlus-test.tsx @@ -79,9 +79,10 @@ it('should render correctly', () => { it('should load correctly', async () => { (getAlmSettings as jest.Mock).mockResolvedValueOnce([ - { alm: AlmKeys.Azure, key: 'A1' }, + { alm: AlmKeys.Azure, key: 'A1' }, // No azure onboarding for now { alm: AlmKeys.Bitbucket, key: 'B1' }, - { alm: AlmKeys.GitHub, key: 'GH1' } + { alm: AlmKeys.GitHub, key: 'GH1' }, + { alm: AlmKeys.GitLab, key: 'GL1', url: 'ok' } ]); const wrapper = shallowRender([PROJECT_CREATION_RIGHT], {}); @@ -89,7 +90,18 @@ it('should load correctly', async () => { await waitAndUpdate(wrapper); expect(getAlmSettings).toBeCalled(); - expect(wrapper.state().boundAlms).toEqual([AlmKeys.Bitbucket, AlmKeys.GitHub]); + expect(wrapper.state().boundAlms).toEqual([AlmKeys.Bitbucket, AlmKeys.GitHub, AlmKeys.GitLab]); +}); + +it('should load without gitlab when no url', async () => { + (getAlmSettings as jest.Mock).mockResolvedValueOnce([{ alm: AlmKeys.GitLab, key: 'GL1' }]); + + const wrapper = shallowRender([PROJECT_CREATION_RIGHT], {}); + + await waitAndUpdate(wrapper); + + expect(getAlmSettings).toBeCalled(); + expect(wrapper.state().boundAlms).toEqual([]); }); it('should display component creation form', () => { diff --git a/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx b/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx index 0329de3f987..fd2763482bf 100644 --- a/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/PersonalAccessTokenForm.tsx @@ -102,7 +102,7 @@ export default function PersonalAccessTokenForm(props: PersonalAccessTokenFormPr <DeferredSpinner className="spacer-left" loading={submitting} /> </form> - <Alert className="big-spacer-left huge-spacer-top width-50" display="block" variant="info"> + <Alert className="big-spacer-left width-50" display="block" variant="info"> <h3>{translate('onboarding.create_project.pat_help.title')}</h3> <p className="big-spacer-top big-spacer-bottom"> diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/PersonalAccessTokenForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/PersonalAccessTokenForm-test.tsx.snap index 7f7cb95101e..3d7cf43b0c8 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/PersonalAccessTokenForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/PersonalAccessTokenForm-test.tsx.snap @@ -47,7 +47,7 @@ exports[`should render correctly: bitbucket 1`] = ` /> </form> <Alert - className="big-spacer-left huge-spacer-top width-50" + className="big-spacer-left width-50" display="block" variant="info" > @@ -168,7 +168,7 @@ exports[`should render correctly: gitlab 1`] = ` /> </form> <Alert - className="big-spacer-left huge-spacer-top width-50" + className="big-spacer-left width-50" display="block" variant="info" > @@ -270,7 +270,7 @@ exports[`should render correctly: gitlab with non-standard api path 1`] = ` /> </form> <Alert - className="big-spacer-left huge-spacer-top width-50" + className="big-spacer-left width-50" display="block" variant="info" > @@ -372,7 +372,7 @@ exports[`should render correctly: submitting 1`] = ` /> </form> <Alert - className="big-spacer-left huge-spacer-top width-50" + className="big-spacer-left width-50" display="block" variant="info" > @@ -494,7 +494,7 @@ exports[`should render correctly: validation failed 1`] = ` /> </form> <Alert - className="big-spacer-left huge-spacer-top width-50" + className="big-spacer-left width-50" display="block" variant="info" > diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx index a284b8ed22f..a64e1be9ad7 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx @@ -48,10 +48,7 @@ export default function GitlabForm(props: GitlabFormProps) { <AlmBindingDefinitionFormField help={ <> - {translate('settings.almintegration.form.url.gitlab.help1')} - <br /> - <br /> - {translate('settings.almintegration.form.url.gitlab.help2')} + {translate('settings.almintegration.form.url.gitlab.help')} <br /> <em>https://gitlab.com/api/v4</em> </> @@ -59,7 +56,6 @@ export default function GitlabForm(props: GitlabFormProps) { id="url.gitlab" maxLength={2000} onFieldChange={onFieldChange} - optional={true} propKey="url" readOnly={readOnly} value={formData.url || ''} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx index 9533191c7b3..a50d7809bde 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabTab.tsx @@ -49,6 +49,8 @@ export default function GitlabTab(props: GitlabTabProps) { loadingProjectCount } = props; + const importFeatureEnabled = Boolean(definitions.length === 1 && definitions[0].url); + return ( <div className="bordered"> {branchesEnabled && ( @@ -86,14 +88,19 @@ export default function GitlabTab(props: GitlabTabProps) { }, { name: translate('settings.almintegration.feature.alm_repo_import.title'), - active: definitions.length === 1, + active: importFeatureEnabled, description: translate( 'settings.almintegration.feature.alm_repo_import.description' ), - inactiveReason: translateWithParameters( - 'settings.almintegration.feature.alm_repo_import.gitlab.wrong_count_x', - definitions.length - ) + inactiveReason: + definitions.length === 1 + ? translate( + 'settings.almintegration.feature.alm_repo_import.gitlab.requires_fields' + ) + : translateWithParameters( + 'settings.almintegration.feature.alm_repo_import.gitlab.wrong_count_x', + definitions.length + ) } ]} form={childProps => <GitlabForm {...childProps} />} @@ -102,7 +109,6 @@ export default function GitlabTab(props: GitlabTabProps) { multipleAlmEnabled={multipleAlmEnabled} onDelete={props.onDelete} onUpdateDefinitions={props.onUpdateDefinitions} - optionalFields={['url']} updateConfiguration={updateGitlabConfiguration} /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx index 619777dd30a..cd3a792d8c1 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/GitlabTab-test.tsx @@ -25,6 +25,16 @@ import GitlabTab, { GitlabTabProps } from '../GitlabTab'; it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot('with branch support'); expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support'); + expect( + shallowRender({ + definitions: [mockGitlabBindingDefinition({ url: 'https://gitlab.com/api/v4' })] + }) + ).toMatchSnapshot('with URL'); + expect( + shallowRender({ + definitions: [] + }) + ).toMatchSnapshot('with no definitions'); }); function shallowRender(props: Partial<GitlabTabProps> = {}) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap index c3366fc39ef..b3c74682498 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap @@ -13,10 +13,7 @@ exports[`should render correctly 1`] = ` <AlmBindingDefinitionFormField help={ <React.Fragment> - settings.almintegration.form.url.gitlab.help1 - <br /> - <br /> - settings.almintegration.form.url.gitlab.help2 + settings.almintegration.form.url.gitlab.help <br /> <em> https://gitlab.com/api/v4 @@ -26,7 +23,6 @@ exports[`should render correctly 1`] = ` id="url.gitlab" maxLength={2000} onFieldChange={[MockFunction]} - optional={true} propKey="url" value="" /> @@ -54,10 +50,7 @@ exports[`should render correctly 2`] = ` <AlmBindingDefinitionFormField help={ <React.Fragment> - settings.almintegration.form.url.gitlab.help1 - <br /> - <br /> - settings.almintegration.form.url.gitlab.help2 + settings.almintegration.form.url.gitlab.help <br /> <em> https://gitlab.com/api/v4 @@ -67,7 +60,6 @@ exports[`should render correctly 2`] = ` id="url.gitlab" maxLength={2000} onFieldChange={[MockFunction]} - optional={true} propKey="url" value="" /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap index 0337700998b..1ab95326119 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabTab-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly: with branch support 1`] = ` +exports[`should render correctly: with URL 1`] = ` <div className="bordered" > @@ -47,6 +47,7 @@ exports[`should render correctly: with branch support 1`] = ` Object { "key": "foo", "personalAccessToken": "foobar", + "url": "https://gitlab.com/api/v4", }, ] } @@ -61,7 +62,7 @@ exports[`should render correctly: with branch support 1`] = ` Object { "active": true, "description": "settings.almintegration.feature.alm_repo_import.description", - "inactiveReason": "settings.almintegration.feature.alm_repo_import.gitlab.wrong_count_x.1", + "inactiveReason": "settings.almintegration.feature.alm_repo_import.gitlab.requires_fields", "name": "settings.almintegration.feature.alm_repo_import.title", }, ] @@ -72,11 +73,175 @@ exports[`should render correctly: with branch support 1`] = ` multipleAlmEnabled={true} onDelete={[MockFunction]} onUpdateDefinitions={[MockFunction]} - optionalFields={ + 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: with branch support 1`] = ` +<div + className="bordered" +> + <AlmTab + additionalColumnsHeaders={ + Array [ + "settings.almintegration.table.column.gitlab.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_gitlab_instances" + id="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_gitlab_instances" + values={ + Object { + "feature": <em> + settings.almintegration.feature.alm_repo_import.title + </em>, + } + } + /> + </Alert> + } + alm="gitlab" + createConfiguration={[Function]} + defaultBinding={ + Object { + "key": "", + "personalAccessToken": "", + "url": "", + } + } + 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", + }, + Object { + "active": false, + "description": "settings.almintegration.feature.alm_repo_import.description", + "inactiveReason": "settings.almintegration.feature.alm_repo_import.gitlab.requires_fields", + "name": "settings.almintegration.feature.alm_repo_import.title", + }, + ] + } + form={[Function]} + loadingAlmDefinitions={false} + loadingProjectCount={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: with no definitions 1`] = ` +<div + className="bordered" +> + <AlmTab + additionalColumnsHeaders={ + Array [ + "settings.almintegration.table.column.gitlab.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_gitlab_instances" + id="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_gitlab_instances" + values={ + Object { + "feature": <em> + settings.almintegration.feature.alm_repo_import.title + </em>, + } + } + /> + </Alert> + } + alm="gitlab" + createConfiguration={[Function]} + defaultBinding={ + Object { + "key": "", + "personalAccessToken": "", + "url": "", + } + } + definitions={Array []} + features={ + Array [ + Object { + "active": false, + "description": "settings.almintegration.feature.mr_decoration.description", + "inactiveReason": "settings.almintegration.feature.need_at_least_1_binding", + "name": "settings.almintegration.feature.mr_decoration.title", + }, + Object { + "active": false, + "description": "settings.almintegration.feature.alm_repo_import.description", + "inactiveReason": "settings.almintegration.feature.alm_repo_import.gitlab.wrong_count_x.0", + "name": "settings.almintegration.feature.alm_repo_import.title", + }, + ] + } + form={[Function]} + loadingAlmDefinitions={false} + loadingProjectCount={false} + multipleAlmEnabled={true} + onDelete={[MockFunction]} + onUpdateDefinitions={[MockFunction]} updateConfiguration={[Function]} /> <div diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 5d051d62271..82a366f2f12 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1054,12 +1054,11 @@ 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=GitHub API URL settings.almintegration.form.url.github.help1=Example for Github Enterprise: settings.almintegration.form.url.github.help2=If using GitHub.com: -settings.almintegration.form.url.gitlab=GitLab URL -settings.almintegration.form.url.gitlab.help1=You do not have to provide this value if you're using GitLab CI. -settings.almintegration.form.url.gitlab.help2=If you're using another CI, provide the GitLab API URL. For example: +settings.almintegration.form.url.gitlab=GitLab API URL +settings.almintegration.form.url.gitlab.help=Provide the GitLab API URL. For example: settings.almintegration.form.app_id=GitHub App ID settings.almintegration.form.client_id=GitHub Client ID settings.almintegration.form.client_secret=GitHub Client Secret @@ -1079,12 +1078,13 @@ 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.almintegration.feature.alm_repo_import.disabled_if_multiple_github_instances=Connecting to multiple GitHub instances will deactivate the {feature} feature. Projects will have to be set up manually. -settings.almintegration.feature.alm_repo_import.disabled_if_multiple_gitlab_instances=Connecting to multiple GitLab instances will deactivate the {feature} feature. Projects will have to be set up manually. +settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances=If you have multiple Bitbucket instances connected, you cannot add a project by importing it from a Bitbucket repository, and you'll have to add it manually. +settings.almintegration.feature.alm_repo_import.disabled_if_multiple_github_instances=If you have multiple GitHub instances connected, you cannot add a project by importing it from a GitHub repository, and you'll have to add it manually. +settings.almintegration.feature.alm_repo_import.disabled_if_multiple_gitlab_instances=If you have multiple GitLab instances connected, you cannot add a project by importing it from a GitLab repository, and you'll have to add it manually. settings.almintegration.feature.alm_repo_import.bitbucket.wrong_count_x=You must have exactly 1 Bitbucket Server instance configured in order to use this method. You currently have {0}. settings.almintegration.feature.alm_repo_import.github.wrong_count_x=You must have exactly 1 GitHub instance configured in order to use this method. You currently have {0}. settings.almintegration.feature.alm_repo_import.gitlab.wrong_count_x=You must have exactly 1 GitLab instance configured in order to use this method. You currently have {0}. +settings.almintegration.feature.alm_repo_import.gitlab.requires_fields=Your configured instance must be provided with its API URL. settings.almintegration.feature.alm_repo_import.github.requires_fields=Your configured instance must be provided with the App's {clientId} and {clientSecret}. settings.pr_decoration.binding.category=Pull Request Decoration @@ -3143,8 +3143,8 @@ onboarding.create_project.zero_alm_instances.github=You must first configure a G onboarding.create_project.wrong_binding_count=You must have exactly 1 {alm} instance configured in order to use this method, but none were found. Either create the project manually, or contact your system administrator. onboarding.create_project.wrong_binding_count.admin=You must have exactly 1 {alm} instance configured in order to use this method. You can configure instances under {url}. onboarding.create_project.enter_pat=Enter personal access token -onboarding.create_project.pat_incorrect.bitbucket=Your personal access token failed to validate. -onboarding.create_project.pat_incorrect.gitlab=Your personal access token failed to validate. Please make sure it has the right scope and that it is not expired. +onboarding.create_project.pat_incorrect.bitbucket=Your personal access couldn't be validated. +onboarding.create_project.pat_incorrect.gitlab=Your personal access couldn't be validated. Please make sure it has the right scope and that it is not expired. onboarding.create_project.pat_help.title=How to create a personal access token? onboarding.create_project.pat_help.instructions=Click the following link to generate a token in {alm}, and copy-paste it into the personal access token field. |