]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12514 UI for bitbucket PR decoration configuration
authorJeremy Davis <jeremy.davis@sonarsource.com>
Tue, 22 Oct 2019 09:16:59 +0000 (11:16 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 6 Nov 2019 09:04:28 +0000 (10:04 +0100)
19 files changed:
server/sonar-web/src/main/js/api/almSettings.ts
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketFormModal.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTable.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketFormModal-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTable-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketFormModal-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTable-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap
server/sonar-web/src/main/js/apps/settings/utils.ts
server/sonar-web/src/main/js/helpers/testMocks.ts
server/sonar-web/src/main/js/types/alm-settings.d.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index e7aaee5082797480e8e000cd6270e8f8dab24b5c..2d20b9f05115b48befa8184b67fa3feaf7d55612 100644 (file)
@@ -46,6 +46,16 @@ export function updateAzureConfiguration(data: T.AzureBindingDefinition & { newK
   return post('/api/alm_settings/update_azure', data).catch(throwGlobalError);
 }
 
+export function createBitbucketConfiguration(data: T.BitbucketBindingDefinition) {
+  return post('/api/alm_settings/create_bitbucket', data).catch(throwGlobalError);
+}
+
+export function updateBitbucketConfiguration(
+  data: T.BitbucketBindingDefinition & { newKey: string }
+) {
+  return post('/api/alm_settings/update_bitbucket', data).catch(throwGlobalError);
+}
+
 export function deleteConfiguration(key: string) {
   return post('/api/alm_settings/delete', { key }).catch(throwGlobalError);
 }
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketFormModal.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketFormModal.tsx
new file mode 100644 (file)
index 0000000..0f34916
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { AlmDefinitionFormField } from './AlmDefinitionFormField';
+
+export interface BitbucketFormModalProps {
+  formData: T.BitbucketBindingDefinition;
+  onFieldChange: (fieldId: keyof T.BitbucketBindingDefinition, value: string) => void;
+}
+
+export default function BitbucketFormModal(props: BitbucketFormModalProps) {
+  const { formData, onFieldChange } = props;
+
+  return (
+    <>
+      <AlmDefinitionFormField
+        autoFocus={true}
+        formData={formData}
+        help={true}
+        id="name"
+        isTextArea={false}
+        maxLength={40}
+        onFieldChange={onFieldChange}
+        propKey="key"
+      />
+      <AlmDefinitionFormField
+        formData={formData}
+        help={false}
+        id="url.bitbucket"
+        isTextArea={false}
+        maxLength={2000}
+        onFieldChange={onFieldChange}
+        propKey="url"
+      />
+      <AlmDefinitionFormField
+        formData={formData}
+        help={false}
+        id="personal_access_token"
+        isTextArea={true}
+        maxLength={2000}
+        onFieldChange={onFieldChange}
+        propKey="personalAccessToken"
+      />
+    </>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx
new file mode 100644 (file)
index 0000000..9f8af24
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import {
+  createBitbucketConfiguration,
+  updateBitbucketConfiguration
+} from '../../../../api/almSettings';
+import BitbucketTabRenderer from './BitbucketTabRenderer';
+
+interface Props {
+  definitions: T.BitbucketBindingDefinition[];
+  loading: boolean;
+  onDelete: (definitionKey: string) => void;
+  onUpdateDefinitions: () => void;
+}
+
+interface State {
+  editedDefinition?: T.BitbucketBindingDefinition;
+  projectCount?: number;
+}
+
+export default class BitbucketTab extends React.PureComponent<Props, State> {
+  mounted = false;
+  state: State = {};
+
+  componentDidMount() {
+    this.mounted = true;
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  handleCancel = () => {
+    this.setState({
+      editedDefinition: undefined
+    });
+  };
+
+  handleCreate = () => {
+    this.setState({ editedDefinition: { key: '', url: '', personalAccessToken: '' } });
+  };
+
+  handleEdit = (config: T.BitbucketBindingDefinition) => {
+    this.setState({ editedDefinition: config });
+  };
+
+  handleSubmit = (config: T.BitbucketBindingDefinition, originalKey: string) => {
+    const call = originalKey
+      ? updateBitbucketConfiguration({ newKey: config.key, ...config, key: originalKey })
+      : createBitbucketConfiguration(config);
+    return call
+      .then(() => {
+        if (this.mounted) {
+          this.setState({ editedDefinition: undefined });
+        }
+      })
+      .then(this.props.onUpdateDefinitions);
+  };
+
+  render() {
+    const { definitions, loading } = this.props;
+    const { editedDefinition } = this.state;
+    return (
+      <BitbucketTabRenderer
+        definitions={definitions}
+        editedDefinition={editedDefinition}
+        loading={loading}
+        onCancel={this.handleCancel}
+        onCreate={this.handleCreate}
+        onDelete={this.props.onDelete}
+        onEdit={this.handleEdit}
+        onSubmit={this.handleSubmit}
+      />
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx
new file mode 100644 (file)
index 0000000..52c1476
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { ALM_KEYS } from '../../utils';
+import AlmPRDecorationFormModal from './AlmPRDecorationFormModal';
+import BitbucketFormModal from './BitbucketFormModal';
+import BitbucketTable from './BitbucketTable';
+import TabHeader from './TabHeader';
+
+export interface BitbucketTabRendererProps {
+  editedDefinition?: T.BitbucketBindingDefinition;
+  definitions: T.BitbucketBindingDefinition[];
+  loading: boolean;
+  onCancel: () => void;
+  onCreate: () => void;
+  onDelete: (definitionKey: string) => void;
+  onEdit: (config: T.BitbucketBindingDefinition) => void;
+  onSubmit: (config: T.BitbucketBindingDefinition, originalKey: string) => void;
+}
+
+export default function BitbucketTabRenderer(props: BitbucketTabRendererProps) {
+  const { definitions, editedDefinition, loading } = props;
+  return (
+    <>
+      <TabHeader alm={ALM_KEYS.BITBUCKET} onCreate={props.onCreate} />
+
+      <BitbucketTable
+        definitions={definitions}
+        loading={loading}
+        onDelete={props.onDelete}
+        onEdit={props.onEdit}
+      />
+
+      {editedDefinition && (
+        <AlmPRDecorationFormModal
+          bindingDefinition={editedDefinition}
+          onCancel={props.onCancel}
+          onSubmit={props.onSubmit}>
+          {childProps => <BitbucketFormModal {...childProps} />}
+        </AlmPRDecorationFormModal>
+      )}
+    </>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTable.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTable.tsx
new file mode 100644 (file)
index 0000000..1c49cb3
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons';
+import EditIcon from 'sonar-ui-common/components/icons/EditIcon';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+
+export interface BitbucketTableProps {
+  definitions: T.BitbucketBindingDefinition[];
+  loading: boolean;
+  onDelete: (definitionKey: string) => void;
+  onEdit: (config: T.BitbucketBindingDefinition) => void;
+}
+
+export default function BitbucketTable(props: BitbucketTableProps) {
+  const { definitions, loading } = props;
+
+  if (loading) {
+    return <DeferredSpinner />;
+  }
+
+  return (
+    <table className="data zebra spacer-bottom">
+      <thead>
+        <tr>
+          <th>{translate('settings.pr_decoration.table.column.name')}</th>
+          <th>{translate(`settings.pr_decoration.table.column.bitbucket.url`)}</th>
+          <th className="thin">{translate('settings.pr_decoration.table.column.edit')}</th>
+          <th className="thin">{translate('settings.pr_decoration.table.column.delete')}</th>
+        </tr>
+      </thead>
+      <tbody>
+        {definitions.length < 1 ? (
+          <tr>
+            <td colSpan={4}>{translate('settings.pr_decoration.table.empty.bitbucket')}</td>
+          </tr>
+        ) : (
+          definitions.map(definition => (
+            <tr key={definition.key}>
+              <td>{definition.key}</td>
+              <td>{definition.url}</td>
+              <td>
+                <ButtonIcon onClick={() => props.onEdit(definition)}>
+                  <EditIcon />
+                </ButtonIcon>
+              </td>
+              <td>
+                <DeleteButton onClick={() => props.onDelete(definition.key)} />
+              </td>
+            </tr>
+          ))
+        )}
+      </tbody>
+    </table>
+  );
+}
index a10de20c8fe791db72c1450e1009c1e40de244bd..ded107bd3432552c24edeb34f646ee5da3b632eb 100644 (file)
@@ -22,6 +22,7 @@ import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import { almName, ALM_KEYS } from '../../utils';
 import AzureTab from './AzureTab';
+import BitbucketTab from './BitbucketTab';
 import DeleteModal from './DeleteModal';
 import GithubTab from './GithubTab';
 
@@ -58,6 +59,10 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
             key: ALM_KEYS.GITHUB,
             label: almName[ALM_KEYS.GITHUB]
           },
+          {
+            key: ALM_KEYS.BITBUCKET,
+            label: almName[ALM_KEYS.BITBUCKET]
+          },
           {
             key: ALM_KEYS.AZURE,
             label: almName[ALM_KEYS.AZURE]
@@ -74,6 +79,14 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
             onUpdateDefinitions={props.onUpdateDefinitions}
           />
         )}
+        {currentAlm === ALM_KEYS.BITBUCKET && (
+          <BitbucketTab
+            definitions={definitions.bitbucket}
+            loading={loading}
+            onDelete={props.onDelete}
+            onUpdateDefinitions={props.onUpdateDefinitions}
+          />
+        )}
         {currentAlm === ALM_KEYS.GITHUB && (
           <GithubTab
             definitions={definitions.github}
index 85f81567b5c2c27bb3930b196dc4ef5f0d2bb821..56367d96f2ac534b77752bd050416ce706342a36 100644 (file)
@@ -40,6 +40,7 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State
     currentAlm: ALM_KEYS.GITHUB,
     definitions: {
       [ALM_KEYS.AZURE]: [],
+      [ALM_KEYS.BITBUCKET]: [],
       [ALM_KEYS.GITHUB]: []
     },
     loading: true
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketFormModal-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketFormModal-test.tsx
new file mode 100644 (file)
index 0000000..8f475d1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockBitbucketDefinition } from '../../../../../helpers/testMocks';
+import BitbucketFormModal, { BitbucketFormModalProps } from '../BitbucketFormModal';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+  expect(shallowRender({ formData: mockBitbucketDefinition() })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<BitbucketFormModalProps> = {}) {
+  return shallow(
+    <BitbucketFormModal
+      formData={{ key: '', personalAccessToken: '', url: '' }}
+      onFieldChange={jest.fn()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx
new file mode 100644 (file)
index 0000000..8aef4b2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
+import {
+  createBitbucketConfiguration,
+  updateBitbucketConfiguration
+} from '../../../../../api/almSettings';
+import { mockBitbucketDefinition } from '../../../../../helpers/testMocks';
+import BitbucketTab from '../BitbucketTab';
+
+jest.mock('../../../../../api/almSettings', () => ({
+  countBindedProjects: jest.fn().mockResolvedValue(2),
+  createBitbucketConfiguration: jest.fn().mockResolvedValue({}),
+  deleteConfiguration: jest.fn().mockResolvedValue({}),
+  updateBitbucketConfiguration: jest.fn().mockResolvedValue({})
+}));
+
+beforeEach(() => {
+  jest.clearAllMocks();
+});
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should handle cancel', async () => {
+  const wrapper = shallowRender();
+
+  wrapper.setState({
+    editedDefinition: mockBitbucketDefinition()
+  });
+
+  wrapper.instance().handleCancel();
+
+  await waitAndUpdate(wrapper);
+
+  expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should create config', async () => {
+  const onUpdateDefinitions = jest.fn();
+  const config = mockBitbucketDefinition();
+  const wrapper = shallowRender({ onUpdateDefinitions });
+  wrapper.setState({ editedDefinition: config });
+
+  await wrapper.instance().handleSubmit(config, '');
+
+  expect(createBitbucketConfiguration).toBeCalledWith(config);
+  expect(onUpdateDefinitions).toBeCalled();
+  expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should update config', async () => {
+  const onUpdateDefinitions = jest.fn();
+  const config = mockBitbucketDefinition();
+  const wrapper = shallowRender({ onUpdateDefinitions });
+  wrapper.setState({ editedDefinition: config });
+
+  await wrapper.instance().handleSubmit(config, 'originalKey');
+
+  expect(updateBitbucketConfiguration).toBeCalledWith({
+    newKey: 'key',
+    ...config,
+    key: 'originalKey'
+  });
+  expect(onUpdateDefinitions).toBeCalled();
+  expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+function shallowRender(props: Partial<BitbucketTab['props']> = {}) {
+  return shallow<BitbucketTab>(
+    <BitbucketTab
+      definitions={[]}
+      loading={false}
+      onDelete={jest.fn()}
+      onUpdateDefinitions={jest.fn()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTable-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTable-test.tsx
new file mode 100644 (file)
index 0000000..37c0bc2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockBitbucketDefinition } from '../../../../../helpers/testMocks';
+import BitbucketTable, { BitbucketTableProps } from '../BitbucketTable';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+  expect(shallowRender({ definitions: [mockBitbucketDefinition()] })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<BitbucketTableProps> = {}) {
+  return shallow(
+    <BitbucketTable
+      definitions={[]}
+      loading={false}
+      onDelete={jest.fn()}
+      onEdit={jest.fn()}
+      {...props}
+    />
+  );
+}
index ef4fb6cd72ebc2bcb14fd4fad2cc0ae09dd72219..1f34d68213713a8f2c03b378561ea15c4fc7da9d 100644 (file)
@@ -33,7 +33,7 @@ function shallowRender(props: Partial<PRDecorationTabsProps> = {}) {
   return shallow(
     <PRDecorationTabs
       currentAlm={ALM_KEYS.GITHUB}
-      definitions={{ azure: [], github: [] }}
+      definitions={{ azure: [], bitbucket: [], github: [] }}
       loading={false}
       onCancel={jest.fn()}
       onConfirmDelete={jest.fn()}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketFormModal-test.tsx.snap
new file mode 100644 (file)
index 0000000..f1fb7f7
--- /dev/null
@@ -0,0 +1,103 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+  <AlmDefinitionFormField
+    autoFocus={true}
+    formData={
+      Object {
+        "key": "",
+        "personalAccessToken": "",
+        "url": "",
+      }
+    }
+    help={true}
+    id="name"
+    isTextArea={false}
+    maxLength={40}
+    onFieldChange={[MockFunction]}
+    propKey="key"
+  />
+  <AlmDefinitionFormField
+    formData={
+      Object {
+        "key": "",
+        "personalAccessToken": "",
+        "url": "",
+      }
+    }
+    help={false}
+    id="url.bitbucket"
+    isTextArea={false}
+    maxLength={2000}
+    onFieldChange={[MockFunction]}
+    propKey="url"
+  />
+  <AlmDefinitionFormField
+    formData={
+      Object {
+        "key": "",
+        "personalAccessToken": "",
+        "url": "",
+      }
+    }
+    help={false}
+    id="personal_access_token"
+    isTextArea={true}
+    maxLength={2000}
+    onFieldChange={[MockFunction]}
+    propKey="personalAccessToken"
+  />
+</Fragment>
+`;
+
+exports[`should render correctly 2`] = `
+<Fragment>
+  <AlmDefinitionFormField
+    autoFocus={true}
+    formData={
+      Object {
+        "key": "key",
+        "personalAccessToken": "asdf1234",
+        "url": "http://bbs.enterprise.com",
+      }
+    }
+    help={true}
+    id="name"
+    isTextArea={false}
+    maxLength={40}
+    onFieldChange={[MockFunction]}
+    propKey="key"
+  />
+  <AlmDefinitionFormField
+    formData={
+      Object {
+        "key": "key",
+        "personalAccessToken": "asdf1234",
+        "url": "http://bbs.enterprise.com",
+      }
+    }
+    help={false}
+    id="url.bitbucket"
+    isTextArea={false}
+    maxLength={2000}
+    onFieldChange={[MockFunction]}
+    propKey="url"
+  />
+  <AlmDefinitionFormField
+    formData={
+      Object {
+        "key": "key",
+        "personalAccessToken": "asdf1234",
+        "url": "http://bbs.enterprise.com",
+      }
+    }
+    help={false}
+    id="personal_access_token"
+    isTextArea={true}
+    maxLength={2000}
+    onFieldChange={[MockFunction]}
+    propKey="personalAccessToken"
+  />
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
new file mode 100644 (file)
index 0000000..68fb3da
--- /dev/null
@@ -0,0 +1,13 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<BitbucketTabRenderer
+  definitions={Array []}
+  loading={false}
+  onCancel={[Function]}
+  onCreate={[Function]}
+  onDelete={[MockFunction]}
+  onEdit={[Function]}
+  onSubmit={[Function]}
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTable-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTable-test.tsx.snap
new file mode 100644 (file)
index 0000000..95b2197
--- /dev/null
@@ -0,0 +1,88 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<table
+  className="data zebra spacer-bottom"
+>
+  <thead>
+    <tr>
+      <th>
+        settings.pr_decoration.table.column.name
+      </th>
+      <th>
+        settings.pr_decoration.table.column.bitbucket.url
+      </th>
+      <th
+        className="thin"
+      >
+        settings.pr_decoration.table.column.edit
+      </th>
+      <th
+        className="thin"
+      >
+        settings.pr_decoration.table.column.delete
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td
+        colSpan={4}
+      >
+        settings.pr_decoration.table.empty.bitbucket
+      </td>
+    </tr>
+  </tbody>
+</table>
+`;
+
+exports[`should render correctly 2`] = `
+<table
+  className="data zebra spacer-bottom"
+>
+  <thead>
+    <tr>
+      <th>
+        settings.pr_decoration.table.column.name
+      </th>
+      <th>
+        settings.pr_decoration.table.column.bitbucket.url
+      </th>
+      <th
+        className="thin"
+      >
+        settings.pr_decoration.table.column.edit
+      </th>
+      <th
+        className="thin"
+      >
+        settings.pr_decoration.table.column.delete
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr
+      key="key"
+    >
+      <td>
+        key
+      </td>
+      <td>
+        http://bbs.enterprise.com
+      </td>
+      <td>
+        <ButtonIcon
+          onClick={[Function]}
+        >
+          <EditIcon />
+        </ButtonIcon>
+      </td>
+      <td>
+        <DeleteButton
+          onClick={[Function]}
+        />
+      </td>
+    </tr>
+  </tbody>
+</table>
+`;
index 8337e33e576e528bac0f59f101e3ff9086c27acc..5e41638529d1fcd5d5f82876cf71ebbb89a988ef 100644 (file)
@@ -24,13 +24,13 @@ export const DEFAULT_CATEGORY = 'general';
 
 export enum ALM_KEYS {
   AZURE = 'azure',
-  // BITBUCKET = 'bitbucket',
+  BITBUCKET = 'bitbucket',
   GITHUB = 'github'
 }
 
 export const almName = {
   [ALM_KEYS.AZURE]: 'Azure DevOps Server',
-  // [ALM_KEYS.BITBUCKET]: 'Bitbucket Server',
+  [ALM_KEYS.BITBUCKET]: 'Bitbucket Server',
   [ALM_KEYS.GITHUB]: 'Github Enterprise'
 };
 
index 40ea08a4cfcd435d49a5797ca66bfe6a1deb6732..db978e76bee38e8f0233433a07d787e612e83501 100644 (file)
@@ -60,12 +60,23 @@ export function mockAzureDefinition(
   };
 }
 
+export function mockBitbucketDefinition(
+  overrides: Partial<T.BitbucketBindingDefinition> = {}
+): T.BitbucketBindingDefinition {
+  return {
+    key: 'key',
+    personalAccessToken: 'asdf1234',
+    url: 'http://bbs.enterprise.com',
+    ...overrides
+  };
+}
+
 export function mockGithubDefinition(
   overrides: Partial<T.GithubBindingDefinition> = {}
 ): T.GithubBindingDefinition {
   return {
     key: 'key',
-    url: 'http:alm.enterprise.com',
+    url: 'http://github.enterprise.com',
     appId: '123456',
     privateKey: 'asdf1234',
     ...overrides
index 16fd0be23da33e95e59302c3699a7bc8a3b59de1..17d7285bc574cb14c3c78a25c151d7348418c551 100644 (file)
@@ -30,18 +30,26 @@ declare namespace T {
 
   export interface AlmSettingsBindingDefinitions {
     azure: AzureBindingDefinition[];
+    bitbucket: BitbucketBindingDefinition[];
     github: GithubBindingDefinition[];
   }
 
-  export interface GithubBindingDefinition extends AlmSettingsBinding {
+  export interface AzureBindingDefinition extends AlmSettingsBinding {
+    personalAccessToken: string;
+  }
+
+  export interface BitbucketBindingDefinition extends AlmSettingsBinding {
+    personalAccessToken: string;
     url: string;
+  }
+  
+  export interface GithubBindingDefinition extends AlmSettingsBinding {
     appId: string;
     privateKey: string;
+    url: string;
   }
 
-  export interface AzureBindingDefinition extends AlmSettingsBinding {
-    personalAccessToken: string;
-  }
+
 
   export interface ProjectAlmBinding {
     key: string;
index 5ea5c4e3c7454f8846659304b8e6f5efdaf37cab..73113f8f983145a75561b92a79620b8901f2c2cd 100644 (file)
@@ -924,11 +924,16 @@ settings.pr_decoration.category=Pull Requests
 settings.pr_decoration.title=Pull Requests decoration
 settings.pr_decoration.description=When Pull Request decoration is enabled, SonarQube publishes the status of the analysis directly in your ALM Pull requests.
 settings.pr_decoration.manage_instances=Manage instances
-settings.pr_decoration.azure.info=The account that will be used to decorate Pull Requests needs write permission. {link}
+settings.pr_decoration.azure.info=Accounts that will be used to decorate Pull Requests needs Code: Read & Write permission. {link}
+settings.pr_decoration.bitbucket.info=Accounts that will be used to decorate Pull Requests needs 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.table.title=Pull 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.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 instance URL
 settings.pr_decoration.table.column.app_id=App ID
 settings.pr_decoration.table.column.edit=Edit
@@ -941,6 +946,7 @@ settings.pr_decoration.form.header.create=Create a Pull Request decoration confi
 settings.pr_decoration.form.header.edit=Edit the Pull Request decoration configuration
 settings.pr_decoration.form.name=Configuration name
 settings.pr_decoration.form.name.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.url.bitbucket=Bitbucket Server URL
 settings.pr_decoration.form.url.github=GitHub Enterprise URL
 settings.pr_decoration.form.app_id=GitHub App ID
 settings.pr_decoration.form.private_key=Private Key