Skip to content

Commit

Permalink
feat: add deployment environment to register repository page (#170)
Browse files Browse the repository at this point in the history
This change updates the Register Repository Page to request the deployment environment when the repository content type is set to deployments.
  • Loading branch information
ChristopherFry committed Oct 7, 2022
1 parent 22c8061 commit 3f9e339
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import { Secret } from '../../types/Secret';
import { allowFunctionRepositoryRegistration } from '../../utils/featureFlags';
import {
ContentSummary,
DeploymentEnvironment,
DeploymentEnvironmentDetails,
getRepositoryGitDetails,
getRepositoryOciDetails,
getRepositoryResource,
Expand Down Expand Up @@ -79,6 +81,7 @@ export const RegisterRepositoryPage = () => {
name: '',
repoUrl: '',
contentSummary: '',
deploymentEnvironment: '',
type: '',
description: '',
repoBranch: '',
Expand Down Expand Up @@ -133,6 +136,7 @@ export const RegisterRepositoryPage = () => {

let gitDetails: RepositoryGitDetails | undefined = undefined;
let ociDetails: RepositoryOciDetails | undefined = undefined;
let deploymentEnvironment: DeploymentEnvironment | undefined = undefined;

if (state.type === RepositoryType.GIT) {
const createBranch = true;
Expand All @@ -152,12 +156,18 @@ export const RegisterRepositoryPage = () => {

const contentSummary = state.contentSummary as ContentSummary;

if (contentSummary === ContentSummary.DEPLOYMENT) {
deploymentEnvironment =
state.deploymentEnvironment as DeploymentEnvironment;
}

const resource = getRepositoryResource(
state.name,
state.description,
contentSummary,
gitDetails,
ociDetails,
deploymentEnvironment,
);

return resource;
Expand Down Expand Up @@ -234,6 +244,14 @@ export const RegisterRepositoryPage = () => {
}
}

for (const [environment, details] of Object.entries(
DeploymentEnvironmentDetails,
)) {
if (repositoryUrl.includes(details.shortName)) {
toSet.deploymentEnvironment = environment;
}
}

const suggestedName = kebabCase(
repositoryUrl
.split('/')
Expand Down Expand Up @@ -289,6 +307,16 @@ export const RegisterRepositoryPage = () => {
return selectItems;
}, []);

const deploymentEnvironmentRadioOptions = useMemo(
() =>
Object.keys(DeploymentEnvironmentDetails).map(env => ({
label: env,
value: env,
description: DeploymentEnvironmentDetails[env].description,
})),
[],
);

return (
<div>
<Breadcrumbs>
Expand Down Expand Up @@ -442,6 +470,22 @@ export const RegisterRepositoryPage = () => {
</div>
</SimpleStepperStep>

{state.contentSummary === ContentSummary.DEPLOYMENT && (
<SimpleStepperStep title="Deployment Environment">
<div className={classes.stepContent}>
<RadioGroup
label="Development Environment"
onChange={value =>
updateStateValue('deploymentEnvironment', value)
}
value={state.deploymentEnvironment}
options={deploymentEnvironmentRadioOptions}
helperText="Select the environment that maps to your repository."
/>
</div>
</SimpleStepperStep>
)}

<SimpleStepperStep
title="Confirm"
actions={{ nextText: 'Register Repository', onNext: registerRepo }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import { InfoCard, StructuredMetadataTable } from '@backstage/core-components';
import React from 'react';
import { Repository } from '../../../types/Repository';
import { RepositorySummary } from '../../../types/RepositorySummary';
import { getPackageDescriptor } from '../../../utils/repository';
import {
getDeploymentEnvironment,
getPackageDescriptor,
isDeploymentRepository,
} from '../../../utils/repository';

type RepositoryDetailsProps = {
repositorySummary: RepositorySummary;
Expand Down Expand Up @@ -60,9 +64,14 @@ const getRepositoryMetadata = (repository: Repository): Metadata => {
name: repository.metadata.name,
description: repository.spec.description ?? '',
content: `${getPackageDescriptor(repository)}s`,
deploymentEnvironment: getDeploymentEnvironment(repository),
...getRepositoryStoreMetadata(repository),
};

if (!isDeploymentRepository(repository)) {
delete metadata.deploymentEnvironment;
}

return metadata;
};

Expand Down
86 changes: 85 additions & 1 deletion plugins/cad/src/utils/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,20 @@ type ContentCloneToDetail = {
message?: string;
};

type EnvironmentDetails = {
[key: string]: EnvironmentDetail;
};

type EnvironmentDetail = {
shortName: string;
description: string;
repositoryEnvironmentLabelValue?: string;
notDeploymentEnvironment?: DeploymentEnvironment[];
};

const REPOSITORY_CONTENT_LABEL = 'kpt.dev/repository-content';
const REPOSITORY_DEPLOYMENT_ENVIRONMENT_LABEL =
'kpt.dev/deployment-environment';

export enum ContentSummary {
EXTERNAL_BLUEPRINT = 'External Blueprint',
Expand All @@ -54,6 +67,12 @@ export enum ContentSummary {
FUNCTION = 'Function',
}

export enum DeploymentEnvironment {
DEVELOPMENT = 'Development',
STAGING = 'Staging',
PRODUCTION = 'Production',
}

export const PackageContentSummaryOrder = [
ContentSummary.DEPLOYMENT,
ContentSummary.TEAM_BLUEPRINT,
Expand All @@ -77,7 +96,7 @@ export const RepositoryContentDetails: ContentDetails = {
[ContentSummary.DEPLOYMENT]: {
repositoryContent: RepositoryContent.PACKAGE,
description:
'Deployment Packages are packages ready for deployment to live clusters.',
"Deployment Packages are packages ready for deployment to live clusters. If selected, you'll need to specify if the repository is for a development, staging, or production cluster.",
isDeployment: true,
cloneTo: [],
},
Expand Down Expand Up @@ -135,6 +154,30 @@ export const RepositoryContentDetails: ContentDetails = {
},
};

export const DeploymentEnvironmentDetails: EnvironmentDetails = {
[DeploymentEnvironment.DEVELOPMENT]: {
shortName: 'dev',
description:
'The development environment is the environment your team uses for day-to-day development. A Team Blueprint package is expected to be cloned to this environment first.',
notDeploymentEnvironment: [
DeploymentEnvironment.STAGING,
DeploymentEnvironment.PRODUCTION,
],
},
[DeploymentEnvironment.STAGING]: {
shortName: 'staging',
description:
'The staging environment is similar to the production environment, except it does not receive live traffic. A Team Blueprint package is expected to be cloned to this environment after it is cloned, published, and tested in the development environment.',
repositoryEnvironmentLabelValue: 'staging',
},
[DeploymentEnvironment.PRODUCTION]: {
shortName: 'prod',
description:
'The production environment receives live traffic. A Team Blueprint package is expected to be cloned to this environment after it is cloned, published, and tested in the staging environment.',
repositoryEnvironmentLabelValue: 'production',
},
};

const isRepositoryContent = (
repository: Repository,
contentType: ContentSummary,
Expand Down Expand Up @@ -170,6 +213,36 @@ export const getPackageDescriptor = (repository: Repository): string => {
return 'Unknown';
};

const isDeploymentEnviroment = (
repository: Repository,
environment: DeploymentEnvironment,
): boolean => {
const environmentDetails = DeploymentEnvironmentDetails[environment];

const isLabelMatch =
!environmentDetails.repositoryEnvironmentLabelValue ||
repository.metadata.labels?.[REPOSITORY_DEPLOYMENT_ENVIRONMENT_LABEL] ===
environmentDetails.repositoryEnvironmentLabelValue;

const isDeployment = isDeploymentRepository(repository);
const notContent = environmentDetails.notDeploymentEnvironment ?? [];
const noDisqualifiers = !notContent
.map(env => isDeploymentEnviroment(repository, env))
.includes(true);

return isDeployment && isLabelMatch && noDisqualifiers;
};

export const getDeploymentEnvironment = (repository: Repository): string => {
for (const env of Object.keys(DeploymentEnvironmentDetails)) {
if (isDeploymentEnviroment(repository, env as DeploymentEnvironment)) {
return env;
}
}

return 'Unknown';
};

export const getRepository = (
allRepositories: Repository[],
repositoryName: string,
Expand Down Expand Up @@ -212,6 +285,7 @@ export const getRepositoryResource = (
contentSummary: ContentSummary,
git?: RepositoryGitDetails,
oci?: RepositoryOciDetails,
deploymentEnvironment?: DeploymentEnvironment,
): Repository => {
const namespace = 'default';

Expand All @@ -229,6 +303,16 @@ export const getRepositoryResource = (
contentDetails.repositoryContentLabelValue;
}

if (contentSummary === ContentSummary.DEPLOYMENT && deploymentEnvironment) {
const environmentDetails =
DeploymentEnvironmentDetails[deploymentEnvironment];

if (environmentDetails.repositoryEnvironmentLabelValue) {
labels[REPOSITORY_DEPLOYMENT_ENVIRONMENT_LABEL] =
environmentDetails.repositoryEnvironmentLabelValue;
}
}

const resource: Repository = {
apiVersion: 'config.porch.kpt.dev/v1alpha1',
kind: 'Repository',
Expand Down

0 comments on commit 3f9e339

Please sign in to comment.