Skip to content

Commit

Permalink
feat(cf): Add Updatable Flag To Create Service (spinnaker#6706)
Browse files Browse the repository at this point in the history
- repaired validators for required fields
- converted CreateUserProvidedInput's handling of data to be consistent with CreateServiceInstanceDirectInput
  • Loading branch information
stuart-pollock authored and jkschneider committed Mar 15, 2019
1 parent facc737 commit dafedac
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ export class CloudfoundryDeployServiceStageConfig extends React.Component<
> {
private defaultDirectManifest = {
direct: {
parameters: '',
service: '',
serviceInstanceName: '',
servicePlan: '',
parameters: '',
updatable: true,
},
};

Expand Down Expand Up @@ -97,7 +98,7 @@ export class CloudfoundryDeployServiceStageConfig extends React.Component<
};

private onArtifactChanged = (artifact: IArtifact): void => {
this.props.updateStageField({ manifest: { artifact: artifact } });
this.props.updateStageField({ manifest: { artifact } });
};

private regionUpdated = (option: Option<string>): void => {
Expand All @@ -110,7 +111,7 @@ export class CloudfoundryDeployServiceStageConfig extends React.Component<
};

private serviceManifestSourceUpdated = (manifest: ICloudFoundryServiceManifestSource) => {
this.props.updateStageField({ manifest: manifest });
this.props.updateStageField({ manifest });
};

private userProvidedUpdated = (event: React.ChangeEvent<HTMLInputElement>): void => {
Expand All @@ -127,13 +128,17 @@ export class CloudfoundryDeployServiceStageConfig extends React.Component<
if (directInput) {
const directManifest = (manifest && manifest.direct) || this.defaultDirectManifest;
manifestInput = userProvided ? (
<CreateUserProvidedInput onChange={this.serviceManifestSourceUpdated} serviceInput={directManifest} />
<CreateUserProvidedInput
onChange={this.serviceManifestSourceUpdated}
service={directManifest}
onServiceChanged={direct => this.serviceManifestSourceUpdated({ direct })}
/>
) : (
<CreateServiceInstanceDirectInput
credentials={credentials}
region={region}
service={directManifest}
onServiceChanged={direct => this.serviceManifestSourceUpdated({ direct: direct })}
onServiceChanged={direct => this.serviceManifestSourceUpdated({ direct })}
/>
);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ export class CreateServiceInstanceDirectInput extends React.Component<
});
};

private updatableUpdated = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.onServiceChanged({
...this.props.service,
updatable: event.target.checked,
});
};

