Browse Source

SONAR-14394 Add frontend for bitbucket cloud project binding.

tags/8.7.0.41497
Mathieu Suen 3 years ago
parent
commit
0da0c9feef

+ 5
- 0
server/sonar-web/src/main/js/api/alm-settings.ts View File

AzureProjectAlmBindingParams, AzureProjectAlmBindingParams,
BitbucketBindingDefinition, BitbucketBindingDefinition,
BitbucketCloudBindingDefinition, BitbucketCloudBindingDefinition,
BitbucketCloudProjectAlmBindingParams,
BitbucketProjectAlmBindingParams, BitbucketProjectAlmBindingParams,
GithubBindingDefinition, GithubBindingDefinition,
GithubProjectAlmBindingParams, GithubProjectAlmBindingParams,
return post('/api/alm_settings/set_bitbucket_binding', data).catch(throwGlobalError); return post('/api/alm_settings/set_bitbucket_binding', data).catch(throwGlobalError);
} }


export function setProjectBitbucketCloudBinding(data: BitbucketCloudProjectAlmBindingParams) {
return post('/api/alm_settings/set_bitbucketcloud_binding', data).catch(throwGlobalError);
}

export function setProjectGithubBinding(data: GithubProjectAlmBindingParams) { export function setProjectGithubBinding(data: GithubProjectAlmBindingParams) {
return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError); return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError);
} }

+ 38
- 9
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx View File

}); });


it('should filter alm bindings appropriately', async () => { it('should filter alm bindings appropriately', async () => {
(getAlmSettings as jest.Mock).mockResolvedValueOnce([
{ alm: AlmKeys.Azure },
{ alm: AlmKeys.BitbucketServer, url: 'b1' },
{ alm: AlmKeys.BitbucketServer, url: 'b2' },
{ alm: AlmKeys.GitHub },
{ alm: AlmKeys.GitLab, url: 'gitlab.com' }
]);
(getAlmSettings as jest.Mock)
.mockResolvedValueOnce([
// Only faulty configs.
{ alm: AlmKeys.Azure }, // Missing some configuration; will be ignored.
{ alm: AlmKeys.BitbucketCloud }, // Bitbucket Cloud isn't supported.
{ alm: AlmKeys.GitLab } // Missing some configuration; will be ignored.
])
.mockResolvedValueOnce([
// All correct configs.
{ alm: AlmKeys.Azure, url: 'http://ado.example.com' },
{ alm: AlmKeys.BitbucketServer, url: 'b1' },
{ alm: AlmKeys.GitHub },
{ alm: AlmKeys.GitLab, url: 'gitlab.com' }
])
.mockResolvedValueOnce([
// Only duplicate ALMs; should all be ignored.
{ alm: AlmKeys.Azure, url: 'http://ado.example.com' },
{ alm: AlmKeys.Azure, url: 'http://ado.example.com' },
{ alm: AlmKeys.BitbucketServer, url: 'b1' },
{ alm: AlmKeys.BitbucketServer, url: 'b1' },
{ alm: AlmKeys.GitHub },
{ alm: AlmKeys.GitHub },
{ alm: AlmKeys.GitLab, url: 'gitlab.com' },
{ alm: AlmKeys.GitLab, url: 'gitlab.com' }
]);


const wrapper = shallowRender();
let wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.state().boundAlms).toEqual([]);


wrapper = shallowRender();
await waitAndUpdate(wrapper); await waitAndUpdate(wrapper);
expect(wrapper.state().boundAlms).toEqual([
AlmKeys.Azure,
AlmKeys.BitbucketServer,
AlmKeys.GitHub,
AlmKeys.GitLab
]);


expect(wrapper.state().boundAlms).toEqual([AlmKeys.GitHub, AlmKeys.GitLab]);
wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.state().boundAlms).toEqual([]);
}); });


function shallowRender(overrides: Partial<ProjectCreationMenu['props']> = {}) { function shallowRender(overrides: Partial<ProjectCreationMenu['props']> = {}) {

+ 21
- 1
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx View File

propKey: 'slug', propKey: 'slug',
value: slug || '' value: slug || ''
})} })}
{renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.Bitbucket])}
{renderMonoRepoFieldWithDocLink(ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketServer])}
</>
);
case AlmKeys.BitbucketCloud:
return (
<>
{renderField({
help: true,
helpParams: {
example: (
<>
{'https://bitbucket.org/{workspace}/'}
<strong>{'{repository}'}</strong>
</>
)
},
id: 'bitbucketcloud.repository',
onFieldChange: props.onFieldChange,
propKey: 'repository',
value: repository || ''
})}
</> </>
); );
case AlmKeys.GitHub: case AlmKeys.GitHub:

+ 11
- 0
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx View File

