logo
Workflows as Code with CodeCatalyst-Blueprints

Workflows as Code with CodeCatalyst-Blueprints

You do not need custom blueprints enabled to generate CodeCatalyst workflows as code - Blueprint hack

Published Jan 30, 2024

This blog introduces how to optimize workflow management within the Amazon ecosystem using codecatalyst-blueprints. By employing a blueprint.ts file, developers can succinctly express workflows as code, promoting readability and collaboration without CodeCatalyst Enterprise tier

Blueprints are code generators used to create and maintain projects in Amazon CodeCatalyst. You can build your own blueprint (Custom Blueprints) today by upgrading to the CodeCatalyst Enterprise tier. An integral aspect of Blueprints involves workflow generation. Disregarding the CodeCatalyst Enterprise tier, we can utilize this feature to create CodeCatalyst workflows as code, utilizing the preferred programming language, such as Typescript.

We cannot use Projen to init a blueprint project as AWS CDK or CDK8S, but we can do a trick by init TypeScript project and then update .projenrc.ts as ProjenBlueprint
While we cannot directly use Projen to initialize a blueprint project such as AWS CDK or CDK8S, we can employ a workaround. Initialize a TypeScript project first, and then update the `.projenrc.ts` file using ProjenBlueprint
To initialize a TypeScript project using Projen, you can use the following command
1
2
3
4
5
➜ projen new typescript --no-git --projenrc-ts --github false --dev-deps "@amazon-codecatalyst/blueprint-util.projen-blueprint" "@amazon-codecatalyst/blueprint-util.cli"
👾 Project definition file was created at /private/tmp/blueprint/.projenrc.ts
👾 Installing dependencies...
👾 install | yarn install --check-files
yarn install v1.22.19
Override the .projenrc.ts with the following code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { ProjenBlueprint } from '@amazon-codecatalyst/blueprint-util.projen-blueprint';

const project = new ProjenBlueprint({
name: 'cdk-todo-web-app',
defaultReleaseBranch: 'main',
projenrcTs: true,
sampleCode: false,
github: false,
tsconfig: {
compilerOptions: {
esModuleInterop: true,
noImplicitAny: false,
},
},
deps: [
'projen',
'@amazon-codecatalyst/blueprints.blueprint',
'@amazon-codecatalyst/blueprint-component.workflows',
'@amazon-codecatalyst/blueprint-component.source-repositories',
'@amazon-codecatalyst/blueprint-component.dev-environments',
'@amazon-codecatalyst/blueprint-component.environments',
],
devDeps: [
'ts-node@^10',
'typescript',
'@amazon-codecatalyst/blueprint-util.projen-blueprint',
'@amazon-codecatalyst/blueprint-util.cli',
],
});

project.synth();
Then run projen to update the package.json, .projen, and other files managed by Projen
1
2
3
4
5
➜ projen
👾 default | ts-node --project tsconfig.dev.json .projenrc.ts
👾 Installing dependencies...
👾 install | yarn install --check-files
yarn install v1.22.19

If you've utilized CodeCatalyst custom blueprints, you are likely familiar with blueprint.ts, which contains code for generating UI options, environment settings, source repository configurations, and workflows. When creating a custom blueprint, these elements are automatically generated. However, if your goal is to leverage the CI/CD capabilities of the CodeCatalyst workspace without requiring all components, you specifically need the workflow generation part.
In short, the `blueprint.ts` file encompasses the following elements:
1. Source repository - serves as a reference point for workflow configurations
1
2
3
const repository = new SourceRepository(this, {
title: "cdk-todo-web-app",
});
2. Environment - Where we define the CI/CD environment, including the connection to the AWS account.
1
2
3
4
5
6
7
8
9
10
const environment = new Environment(this, {
name: "default_environment",
environmentType: "DEVELOPMENT",
description: "Blueprint environment",
awsAccount: {
cdkRole: { name: CDK_DEFAULT_ROLE },
id: CDK_DEFAULT_ACCOUNT,
name: CDK_DEFAULT_ACCOUNT,
},
});
3. Workflow Actions
- An Action includes the following major components
1
2
3
4
5
6
7
8
9
export interface ActionProps {
actionName: string;
identifier: string;
steps: string[];
environment?: WorkflowEnvironment;
dependancies?: string[];
inputs?: { [key: string]: any[] };
outputs?: { [key: string]: any };
}
- A wrapper function that generates a workflow Action based on the interface
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Generate an action for the workflow
* @param props ActionProps
* @returns Action
*/

