aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2019-10-21 17:36:17 +0200
committersonartech <sonartech@sonarsource.com>2019-11-06 10:04:27 +0100
commitefe02985a999dcc36c966ade6153e3af4829bdab (patch)
treef9527ff4235929e1a2dad25ba5549f3b9031f8e7
parent7c707a301f8a970f67a0bd34a7f02dace253c579 (diff)
downloadsonarqube-efe02985a999dcc36c966ade6153e3af4829bdab.tar.gz
sonarqube-efe02985a999dcc36c966ade6153e3af4829bdab.zip
SONAR-12515 UI for project-level form - Azure
-rw-r--r--server/sonar-web/src/main/js/api/almSettings.ts8
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx105
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/types/alm-settings.d.ts14
7 files changed, 138 insertions, 58 deletions
diff --git a/server/sonar-web/src/main/js/api/almSettings.ts b/server/sonar-web/src/main/js/api/almSettings.ts
index 52cf1b61366..e7aaee50827 100644
--- a/server/sonar-web/src/main/js/api/almSettings.ts
+++ b/server/sonar-web/src/main/js/api/almSettings.ts
@@ -57,13 +57,17 @@ export function countBindedProjects(almSetting: string) {
}
export function getProjectAlmBinding(project: string): Promise<T.ProjectAlmBinding> {
- return getJSON('/api/alm_settings/get_github_binding', { project });
+ return getJSON('/api/alm_settings/get_binding', { project });
}
export function deleteProjectAlmBinding(project: string): Promise<void> {
return post('/api/alm_settings/delete_binding', { project }).catch(throwGlobalError);
}
-export function setProjectAlmBinding(data: T.GithubProjectAlmBinding) {
+export function setProjectAzureBinding(data: T.AzureProjectAlmBinding) {
+ return post('/api/alm_settings/set_azure_binding', data).catch(throwGlobalError);
+}
+
+export function setProjectGithubBinding(data: T.GithubProjectAlmBinding) {
return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx
index 82482cbcbfc..6c31725727a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx
@@ -22,9 +22,11 @@ import {
deleteProjectAlmBinding,
getAlmSettings,
getProjectAlmBinding,
- setProjectAlmBinding
+ setProjectAzureBinding,
+ setProjectGithubBinding
} from '../../../../api/almSettings';
import throwGlobalError from '../../../../app/utils/throwGlobalError';
+import { ALM_KEYS } from '../../utils';
import PRDecorationBindingRenderer from './PRDecorationBindingRenderer';
interface Props {
@@ -32,7 +34,7 @@ interface Props {
}
interface State {
- formData: T.GithubBinding;
+ formData: T.ProjectAlmBinding;
hasBinding: boolean;
instances: T.AlmSettingsInstance[];
isValid: boolean;
@@ -41,6 +43,11 @@ interface State {
success: boolean;
}
+const FIELDS_BY_ALM: { [almKey: string]: Array<'repository'> } = {
+ [ALM_KEYS.AZURE]: [],
+ [ALM_KEYS.GITHUB]: ['repository']
+};
+
export default class PRDecorationBinding extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
@@ -70,13 +77,16 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
return Promise.all([getAlmSettings(project), this.getProjectBinding(project)])
.then(([instances, data]) => {
if (this.mounted) {
- this.setState(({ formData }) => ({
- formData: data || formData,
- hasBinding: Boolean(data),
- instances,
- isValid: this.validateForm(),
- loading: false
- }));
+ this.setState(({ formData }) => {
+ const newFormData = data || formData;
+ return {
+ formData: newFormData,
+ hasBinding: Boolean(data),
+ instances,
+ isValid: this.validateForm(newFormData),
+ loading: false
+ };
+ });
if (!data && instances.length === 1) {
this.handleFieldChange('key', instances[0].key);
@@ -125,18 +135,50 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
.catch(this.catchError);
};
+ submitProjectAlmBinding(
+ alm: ALM_KEYS,
+ key: string,
+ almSpecificFields?: { repository?: string }
+ ): Promise<void> {
+ const almSetting = key;
+ const project = this.props.component.key;
+
+ switch (alm) {
+ case ALM_KEYS.AZURE:
+ return setProjectAzureBinding({
+ almSetting,
+ project
+ });
+ case ALM_KEYS.GITHUB: {
+ const repository = almSpecificFields && almSpecificFields.repository;
+ if (!repository) {
+ return Promise.reject();
+ }
+ return setProjectGithubBinding({
+ almSetting,
+ project,
+ repository
+ });
+ }
+ default:
+ return Promise.reject();
+ }
+ }
+
handleSubmit = () => {
this.setState({ saving: true });
const {
- formData: { key, repository }
+ formData: { key, ...additionalFields },
+ instances
} = this.state;
- if (key && repository) {
- setProjectAlmBinding({
- almSetting: key,
- project: this.props.component.key,
- repository
- })
+ const selected = instances.find(i => i.key === key);
+ if (!key || !selected) {
+ return;
+ }
+
+ if (key) {
+ this.submitProjectAlmBinding(selected.alm as ALM_KEYS, key, additionalFields)
.then(() => {
if (this.mounted) {
this.setState({
@@ -150,21 +192,28 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat
}
};
- handleFieldChange = (id: keyof T.GithubBinding, value: string) => {
- this.setState(({ formData: formdata }) => ({
- formData: {
- ...formdata,
+ handleFieldChange = (id: keyof T.ProjectAlmBinding, value: string) => {
+ this.setState(({ formData }) => {
+ const newFormData = {
+ ...formData,
[id]: value
- },
- isValid: this.validateForm(),
- success: false
- }));
+ };
+ return {
+ formData: newFormData,
+ isValid: this.validateForm(newFormData),
+ success: false
+ };
+ });
};
- validateForm = () => {
- const { formData } = this.state;
- return Object.values(formData).reduce(
- (result: boolean, value) => result && Boolean(value),
+ validateForm = ({ key, ...additionalFields }: State['formData']) => {
+ const { instances } = this.state;
+ const selected = instances.find(i => i.key === key);
+ if (!key || !selected) {
+ return false;
+ }
+ return FIELDS_BY_ALM[selected.alm as ALM_KEYS].reduce(
+ (result: boolean, field) => result && Boolean(additionalFields[field]),
true
);
};
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx
index a36aca0c226..3fa7892e320 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBindingRenderer.tsx
@@ -26,14 +26,15 @@ 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 { ALM_KEYS } from '../../utils';
export interface PRDecorationBindingRendererProps {
- formData: T.GithubBinding;
+ formData: T.ProjectAlmBinding;
hasBinding: boolean;
instances: T.AlmSettingsInstance[];
isValid: boolean;
loading: boolean;
- onFieldChange: (id: keyof T.GithubBinding, value: string) => void;
+ onFieldChange: (id: keyof T.ProjectAlmBinding, value: string) => void;
onReset: () => void;
onSubmit: () => void;
saving: boolean;
@@ -79,6 +80,9 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe
);
}
+ const selected = key && instances.find(i => i.key === key);
+ const alm = selected && (selected.alm as ALM_KEYS);
+
return (
<div>
<header className="page-header">
@@ -110,7 +114,7 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe
/>
</div>
- {key && (
+ {alm === ALM_KEYS.GITHUB && (
<div className="form-field">
<label htmlFor="repository">
{translate('settings.pr_decoration.binding.form.repository')}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx
index 4129a868c6f..e0e1b899c4a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx
@@ -24,15 +24,18 @@ import {
deleteProjectAlmBinding,
getAlmSettings,
getProjectAlmBinding,
- setProjectAlmBinding
+ setProjectAzureBinding,
+ setProjectGithubBinding
} from '../../../../../api/almSettings';
import { mockComponent } from '../../../../../helpers/testMocks';
+import { ALM_KEYS } from '../../../utils';
import PRDecorationBinding from '../PRDecorationBinding';
jest.mock('../../../../../api/almSettings', () => ({
getAlmSettings: jest.fn().mockResolvedValue([]),
getProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
- setProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
+ setProjectAzureBinding: jest.fn().mockResolvedValue(undefined),
+ setProjectGithubBinding: jest.fn().mockResolvedValue(undefined),
deleteProjectAlmBinding: jest.fn().mockResolvedValue(undefined)
}));
@@ -48,7 +51,7 @@ it('should render correctly', () => {
it('should fill selects and fill formdata', async () => {
const url = 'github.com';
- const instances = [{ key: 'instance1', url, alm: 'github' }];
+ const instances = [{ key: 'instance1', url, alm: ALM_KEYS.GITHUB }];
const formdata = {
key: 'instance1',
repository: 'account/repo'
@@ -96,18 +99,38 @@ it('should handle reset', async () => {
expect(wrapper.state().hasBinding).toBe(false);
});
-it('should handle submit', async () => {
+it('should handle submit to github or azure', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
- wrapper.setState({ formData });
+ const instances = [
+ { key: 'github', alm: ALM_KEYS.GITHUB },
+ { key: 'azure', alm: ALM_KEYS.AZURE }
+ ];
+ // Github
+ const githubKey = 'github';
+ const repository = 'repo/path';
+ wrapper.setState({ formData: { key: githubKey, repository }, instances });
wrapper.instance().handleSubmit();
await waitAndUpdate(wrapper);
- expect(setProjectAlmBinding).toBeCalledWith({
- almSetting: formData.key,
+ expect(setProjectGithubBinding).toBeCalledWith({
+ almSetting: githubKey,
project: PROJECT_KEY,
- repository: formData.repository
+ repository
+ });
+ expect(wrapper.state().hasBinding).toBe(true);
+ expect(wrapper.state().success).toBe(true);
+
+ // azure
+ const azureKey = 'azure';
+ wrapper.setState({ formData: { key: azureKey } });
+ wrapper.instance().handleSubmit();
+ await waitAndUpdate(wrapper);
+
+ expect(setProjectAzureBinding).toBeCalledWith({
+ almSetting: azureKey,
+ project: PROJECT_KEY
});
expect(wrapper.state().hasBinding).toBe(true);
expect(wrapper.state().success).toBe(true);
@@ -115,7 +138,7 @@ it('should handle submit', async () => {
it('should handle failures gracefully', async () => {
(getProjectAlmBinding as jest.Mock).mockRejectedValueOnce({ status: 500 });
- (setProjectAlmBinding as jest.Mock).mockRejectedValueOnce({ status: 500 });
+ (setProjectGithubBinding as jest.Mock).mockRejectedValueOnce({ status: 500 });
(deleteProjectAlmBinding as jest.Mock).mockRejectedValueOnce({ status: 500 });
const wrapper = shallowRender();
@@ -158,13 +181,15 @@ it('should validate form', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
- expect(wrapper.instance().validateForm()).toBe(false);
-
- wrapper.setState({ formData: { key: '', repository: 'c' } });
- expect(wrapper.instance().validateForm()).toBe(false);
+ expect(wrapper.instance().validateForm({ key: '', repository: '' })).toBe(false);
+ expect(wrapper.instance().validateForm({ key: '', repository: 'c' })).toBe(false);
- wrapper.setState({ formData: { key: 'a', repository: 'c' } });
- expect(wrapper.instance().validateForm()).toBe(true);
+ wrapper.setState({
+ instances: [{ key: 'azure', alm: ALM_KEYS.AZURE }, { key: 'github', alm: ALM_KEYS.GITHUB }]
+ });
+ expect(wrapper.instance().validateForm({ key: 'azure' })).toBe(true);
+ expect(wrapper.instance().validateForm({ key: 'github', repository: '' })).toBe(false);
+ expect(wrapper.instance().validateForm({ key: 'github', repository: 'asdf' })).toBe(true);
});
function shallowRender(props: Partial<PRDecorationBinding['props']> = {}) {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
index f47e0713fcf..48c7c098208 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBindingRenderer-test.tsx
@@ -74,7 +74,7 @@ it('should render multiple instances correctly', () => {
expect(
shallowRender({
formData: {
- key: 'Github - main instance',
+ key: 'i1',
repository: 'account/repo'
},
hasBinding: true,
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap
index 06ad8d9c9c6..a57c9bfa856 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/PRDecorationBindingRenderer-test.tsx.snap
@@ -373,7 +373,7 @@ exports[`should render multiple instances correctly 2`] = `
]
}
searchable={false}
- value="Github - main instance"
+ value="i1"
/>
</div>
<div
diff --git a/server/sonar-web/src/main/js/types/alm-settings.d.ts b/server/sonar-web/src/main/js/types/alm-settings.d.ts
index 0944092c96f..16fd0be23da 100644
--- a/server/sonar-web/src/main/js/types/alm-settings.d.ts
+++ b/server/sonar-web/src/main/js/types/alm-settings.d.ts
@@ -45,19 +45,17 @@ declare namespace T {
export interface ProjectAlmBinding {
key: string;
- alm: string;
- url: string;
- repository: string;
+ repository?: string;
}
- export interface GithubProjectAlmBinding {
+ export interface AzureProjectAlmBinding {
almSetting: string;
project: string;
- repository: string;
}
- export interface GithubBinding {
- key: string;
- repository?: string;
+ export interface GithubProjectAlmBinding {
+ almSetting: string;
+ project: string;
+ repository: string;
}
}