import java.net.HttpURLConnection;
import java.util.Objects;
import java.util.function.Function;
+import java.util.function.UnaryOperator;
import javax.annotation.Nullable;
import okhttp3.Credentials;
import okhttp3.FormBody;
}
protected <G> G doGet(String accessToken, HttpUrl url, Function<Response, G> handler) {
- Request request = prepareRequestWithAccessToken(accessToken, GET, url, null);
- return doCall(request, handler, false);
+ return doGet(accessToken, url, handler, false);
}
protected void doPost(String accessToken, HttpUrl url, RequestBody body) {
});
}
- private static <T> ErrorDetails getErrorDetails(@Nullable ResponseBody body, Function<String, String> parser) throws IOException {
+ private static ErrorDetails getErrorDetails(@Nullable ResponseBody body, UnaryOperator<String> parser) throws IOException {
if (body == null) {
return new ErrorDetails("", null);
}
try {
return new ErrorDetails(bodyStr, parser.apply(bodyStr));
} catch (JsonParseException e) {
- // ignore
+ //ignore
}
}
return new ErrorDetails(bodyStr, null);
export interface AlmBindingDefinitionFormChildrenProps<B> {
formData: B;
- hideKeyField?: boolean;
onFieldChange: (fieldId: keyof B, value: string) => void;
- readOnly?: boolean;
}
interface Props<B> {
bindingDefinition: B;
children: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode;
help?: React.ReactNode;
- hideKeyField?: boolean;
isSecondInstance?: boolean;
onCancel?: () => void;
onDelete?: (definitionKey: string) => void;
};
canSubmit = () => {
- const { hideKeyField, optionalFields } = this.props;
+ const { optionalFields } = this.props;
const { formData, touched } = this.state;
- let values;
- if (hideKeyField) {
- values = omit(formData, 'key');
- } else {
- values = { ...formData };
- }
+ let values = { ...formData };
if (optionalFields && optionalFields.length > 0) {
- values = omit(values, optionalFields);
+ values = omit(values, optionalFields) as B;
}
return touched && !Object.values(values).some(v => !v);
optional?: boolean;
overwriteOnly?: boolean;
propKey: keyof B;
- readOnly?: boolean;
value: string;
}
optional,
overwriteOnly = false,
propKey,
- readOnly = false,
value
} = props;
const [showField, setShowField] = React.useState(!overwriteOnly);
{showField && isTextArea && (
<textarea
className="settings-large-input"
- disabled={readOnly}
id={id}
maxLength={maxLength || 2000}
onChange={e => props.onFieldChange(propKey, e.currentTarget.value)}
<input
autoFocus={autoFocus}
className="input-super-large"
- disabled={readOnly}
id={id}
maxLength={maxLength || 100}
name={id}
handleSubmit = (config: B, originalKey: string) => {
const call = originalKey
? this.props.updateConfiguration({ newKey: config.key, ...config, key: originalKey })
- : // If there's no support for multi-ALM binding, the key will be an empty string.
- // Set a default.
- this.props.createConfiguration({ ...config, key: config.key || this.props.alm });
+ : this.props.createConfiguration({ ...config });
this.setState({ submitting: true });
return call
const {
alm,
branchesEnabled,
- defaultBinding,
definitions,
definitionStatus,
form,
<AlmTabRenderer
alm={alm}
branchesEnabled={branchesEnabled}
- defaultBinding={defaultBinding}
definitions={definitions}
definitionStatus={definitionStatus}
editedDefinition={editedDefinition}
branchesEnabled: boolean;
definitionStatus: T.Dict<AlmSettingsBindingStatus>;
editedDefinition?: B;
- defaultBinding: B;
definitions: B[];
form: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode;
help: React.ReactNode;
export interface AzureFormProps {
formData: AzureBindingDefinition;
- hideKeyField?: boolean;
onFieldChange: (fieldId: keyof AzureBindingDefinition, value: string) => void;
- readOnly?: boolean;
}
export default function AzureForm(props: AzureFormProps) {
- const { formData, hideKeyField, onFieldChange, readOnly } = props;
+ const { formData, onFieldChange } = props;
return (
<>
- {!hideKeyField && (
- <AlmBindingDefinitionFormField
- autoFocus={true}
- help={translate('settings.almintegration.form.name.azure.help')}
- id="name.azure"
- onFieldChange={onFieldChange}
- propKey="key"
- readOnly={readOnly}
- value={formData.key}
- />
- )}
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.almintegration.form.name.azure.help')}
+ id="name.azure"
+ onFieldChange={onFieldChange}
+ propKey="key"
+ value={formData.key}
+ />
<AlmBindingDefinitionFormField
help={
<>
maxLength={2000}
onFieldChange={onFieldChange}
propKey="url"
- readOnly={readOnly}
value={formData.url || ''}
/>
<AlmBindingDefinitionFormField
onFieldChange={onFieldChange}
overwriteOnly={Boolean(formData.key)}
propKey="personalAccessToken"
- readOnly={readOnly}
value={formData.personalAccessToken}
/>
</>
export interface GithubFormProps {
formData: GithubBindingDefinition;
- hideKeyField?: boolean;
onFieldChange: (fieldId: keyof GithubBindingDefinition, value: string) => void;
- readOnly?: boolean;
}
export default function GithubForm(props: GithubFormProps) {
- const { formData, hideKeyField, onFieldChange, readOnly } = props;
+ const { formData, onFieldChange } = props;
return (
<>
- {!hideKeyField && (
- <AlmBindingDefinitionFormField
- autoFocus={true}
- help={translate('settings.almintegration.form.name.github.help')}
- id="name.github"
- onFieldChange={onFieldChange}
- propKey="key"
- readOnly={readOnly}
- value={formData.key}
- />
- )}
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.almintegration.form.name.github.help')}
+ id="name.github"
+ onFieldChange={onFieldChange}
+ propKey="key"
+ value={formData.key}
+ />
<AlmBindingDefinitionFormField
help={
<>
maxLength={2000}
onFieldChange={onFieldChange}
propKey="url"
- readOnly={readOnly}
value={formData.url}
/>
<AlmBindingDefinitionFormField
maxLength={80}
onFieldChange={onFieldChange}
propKey="appId"
- readOnly={readOnly}
value={formData.appId}
/>
<AlmBindingDefinitionFormField
maxLength={80}
onFieldChange={onFieldChange}
propKey="clientId"
- readOnly={readOnly}
value={formData.clientId}
/>
<AlmBindingDefinitionFormField
onFieldChange={onFieldChange}
overwriteOnly={Boolean(formData.key)}
propKey="clientSecret"
- readOnly={readOnly}
value={formData.clientSecret}
/>
<AlmBindingDefinitionFormField
onFieldChange={onFieldChange}
overwriteOnly={Boolean(formData.key)}
propKey="privateKey"
- readOnly={readOnly}
value={formData.privateKey}
/>
</>
export interface GitlabFormProps {
formData: GitlabBindingDefinition;
- hideKeyField?: boolean;
onFieldChange: (fieldId: keyof GitlabBindingDefinition, value: string) => void;
- readOnly?: boolean;
}
export default function GitlabForm(props: GitlabFormProps) {
- const { formData, hideKeyField, onFieldChange, readOnly } = props;
+ const { formData, onFieldChange } = props;
return (
<>
- {!hideKeyField && (
- <AlmBindingDefinitionFormField
- autoFocus={true}
- help={translate('settings.almintegration.form.name.gitlab.help')}
- id="name.gitlab"
- onFieldChange={onFieldChange}
- propKey="key"
- readOnly={readOnly}
- value={formData.key}
- />
- )}
+ <AlmBindingDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.almintegration.form.name.gitlab.help')}
+ id="name.gitlab"
+ onFieldChange={onFieldChange}
+ propKey="key"
+ value={formData.key}
+ />
<AlmBindingDefinitionFormField
help={
<>
maxLength={2000}
onFieldChange={onFieldChange}
propKey="url"
- readOnly={readOnly}
value={formData.url || ''}
/>
<AlmBindingDefinitionFormField
onFieldChange={onFieldChange}
overwriteOnly={Boolean(formData.key)}
propKey="personalAccessToken"
- readOnly={readOnly}
value={formData.personalAccessToken}
/>
</>
wrapper.setState({ formData: mockGithubBindingDefinition(), touched: true });
expect(wrapper.instance().canSubmit()).toBe(true);
- wrapper.setState({ formData: mockGithubBindingDefinition({ key: '' }), touched: true });
- wrapper.setProps({ hideKeyField: true });
- expect(wrapper.instance().canSubmit()).toBe(true);
-
wrapper.setState({ formData: mockGithubBindingDefinition({ url: '' }), touched: true });
wrapper.setProps({ optionalFields: ['url'] });
expect(wrapper.instance().canSubmit()).toBe(true);
it('should render correctly with validation', () => {
const githubProps = {
alm: AlmKeys.GitHub,
- defaultBinding: mockGithubBindingDefinition(),
definitions: [mockGithubBindingDefinition()]
};
expect(shallowRender(githubProps)).toMatchSnapshot('default');
function shallowRenderAzure(props: Partial<AlmTabRendererProps<AzureBindingDefinition>> = {}) {
return shallowRender({
- defaultBinding: mockAzureBindingDefinition(),
definitions: [mockAzureBindingDefinition()],
...props
});
<AlmTabRenderer
alm={AlmKeys.Azure}
branchesEnabled={true}
- defaultBinding={{} as any}
definitions={[]}
definitionStatus={{}}
form={jest.fn()}
</label>
<input
className="input-super-large"
- disabled={false}
id="key"
maxLength={40}
name="key"
</label>
<input
className="input-super-large"
- disabled={false}
id="key"
maxLength={40}
name="key"
</label>
<textarea
className="settings-large-input"
- disabled={false}
id="key"
maxLength={40}
onChange={[Function]}
</label>
<input
className="input-super-large"
- disabled={false}
id="key"
maxLength={40}
name="key"
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
.execute()).isInstanceOf(IllegalArgumentException.class).hasMessage("Invalid Azure URL or Personal Access Token");
}
+ @Test
+ public void bitbucketcloud_validation_checks() {
+ AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertBitbucketCloudAlmSetting());
+
+ ws.newRequest()
+ .setParam("key", almSetting.getKey())
+ .execute();
+
+ verify(bitbucketCloudRestClient).validate(almSetting.getClientId(), almSetting.getClientSecret(), almSetting.getAppId());
+ }
+
+ @Test
+ public void bitbucketcloud_validation_check_fails() {
+ AlmSettingDto almSetting = insertAlmSetting(db.almSettings().insertBitbucketCloudAlmSetting());
+
+ doThrow(IllegalArgumentException.class)
+ .when(bitbucketCloudRestClient).validate(almSetting.getClientId(), almSetting.getClientSecret(), almSetting.getAppId());
+
+ TestRequest request = ws.newRequest()
+ .setParam("key", almSetting.getKey());
+ assertThatThrownBy(request::execute).isInstanceOf(IllegalArgumentException.class);
+ }
+
private AlmSettingDto insertAlmSetting(AlmSettingDto almSettingDto) {
UserDto user = db.users().insertUser();
userSession.logIn(user).setSystemAdministrator();