getProjectAlmBinding, getProjectAlmBinding,
setProjectAzureBinding, setProjectAzureBinding,
setProjectBitbucketBinding, setProjectBitbucketBinding,
setProjectBitbucketCloudBinding,
setProjectGithubBinding, setProjectGithubBinding,
setProjectGitlabBinding setProjectGitlabBinding
} from '../../../../api/alm-settings'; } from '../../../../api/alm-settings';
monorepo monorepo
}); });
} }
case AlmKeys.BitbucketCloud: {
if (!repository) {
return Promise.reject();
}
return setProjectBitbucketCloudBinding({
almSetting,
project,
repository
});
}
case AlmKeys.GitHub: { case AlmKeys.GitHub: {
// By default it must remain true. // By default it must remain true.
const summaryCommentEnabled = const summaryCommentEnabled =

+ 1
- 0
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/AlmSpecificForm-test.tsx View File

[AlmKeys.Azure, true], [AlmKeys.Azure, true],
[AlmKeys.BitbucketServer, false], [AlmKeys.BitbucketServer, false],
[AlmKeys.BitbucketServer, true], [AlmKeys.BitbucketServer, true],
[AlmKeys.BitbucketCloud, false],
[AlmKeys.GitHub, false], [AlmKeys.GitHub, false],
[AlmKeys.GitHub, true], [AlmKeys.GitHub, true],
[AlmKeys.GitLab, false], [AlmKeys.GitLab, false],

+ 30
- 1
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-test.tsx View File

getProjectAlmBinding, getProjectAlmBinding,
setProjectAzureBinding, setProjectAzureBinding,
setProjectBitbucketBinding, setProjectBitbucketBinding,
setProjectBitbucketCloudBinding,
setProjectGithubBinding, setProjectGithubBinding,
setProjectGitlabBinding setProjectGitlabBinding
} from '../../../../../api/alm-settings'; } from '../../../../../api/alm-settings';
setProjectBitbucketBinding: jest.fn().mockResolvedValue(undefined), setProjectBitbucketBinding: jest.fn().mockResolvedValue(undefined),
setProjectGithubBinding: jest.fn().mockResolvedValue(undefined), setProjectGithubBinding: jest.fn().mockResolvedValue(undefined),
setProjectGitlabBinding: jest.fn().mockResolvedValue(undefined), setProjectGitlabBinding: jest.fn().mockResolvedValue(undefined),
setProjectBitbucketCloudBinding: jest.fn().mockResolvedValue(undefined),
deleteProjectAlmBinding: jest.fn().mockResolvedValue(undefined) deleteProjectAlmBinding: jest.fn().mockResolvedValue(undefined)
})); }));


{ key: 'github', alm: AlmKeys.GitHub }, { key: 'github', alm: AlmKeys.GitHub },
{ key: 'azure', alm: AlmKeys.Azure }, { key: 'azure', alm: AlmKeys.Azure },
{ key: 'bitbucket', alm: AlmKeys.BitbucketServer }, { key: 'bitbucket', alm: AlmKeys.BitbucketServer },
{ key: 'gitlab', alm: AlmKeys.GitLab }
{ key: 'gitlab', alm: AlmKeys.GitLab },
{ key: 'bitbucketcloud', alm: AlmKeys.BitbucketCloud }
]; ];


it('should work for github', async () => { it('should work for github', async () => {
}); });
expect(wrapper.state().success).toBe(true); expect(wrapper.state().success).toBe(true);
}); });

it('should work for bitbucket cloud', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
const bitbucketKey = 'bitbucketcloud';
const repository = 'repoKey';
wrapper.setState({ formData: { key: bitbucketKey, repository }, instances: [] });
wrapper.instance().handleSubmit();
await waitAndUpdate(wrapper);
expect(setProjectBitbucketCloudBinding).not.toBeCalled();

wrapper.setState({ formData: { key: bitbucketKey, repository }, instances });
wrapper.instance().handleSubmit();
await waitAndUpdate(wrapper);

expect(setProjectBitbucketCloudBinding).toBeCalledWith({
almSetting: bitbucketKey,
project: PROJECT_KEY,
repository
});
expect(wrapper.state().success).toBe(true);
});
}); });