export function GenerateAction(props: ActionProps) {
return {
[props.actionName]: {
Identifier: props.identifier,
Inputs: props.inputs ? props.inputs : { Sources: ["WorkflowSource"] },
Outputs: props.outputs
? props.outputs
: {
AutoDiscoverReports: {
IncludePaths: ["**/*"],
ExcludePaths: ["*/.codecatalyst/workflows/*"],
ReportNamePrefix: "AutoDiscovered",
Enabled: true,
},
},
Configuration: {
Steps: props.steps.map((step) => ({ Run: step })),
},
Environment: props.environment,
DependsOn: (props.dependancies) ? props.dependancies : undefined,
},
};
}
- We will have following actions
1. FrontendBuildAndPackage
2. FrontendTest
3. CDKBootstrapAction
4. CDKDeploy
4. WorkflowBuilder - Responsible for defining the workflow name, compute type, trigger type, and the required actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const workflowBuilder = new WorkflowBuilder(this, {
Name: "main_fullstack_workflow",
Compute: {
Type: ComputeType.EC2,
Fleet: ComputeFleet.LINUX_X86_64_LARGE,
},
Triggers: [
{
Branches: ["main"],
Type: TriggerType.PUSH,
},
],
Actions: {
...frontendBuildAndPackage,
...frontendTest,
...cdkBootstrapAction,
...cdkDeploy,
},
});
5. Workflow - Collects all WorkflowBuilder instances and incorporates them into the source code repository
1
new Workflow(this, repository, workflowBuilder.getDefinition());

Run yarn blueprint:synth (This script is from `package.json`)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
➜ cdk-todo-web-app git:(main) ✗ yarn blueprint:synth
yarn run v1.22.19
$ blueprint drive-synth --blueprint ./ --outdir ./synth --default-options ./src/defaults.json --additional-options ./src/wizard-configurations $*
[1706372494181] INFO (5048 on Daos-MBP): Running in quick mode. Run this command with --cache to emulate the wizard
[1706372494192] INFO (5048 on Daos-MBP): ==========================================
[1706372494192] INFO (5048 on Daos-MBP): [00.synth.defaults.json]
[1706372494192] INFO (5048 on Daos-MBP): npx blueprint synth --options merge[./src/defaults.json,./src/defaults.json] --blueprint ./ --outdir synth/00.synth.defaults.json/proposed-bundle
[1706372494192] INFO (5048 on Daos-MBP): ==========================================
===== Starting synthesis =====
options: {}
outputDir: synth/00.synth.defaults.json/proposed-bundle
Instantiations location not specified
running synthesis into /codecatalyst/cdk-todo-web-app/synth/00.synth.defaults.json/proposed-bundle/src/cdk-todo-web-app
===== Ending synthesis =====
✨ Done in 2.10s.
We have the generated files in `synth/00.synth.defaults.json/proposed-bundle` and we have our workflow YAML file is located at `synth/00.synth.defaults.json/proposed-bundle/src/cdk-todo-web-app/.codecatalyst/workflows/main_fullstack_workflow.yaml`
1
2
3
4
5
6
➜ cdk-todo-web-app git:(main) ✗ tree synth/00.synth.defaults.json/proposed-bundle/src/cdk-todo-web-app/.codecatalyst
synth/00.synth.defaults.json/proposed-bundle/src/cdk-todo-web-app/.codecatalyst
└── workflows
└── main_fullstack_workflow.yaml

2 directories, 1 file
Copy the YAML file
1
➜ cdk-todo-web-app git:(main) ✗ cp synth/00.synth.defaults.json/proposed-bundle/src/cdk-todo-web-app/.codecatalyst/workflows/main_fullstack_workflow.yaml .codecatalyst/workflows/main_fullstack_workflow.yaml
Now we can push the code to the repository and check the workflow run

Congratulations! You have successfully generated CodeCatalyst workflows as code using codecatalyst-blueprints without enabling the CodeCatalyst Enterprise tier.
You can create an Action to automatically generate and update the workflow YAML file by pushing a new commit to the main branch, reflecting changes from the `blueprint.ts` file.