Skip to content

Commit

Permalink
feat(release): trigger release plan
Browse files Browse the repository at this point in the history
  • Loading branch information
abhinandan13jan committed Mar 8, 2024
1 parent 440184a commit d0f1c31
Show file tree
Hide file tree
Showing 9 changed files with 467 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { useField } from 'formik';
import { useReleasePlans } from '../../../../hooks/useReleasePlans';
import { DropdownField } from '../../../../shared';
import { useWorkspaceInfo } from '../../../../utils/workspace-context-utils';

type ReleasePlanDropdownProps = Omit<
React.ComponentProps<typeof DropdownField>,
'items' | 'label' | 'placeholder'
>;

export const ReleasePlanDropdown: React.FC<React.PropsWithChildren<ReleasePlanDropdownProps>> = (
props,
) => {
const { namespace } = useWorkspaceInfo();
const [applications, loaded] = useReleasePlans(namespace);
const [, , { setValue }] = useField<string>(props.name);

const dropdownItems = React.useMemo(
() => applications.map((a) => ({ key: a.metadata.name, value: a.metadata.name })),
[applications],
);

return (
<DropdownField
{...props}
label="Release plan"
placeholder={!loaded ? 'Loading releases...' : 'Select release'}
isDisabled={props.isDisabled || !loaded}
items={dropdownItems}
onChange={(app: string) => setValue(app)}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { useField } from 'formik';
import { useSnapshots } from '../../../../hooks/useSnapshots';
import { DropdownField } from '../../../../shared';
import { useWorkspaceInfo } from '../../../../utils/workspace-context-utils';

type SnapshotDropdownProps = Omit<
React.ComponentProps<typeof DropdownField>,
'items' | 'label' | 'placeholder'
>;

export const SnapshotDropdown: React.FC<React.PropsWithChildren<SnapshotDropdownProps>> = (
props,
) => {
const { namespace } = useWorkspaceInfo();
const [applications, loaded] = useSnapshots(namespace);
const [, , { setValue }] = useField<string>(props.name);

const dropdownItems = React.useMemo(
() => applications.map((a) => ({ key: a.metadata.name, value: a.metadata.name })),
[applications],
);

return (
<DropdownField
{...props}
label="Snapshot"
placeholder={!loaded ? 'Loading snapshots...' : 'Select snapshot'}
isDisabled={props.isDisabled || !loaded}
items={dropdownItems}
onChange={(app: string) => setValue(app)}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import * as React from 'react';
import { Form, PageSection, PageSectionVariants } from '@patternfly/react-core';
import { FormikProps, useField } from 'formik';
import isEmpty from 'lodash-es/isEmpty';
import PageLayout from '../../../../components/PageLayout/PageLayout';
import { FormFooter, TextAreaField } from '../../../../shared';
import KeyValueField from '../../../../shared/components/formik-fields/key-value-input-field/KeyValueInputField';
import { useWorkspaceBreadcrumbs } from '../../../../utils/breadcrumb-utils';
import { ReleasePlanFormValues } from '../ReleasePlanForm/form-utils';
import { ReleasePlanDropdown } from './ReleasePlanDropdown';
import { SnapshotDropdown } from './SnapshotDropdown';

type Props = FormikProps<ReleasePlanFormValues> & {
edit?: boolean;
};

export const TriggerReleaseForm: React.FC<Props> = ({
handleSubmit,
handleReset,
isSubmitting,
dirty,
errors,
status,
edit,
}) => {
const breadcrumbs = useWorkspaceBreadcrumbs();
const [{ value: labels }] = useField<ReleasePlanFormValues['labels']>('labels');

return (
<PageLayout
title="Trigger release plan"
description="A release plan schedules when to send your code to production."
breadcrumbs={[
...breadcrumbs,
{
path: `/application-pipeline/release`,
name: 'Releases',
},
{
path: '#',
name: edit ? 'Edit release plan' : 'Create release plan',
},
]}
footer={
<FormFooter
submitLabel="Trigger"
handleCancel={handleReset}
handleSubmit={handleSubmit}
isSubmitting={isSubmitting}
disableSubmit={!dirty || !isEmpty(errors) || isSubmitting}
errorMessage={status?.submitError}
/>
}
>
<PageSection variant={PageSectionVariants.light} isFilled isWidthLimited>
<Form style={{ maxWidth: '70%' }}>
<ReleasePlanDropdown
name="release"
helpText="The release you want to release to the environments in your target workspace."
required
/>
<SnapshotDropdown
name="snapshot"
helpText="The release you want to release to the environments in your target workspace."
required
/>
<TextAreaField
name="synopsis"
label="Synopsis"
helpText="What is the content and purpose of this release?"
/>
<TextAreaField
name="topic"
label="Topic"
helpText="What topics are related to this release? Such as osp-director-downloader-container or osp-director-agent-container"
/>
<TextAreaField
name="description"
label="Description"
helpText="Provide data related to a release pipeline."
/>
<TextAreaField
name="solution"
label="Solution"
helpText="Provide data related to a release pipeline."
/>
<TextAreaField
name="references"
label="References"
helpText="Provide atleast 1 URL. Sparate URLs by commas"
/>
<KeyValueField
name="labels"
label="Labels"
description="You can add labels to provide more context or tag your release plan."
entries={labels}
/>
</Form>
</PageSection>
</PageLayout>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import * as React from 'react';
import { useNavigate } from 'react-router-dom';
import { Formik, FormikHelpers } from 'formik';
import { ResolverRefParams } from '../../../../components/IntegrationTest/IntegrationTestForm/utils/create-utils';
import { ReleasePlanKind, ReleasePlanLabel } from '../../../../types/coreBuildService';
import { useTrackEvent, TrackEvents } from '../../../../utils/analytics';
import { useWorkspaceInfo } from '../../../../utils/workspace-context-utils';
import {
ReleasePlanFormValues,
createReleasePlan,
editReleasePlan,
ReleasePipelineLocation,
releasePlanFormParams,
releasePlanFormSchema,
} from '../ReleasePlanForm/form-utils';
import { TriggerReleaseForm } from './TriggerReleaseForm';

type Props = {
releasePlan?: ReleasePlanKind;
};

export const TriggerReleaseFormPage: React.FC<Props> = ({ releasePlan }) => {
const navigate = useNavigate();
const track = useTrackEvent();
const { namespace, workspace } = useWorkspaceInfo();
const edit = !!releasePlan;

const handleSubmit = async (
values: ReleasePlanFormValues,
{ setSubmitting, setStatus }: FormikHelpers<ReleasePlanFormValues>,
) => {
if (edit) {
track(TrackEvents.ButtonClicked, {
link_name: 'edit-release-plan-submit',
// eslint-disable-next-line camelcase
release_plan_name: releasePlan.metadata.name,
// eslint-disable-next-line camelcase
target_workspace: releasePlan.spec.target,
app_name: releasePlan.spec.application,
workspace,
});
} else {
track(TrackEvents.ButtonClicked, {
link_name: 'add-release-plan-submit',
workspace,
});
}
try {
edit
? await editReleasePlan(releasePlan, values, workspace, true)
: await createReleasePlan(values, namespace, workspace, true);
const newReleasePlan = edit
? await editReleasePlan(releasePlan, values, workspace)
: await createReleasePlan(values, namespace, workspace);
track(edit ? 'Release plan edited' : 'Release plan created', {
// eslint-disable-next-line camelcase
release_plan_name: newReleasePlan.metadata.name,
// eslint-disable-next-line camelcase
target_workspace: newReleasePlan.spec.target,
app_name: newReleasePlan.spec.application,
workspace,
});
navigate('/application-pipeline/release');
} catch (e) {
// eslint-disable-next-line no-console
console.warn('Error while submitting integration test:', e);
setSubmitting(false);
setStatus({ submitError: e.message });
}
};

const handleReset = () => {
if (edit) {
track(TrackEvents.ButtonClicked, {
link_name: 'edit-release-plan-leave',
// eslint-disable-next-line camelcase
release_plan_name: releasePlan.metadata.name,
// eslint-disable-next-line camelcase
target_workspace: releasePlan.spec.target,
app_name: releasePlan.spec.application,
workspace,
});
} else {
track(TrackEvents.ButtonClicked, {
link_name: 'add-release-plan-leave',
workspace,
});
}
navigate('/application-pipeline/release');
};

const initialValues: ReleasePlanFormValues = {
name: releasePlan?.metadata?.name ?? '',
application: releasePlan?.spec?.application ?? '',
autoRelease: releasePlan?.metadata?.labels?.[ReleasePlanLabel.AUTO_RELEASE] === 'true' ?? false,
standingAttribution:
releasePlan?.metadata?.labels?.[ReleasePlanLabel.STANDING_ATTRIBUTION] === 'true' ?? false,
releasePipelineLocation: releasePlan?.spec?.target
? releasePlan.spec.target === workspace
? ReleasePipelineLocation.current
: ReleasePipelineLocation.target
: undefined,
serviceAccount: releasePlan?.spec?.serviceAccount ?? '',
target: releasePlan?.spec?.target ?? '',
data: releasePlan?.spec?.data ?? '',
params: releasePlanFormParams(releasePlan),
labels: releasePlan?.metadata?.labels
? Object.entries(releasePlan?.metadata?.labels).map(([key, value]) => ({ key, value }))
: [{ key: '', value: '' }],
git: {
url:
releasePlan?.spec?.pipelineRef?.params?.find((p) => p.name === ResolverRefParams.URL)
?.value ?? '',
revision:
releasePlan?.spec?.pipelineRef?.params?.find((p) => p.name === ResolverRefParams.REVISION)
?.value ?? '',
path:
releasePlan?.spec?.pipelineRef?.params?.find((p) => p.name === ResolverRefParams.PATH)
?.value ?? '',
},
};

return (
<Formik
onSubmit={handleSubmit}
onReset={handleReset}
initialValues={initialValues}
validationSchema={releasePlanFormSchema}
>
{(props) => <TriggerReleaseForm {...props} edit={edit} />}
</Formik>
);
};
Loading

0 comments on commit d0f1c31

Please sign in to comment.