describe.each([[500], [404]])('For status %i', status => { describe.each([[500], [404]])('For status %i', status => {
[AlmKeys.BitbucketServer, {}], [AlmKeys.BitbucketServer, {}],
[AlmKeys.BitbucketServer, { slug: 'test' }], [AlmKeys.BitbucketServer, { slug: 'test' }],
[AlmKeys.BitbucketServer, { repository: 'test' }], [AlmKeys.BitbucketServer, { repository: 'test' }],
[AlmKeys.BitbucketCloud, {}],
[AlmKeys.GitHub, {}], [AlmKeys.GitHub, {}],
[AlmKeys.GitLab, {}] [AlmKeys.GitLab, {}]
])('should properly reject promise for %s & %s', async (almKey: AlmKeys, params: {}) => { ])('should properly reject promise for %s & %s', async (almKey: AlmKeys, params: {}) => {
instances: [ instances: [
{ key: 'azure', alm: AlmKeys.Azure }, { key: 'azure', alm: AlmKeys.Azure },
{ key: 'bitbucket', alm: AlmKeys.BitbucketServer }, { key: 'bitbucket', alm: AlmKeys.BitbucketServer },
{ key: 'bitbucketcloud', alm: AlmKeys.BitbucketCloud },
{ key: 'github', alm: AlmKeys.GitHub }, { key: 'github', alm: AlmKeys.GitHub },
{ key: 'gitlab', alm: AlmKeys.GitLab } { key: 'gitlab', alm: AlmKeys.GitLab }
] ]
{ values: { key: 'github', repository: 'asdf' }, result: true }, { values: { key: 'github', repository: 'asdf' }, result: true },
{ values: { key: 'bitbucket', repository: 'key' }, result: false }, { values: { key: 'bitbucket', repository: 'key' }, result: false },
{ values: { key: 'bitbucket', repository: 'key', slug: 'slug' }, result: true }, { values: { key: 'bitbucket', repository: 'key', slug: 'slug' }, result: true },
{ values: { key: 'bitbucketcloud', repository: '' }, result: false },
{ values: { key: 'bitbucketcloud', repository: 'key' }, result: true },
{ values: { key: 'gitlab' }, result: false }, { values: { key: 'gitlab' }, result: false },
{ values: { key: 'gitlab', repository: 'key' }, result: true } { values: { key: 'gitlab', repository: 'key' }, result: true }
].forEach(({ values, result }) => { ].forEach(({ values, result }) => {

+ 49
- 0
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap View File

</Fragment> </Fragment>
`; `;


exports[`it should render correctly for bitbucketcloud and monorepo=false 1`] = `
<Fragment>
<div
className="form-field"
>
<label
className="display-flex-center"
htmlFor="bitbucketcloud.repository"
>
settings.pr_decoration.binding.form.bitbucketcloud.repository
<em
className="mandatory"
>
*
</em>
<HelpTooltip
className="spacer-left"
overlay={
<FormattedMessage
defaultMessage="settings.pr_decoration.binding.form.bitbucketcloud.repository.help"
id="settings.pr_decoration.binding.form.bitbucketcloud.repository.help"
values={
Object {
"example": <React.Fragment>
https://bitbucket.org/{workspace}/
<strong>
{repository}
</strong>
</React.Fragment>,
}
}
/>
}
placement="right"
/>
</label>
<input
className="input-super-large"
id="bitbucketcloud.repository"
maxLength={256}
name="bitbucketcloud.repository"
onChange={[Function]}
type="text"
value=""
/>
</div>
</Fragment>
`;

exports[`it should render correctly for github and monorepo=false 1`] = ` exports[`it should render correctly for github and monorepo=false 1`] = `
<Fragment> <Fragment>
<div <div

+ 4
- 0
server/sonar-web/src/main/js/types/alm-settings.ts View File

monorepo: boolean; monorepo: boolean;
} }


export interface BitbucketCloudProjectAlmBindingParams extends ProjectAlmBindingParams {
repository: string;
}

export interface GithubProjectAlmBindingParams extends ProjectAlmBindingParams { export interface GithubProjectAlmBindingParams extends ProjectAlmBindingParams {
repository: string; repository: string;
summaryCommentEnabled: boolean; summaryCommentEnabled: boolean;

+ 3
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

settings.pr_decoration.binding.form.bitbucket.repository.help=The project key is part of your Bitbucket Server repository URL. Example: ({example}) settings.pr_decoration.binding.form.bitbucket.repository.help=The project key is part of your Bitbucket Server repository URL. Example: ({example})
settings.pr_decoration.binding.form.bitbucket.slug=Repository SLUG settings.pr_decoration.binding.form.bitbucket.slug=Repository SLUG
settings.pr_decoration.binding.form.bitbucket.slug.help=The Repository Slug is part of your Bitbucket Server repository URL. Example: ({example}) settings.pr_decoration.binding.form.bitbucket.slug.help=The Repository Slug is part of your Bitbucket Server repository URL. Example: ({example})
settings.pr_decoration.binding.form.bitbucketcloud.repository=Repository SLUG
settings.pr_decoration.binding.form.bitbucketcloud.repository.help=The Repository SLUG is part of your Bitbucket Cloud URL. Example: {example}

settings.pr_decoration.binding.form.gitlab.repository=Project ID settings.pr_decoration.binding.form.gitlab.repository=Project ID


property.category.general=General property.category.general=General

Loading…
Cancel
Save