public render() {
const { service } = this.props;
const services = this.state.serviceNamesAndPlans.map(item => item.name);
Expand Down Expand Up @@ -127,6 +134,15 @@ export class CreateServiceInstanceDirectInput extends React.Component<
<StageConfigField label="Parameters">
<TextAreaInput className="form-control" onChange={this.parametersUpdated} value={service.parameters || ''} />
</StageConfigField>
<StageConfigField label="Updatable">
<input type="checkbox" checked={!!service.updatable} onChange={this.updatableUpdated} />
{!service.updatable && (
<div>
If a service instance with the name '{service.serviceInstanceName}' is already present then it will not be
updated, and the operation will succeed.
</div>
)}
</StageConfigField>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,99 +10,89 @@ import {

interface ICreateServiceInstanceUserProvidedInputProps {
onChange: (serviceInput: ICloudFoundryServiceManifestSource) => void;
serviceInput: ICloudFoundryServiceUserProvidedSource;
service: ICloudFoundryServiceUserProvidedSource;
onServiceChanged: (_: ICloudFoundryServiceUserProvidedSource) => void;
}

interface ICreateServiceInstanceUserProvidedInputState {
serviceInstanceName: string;
tags?: string[];
syslogDrainUrl?: string;
credentials?: string;
routeServiceUrl: string;
}

export class CreateUserProvidedInput extends React.Component<
ICreateServiceInstanceUserProvidedInputProps,
ICreateServiceInstanceUserProvidedInputState
> {
export class CreateUserProvidedInput extends React.Component<ICreateServiceInstanceUserProvidedInputProps> {
constructor(props: ICreateServiceInstanceUserProvidedInputProps) {
super(props);
const { serviceInput } = props;
this.state = { ...serviceInput };
}

private serviceInstanceNameUpdated = (event: React.ChangeEvent<HTMLInputElement>): void => {
const serviceInstanceName = event.target.value;
const { onChange, serviceInput } = this.props;
this.setState({ serviceInstanceName });
onChange({
...serviceInput,
serviceInstanceName,
} as ICloudFoundryServiceManifestSource);
private serviceInstanceNameUpdated = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.onServiceChanged({
...this.props.service,
serviceInstanceName: event.target.value,
});
};

private syslogDrainUrlUpdated = (event: React.ChangeEvent<HTMLInputElement>): void => {
const syslogDrainUrl = event.target.value;
const { onChange, serviceInput } = this.props;
this.setState({ syslogDrainUrl });
onChange({
...serviceInput,
syslogDrainUrl,
} as ICloudFoundryServiceManifestSource);
this.props.onServiceChanged({
...this.props.service,
syslogDrainUrl: event.target.value,
});
};

private routeServiceUrlUpdated = (event: React.ChangeEvent<HTMLInputElement>): void => {
const routeServiceUrl = event.target.value;
const { onChange, serviceInput } = this.props;
this.setState({ routeServiceUrl });
onChange({
...serviceInput,
routeServiceUrl,
} as ICloudFoundryServiceManifestSource);
this.props.onServiceChanged({
...this.props.service,
routeServiceUrl: event.target.value,
});
};

private credentialsUpdated = (event: React.ChangeEvent<HTMLTextAreaElement>): void => {
const credentials = event.target.value;
const { onChange, serviceInput } = this.props;
this.setState({ credentials });
onChange({
...serviceInput,
credentials,
} as ICloudFoundryServiceManifestSource);
this.props.onServiceChanged({
...this.props.service,
credentials: event.target.value,
});
};

private tagsUpdated = (tags: string[]) => {
const { onChange, serviceInput } = this.props;
this.setState({ tags });
onChange({
...serviceInput,
tags,
} as ICloudFoundryServiceManifestSource);
this.props.onServiceChanged({
...this.props.service,
tags: tags,
});
};

private updatableUpdated = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.onServiceChanged({
...this.props.service,
updatable: event.target.checked,
});
};

public render() {
const { serviceInstanceName, tags, syslogDrainUrl, credentials, routeServiceUrl } = this.state;
const { service } = this.props;
return (
<>
<StageConfigField label="Service Instance Name">
<TextInput
type="text"
className="form-control"
onChange={this.serviceInstanceNameUpdated}
value={serviceInstanceName}
value={service.serviceInstanceName}
/>
</StageConfigField>
<StageConfigField label="Syslog Drain URL">
<TextInput onChange={this.syslogDrainUrlUpdated} value={syslogDrainUrl} />
<TextInput onChange={this.syslogDrainUrlUpdated} value={service.syslogDrainUrl} />
</StageConfigField>
<StageConfigField label="Resource Service URL">
<TextInput onChange={this.routeServiceUrlUpdated} value={routeServiceUrl} />
<TextInput onChange={this.routeServiceUrlUpdated} value={service.routeServiceUrl} />
</StageConfigField>
<StageConfigField label="Credentials">
<TextAreaInput onChange={this.credentialsUpdated} value={credentials} />
<TextAreaInput onChange={this.credentialsUpdated} value={service.credentials} />
</StageConfigField>
<StageConfigField label="Tags">
<ServiceTagsInput tags={tags} onChange={this.tagsUpdated} />
<ServiceTagsInput tags={service.tags || []} onChange={this.tagsUpdated} />
</StageConfigField>
<StageConfigField label="Updatable">
<input type="checkbox" checked={!!service.updatable} onChange={this.updatableUpdated} />
{!service.updatable && (
<div>
If a service instance with the name '{service.serviceInstanceName}' is already present then it will not be
updated, and the operation will succeed.
</div>
)}
</StageConfigField>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface ICloudfoundryServiceManifestDirectSource {
serviceInstanceName: string;
servicePlan: string;
tags?: string[];
updatable: boolean;
}

export interface ICloudFoundryServiceUserProvidedSource {
Expand All @@ -14,6 +15,7 @@ export interface ICloudFoundryServiceUserProvidedSource {
serviceInstanceName: string;
syslogDrainUrl?: string;
tags?: string[];
updatable: boolean;
}

export interface ICloudFoundryServiceManifestSource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const sourceType = (manifest: ICloudFoundryServiceManifestSource, userProvided:
}
};

const sourceStruct = (manifest: ICloudFoundryServiceManifestSource) => {
return manifest.direct ? 'direct' : 'artifact';
};

PipelineConfigValidator.registerValidator(
'requiredDeployServiceField',
new class implements IStageOrTriggerValidator {
Expand All @@ -39,7 +43,7 @@ PipelineConfigValidator.registerValidator(
if (sourceType(serviceInput, get(stage, 'userProvided')) !== validationConfig.manifestSource) {
return null;
}
const manifestSource: any = get(serviceInput, validationConfig.manifestSource);
const manifestSource: any = get(serviceInput, sourceStruct(serviceInput));
const content: any = get(manifestSource, validationConfig.fieldName);
const fieldLabel = validationConfig.fieldLabel || upperFirst(validationConfig.fieldName);
return content ? null : `<strong>${fieldLabel}</strong> is a required field for the Deploy Service stage.`;
Expand All @@ -63,7 +67,8 @@ PipelineConfigValidator.registerValidator(

private fieldIsValid(stage: IStage | ITrigger, config: IServiceFieldValidatorConfig): boolean {
const serviceInput = get(stage, 'manifest');
const content: any = get(serviceInput, config.fieldName);
const manifestSource: any = get(serviceInput, sourceStruct(serviceInput));
const content: any = get(manifestSource, config.fieldName);

if (!content) {
return true;
Expand Down Expand Up @@ -129,7 +134,7 @@ Registry.pipeline.registerStage({
{
type: 'requiredDeployServiceField',
manifestSource: 'artifact',
fieldName: 'account',
fieldName: 'artifactAccount',
preventSave: true,
} as IServiceFieldValidatorConfig,
{
Expand Down

0 comments on commit dafedac

Please sign in to comment.