diff --git a/packages/blueprints/blueprint-builder/package.json b/packages/blueprints/blueprint-builder/package.json index 88ec38b9d..0748c81df 100644 --- a/packages/blueprints/blueprint-builder/package.json +++ b/packages/blueprints/blueprint-builder/package.json @@ -70,7 +70,7 @@ "main": "lib/index.js", "license": "Apache-2.0", "homepage": "https://aws.amazon.com/", - "version": "0.3.26", + "version": "0.3.27", "types": "lib/index.d.ts", "publishingSpace": "blueprints", "mediaUrls": [ diff --git a/packages/blueprints/blueprint-builder/src/blueprint.ts b/packages/blueprints/blueprint-builder/src/blueprint.ts index 6f5164a98..f52b63322 100644 --- a/packages/blueprints/blueprint-builder/src/blueprint.ts +++ b/packages/blueprints/blueprint-builder/src/blueprint.ts @@ -3,6 +3,7 @@ import devEnvPackage from '@amazon-codecatalyst/blueprint-component.dev-environm import envPackage from '@amazon-codecatalyst/blueprint-component.environments/package.json'; import { SourceRepository, SourceFile, StaticAsset, File } from '@amazon-codecatalyst/blueprint-component.source-repositories'; import sourceReposPackage from '@amazon-codecatalyst/blueprint-component.source-repositories/package.json'; +import { Workflow, WorkflowBuilder } from '@amazon-codecatalyst/blueprint-component.workflows'; import workflowsPackage from '@amazon-codecatalyst/blueprint-component.workflows/package.json'; import cliPackage from '@amazon-codecatalyst/blueprint-util.cli/package.json'; import { ProjenBlueprint, ProjenBlueprintOptions } from '@amazon-codecatalyst/blueprint-util.projen-blueprint'; @@ -15,6 +16,7 @@ import { } from '@amazon-codecatalyst/blueprints.blueprint'; import baseBlueprintPackage from '@amazon-codecatalyst/blueprints.blueprint/package.json'; import * as decamelize from 'decamelize'; +import { buildReleaseWorkflow } from './build-release-workflow'; import defaults from './defaults.json'; devEnvPackage.version; @@ -63,6 +65,19 @@ export interface Options extends ParentOptions { * @validationMessage This contains characters that are not allowed in NPM package names. */ blueprintPackageName?: string; + + /** + * Generate a release workflow? + * If this is set, the blueprint will generate a release workflow. On push to main, a workflow will release this blueprint into your codecatalyst space. + */ + releaseWorkflow?: boolean; + + /** + * Include a publishing step in the release workflow? + * If this is set, the generated release workflow will contain a publishing action. + * @hidden + */ + includePublishingAction?: boolean; }; } @@ -149,6 +164,10 @@ export class Blueprint extends ParentBlueprint { // copy-paste additional code over it StaticAsset.findAll().forEach(asset => { + if (asset.path() === 'release.sh' && !options.advancedSettings.releaseWorkflow) { + return; + } + new File(repository, asset.path(), asset.content()); }); @@ -217,6 +236,17 @@ export class Blueprint extends ParentBlueprint { ], }, }); + + if (options.advancedSettings.releaseWorkflow) { + const releaseWorkflow = new WorkflowBuilder(this); + new Workflow( + this, + repository, + buildReleaseWorkflow(releaseWorkflow, { + includePublishStep: options.advancedSettings.includePublishingAction, + }).getDefinition(), + ); + } } synth(): void { diff --git a/packages/blueprints/blueprint-builder/src/build-release-workflow.ts b/packages/blueprints/blueprint-builder/src/build-release-workflow.ts new file mode 100644 index 000000000..bbdfdfaf6 --- /dev/null +++ b/packages/blueprints/blueprint-builder/src/build-release-workflow.ts @@ -0,0 +1,73 @@ +import { TriggerType, WorkflowBuilder } from '@amazon-codecatalyst/blueprint-component.workflows'; + +export function buildReleaseWorkflow(workflow: WorkflowBuilder, options?: { includePublishStep?: boolean }): WorkflowBuilder { + const publishingEnabled = options?.includePublishStep ?? true; + + workflow.setName('blueprint-release'); + const RELEASE_COMMIT_PREFIX = 'chore(release):'; + const BUILD_ARTIFACT_NAME = 'codebase'; + + workflow.addBranchTrigger(['main']); + workflow.addTrigger({ + Type: TriggerType.MANUAL, + }); + workflow.addBuildAction({ + actionName: 'check_commit', + input: { + Sources: ['WorkflowSource'], + }, + output: { + Variables: ['IS_RELEASE_COMMIT'], + }, + steps: [ + 'TRIGGER_COMMIT_ID=$CATALYST_EVENT_SHA', + 'COMMIT_MESSAGE="$(git log -n 1 $TRIGGER_COMMIT_ID --oneline)"', + `RELEASE_PREFIX='${RELEASE_COMMIT_PREFIX}'`, + 'IS_RELEASE_COMMIT=false', + 'if grep -q "$RELEASE_PREFIX" <<< "$COMMIT_MESSAGE"; then echo \'this is a release commit\' && IS_RELEASE_COMMIT=true; fi', + ], + }); + workflow.addBuildAction({ + actionName: 'build_and_commit', + dependsOn: ['check_commit'], + input: { + Sources: ['WorkflowSource'], + Variables: { + IS_RELEASE_COMMIT: '${check_commit.IS_RELEASE_COMMIT}', + }, + }, + output: { + Artifacts: [ + { + Name: BUILD_ARTIFACT_NAME, + Files: ['**/*'], + }, + ], + }, + steps: ["if $IS_RELEASE_COMMIT; then echo 'This is a release commit, skipping'; else chmod +x release.sh && ./release.sh; fi"], + }); + + if (publishingEnabled) { + workflow.addPublishBlueprintAction({ + actionName: 'publish_blueprint', + dependsOn: ['build_and_commit'], + inputs: { + Artifacts: [BUILD_ARTIFACT_NAME], + Variables: [ + { + Name: 'IS_RELEASE_COMMIT', + Value: '${check_commit.IS_RELEASE_COMMIT}', + }, + ], + }, + configuration: { + ArtifactPackagePath: 'dist/js/*.tgz', + PackageJSONPath: 'package.json', + InputArtifactName: BUILD_ARTIFACT_NAME, + TimeoutInSeconds: '120', + }, + }); + } + + return workflow; +} diff --git a/packages/blueprints/blueprint-builder/src/defaults.json b/packages/blueprints/blueprint-builder/src/defaults.json index 7d9753174..35f4ba55d 100644 --- a/packages/blueprints/blueprint-builder/src/defaults.json +++ b/packages/blueprints/blueprint-builder/src/defaults.json @@ -5,6 +5,8 @@ "advancedSettings": { "blueprintPackageName": "", "license": "Apache-2.0", - "tags": ["first-label", "second-label"] + "tags": ["first-label", "second-label"], + "releaseWorkflow": true, + "includePublishingAction": true } } diff --git a/packages/blueprints/blueprint-builder/static-assets/release.sh b/packages/blueprints/blueprint-builder/static-assets/release.sh new file mode 100644 index 000000000..7ac2e1535 --- /dev/null +++ b/packages/blueprints/blueprint-builder/static-assets/release.sh @@ -0,0 +1,35 @@ +# This script is used by the blueprint-release workflow to build +# the blueprint, bump its package version, and commit the version +# bump back into the repository. +echo "Installing dependencies..." +yum install -y rsync +npm install -g yarn +yarn + +echo "Building blueprint..." +yarn build + +echo "Bumping package version..." +yarn bump +NEW_VERSION=`jq -r .version package.json` +yarn blueprint:package + +echo "Getting credentials..." +MI=`curl $AWS_CONTAINER_TOKEN_ENDPOINT` +ACCESS_KEY_ID=$(echo "$MI" | jq -r '.AccessKeyId') +SECRET_ACCESS_KEY=$(echo "$MI" | jq -r '.SecretAccessKey') +ORIGINAL_REMOTE=`git config --get remote.origin.url` +SOURCE_REPO_URL=`sed -e "s^//^//$ACCESS_KEY_ID:$SECRET_ACCESS_KEY@^" <<< $ORIGINAL_REMOTE` + +echo "Configuring git..." +git remote set-url origin $SOURCE_REPO_URL +git config --global user.email "noreply@amazon.com" +git config --global user.name "Release Workflow" + +echo "Committing changes..." +git add . +RELEASE_COMMIT_MESSAGE="chore(release): release $NEW_VERSION" +git commit -m "$RELEASE_COMMIT_MESSAGE" + +echo "Pushing to origin..." +git push origin HEAD:main diff --git a/packages/blueprints/blueprint/package.json b/packages/blueprints/blueprint/package.json index 5db19218f..5c1c18a8b 100644 --- a/packages/blueprints/blueprint/package.json +++ b/packages/blueprints/blueprint/package.json @@ -75,7 +75,7 @@ "main": "lib/index.js", "license": "Apache-2.0", "homepage": "https://aws.amazon.com/", - "version": "0.3.25", + "version": "0.3.26", "jest": { "testMatch": [ "/src/**/__tests__/**/*.ts?(x)", diff --git a/packages/blueprints/sam-serverless-app/package.json b/packages/blueprints/sam-serverless-app/package.json index 7f5378604..51f2e5f5a 100644 --- a/packages/blueprints/sam-serverless-app/package.json +++ b/packages/blueprints/sam-serverless-app/package.json @@ -88,7 +88,7 @@ "main": "lib/index.js", "license": "Apache-2.0", "homepage": "https://aws.amazon.com/", - "version": "0.3.26", + "version": "0.3.27", "jest": { "testMatch": [ "/src/**/__tests__/**/*.ts?(x)", diff --git a/packages/blueprints/test-blueprint/package.json b/packages/blueprints/test-blueprint/package.json index e7983fa0b..646232651 100644 --- a/packages/blueprints/test-blueprint/package.json +++ b/packages/blueprints/test-blueprint/package.json @@ -66,7 +66,7 @@ "main": "lib/index.js", "license": "Apache-2.0", "homepage": "", - "version": "0.3.26", + "version": "0.3.27", "types": "lib/index.d.ts", "publishingSpace": "blueprints", "mediaUrls": [ diff --git a/packages/components/dev-environments/package.json b/packages/components/dev-environments/package.json index 7ae7128ef..b96eefc8e 100644 --- a/packages/components/dev-environments/package.json +++ b/packages/components/dev-environments/package.json @@ -50,7 +50,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "types": "lib/index.d.ts", "preferGlobal": true, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." diff --git a/packages/components/environments/package.json b/packages/components/environments/package.json index d2c39cb88..c27e02d81 100644 --- a/packages/components/environments/package.json +++ b/packages/components/environments/package.json @@ -47,7 +47,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "types": "lib/index.d.ts", "preferGlobal": true, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." diff --git a/packages/components/source-repositories/package.json b/packages/components/source-repositories/package.json index 5ae076332..bb92fd27d 100644 --- a/packages/components/source-repositories/package.json +++ b/packages/components/source-repositories/package.json @@ -57,7 +57,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "jest": { "testMatch": [ "/src/**/__tests__/**/*.ts?(x)", diff --git a/packages/components/workflows/package.json b/packages/components/workflows/package.json index e4b9fa5c0..09d44baa2 100644 --- a/packages/components/workflows/package.json +++ b/packages/components/workflows/package.json @@ -53,7 +53,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "types": "lib/index.d.ts", "preferGlobal": true, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." diff --git a/packages/components/workflows/src/actions/action-publish-blueprint.ts b/packages/components/workflows/src/actions/action-publish-blueprint.ts new file mode 100644 index 000000000..cf323e8a1 --- /dev/null +++ b/packages/components/workflows/src/actions/action-publish-blueprint.ts @@ -0,0 +1,41 @@ +import { Blueprint } from '@amazon-codecatalyst/blueprints.blueprint'; +import { ActionDefiniton, ActionIdentifierAlias, ComputeConfiguration, InputsDefinition, getDefaultActionIdentifier } from './action'; +import { WorkflowDefinition } from '../workflow/workflow'; + +export interface PublishBlueprintActionConfiguration { + ArtifactPackagePath: string; + PackageJSONPath: string; + InputArtifactName: string; + TimeoutInSeconds?: string; +} + +export interface PublishBlueprintActionParameters { + actionName: string; + inputs: InputsDefinition; + configuration: PublishBlueprintActionConfiguration; + dependsOn?: string[]; + computeName?: ComputeConfiguration; +} + +export function addGenericPublishBlueprintAction( + params: PublishBlueprintActionParameters & { + blueprint: Blueprint; + workflow: WorkflowDefinition; + }, +): string { + const { blueprint, inputs, dependsOn, computeName, configuration } = params; + const actionName = (params.actionName || 'PublishBlueprint').replace(new RegExp('-', 'g'), '_'); + + const publishBlueprintAction: ActionDefiniton = { + Identifier: getDefaultActionIdentifier(ActionIdentifierAlias.publishBlueprint, blueprint.context.environmentId), + Inputs: inputs, + DependsOn: dependsOn, + Compute: computeName, + Configuration: configuration, + }; + + params.workflow.Actions = params.workflow.Actions || {}; + params.workflow.Actions[actionName] = publishBlueprintAction; + + return actionName; +} diff --git a/packages/components/workflows/src/actions/action.ts b/packages/components/workflows/src/actions/action.ts index ab1dc5369..4fa583928 100644 --- a/packages/components/workflows/src/actions/action.ts +++ b/packages/components/workflows/src/actions/action.ts @@ -7,6 +7,7 @@ import { BuildActionConfiguration } from './action-build'; import { CdkBootstrapActionConfiguration } from './action-cdk-bootstrap'; import { CdkDeployActionYamlOutput } from './action-cdk-deploy'; import { CfnDeployActionConfiguration } from './action-cfn-deploy'; +import { PublishBlueprintActionConfiguration } from './action-publish-blueprint'; import { TestActionConfiguration } from './action-test-reports'; import { WorkflowEnvironment } from '../environment/workflow-environment'; @@ -16,6 +17,7 @@ export enum ActionIdentifierAlias { test = 'test', cdkDeploy = 'cdkDeploy', cdkBootstrap = 'cdkBootstrap', + publishBlueprint = 'publishBlueprint', } const ACTION_IDENTIFIERS: { [key: string]: { default: string; prod: string } } = { @@ -59,6 +61,10 @@ const ACTION_IDENTIFIERS: { [key: string]: { default: string; prod: string } } = default: 'aws/cdk-bootstrap-gamma@v1', prod: 'aws/cdk-bootstrap@v1', }, + publishBlueprint: { + default: 'aws/publish-blueprint-action@v1', + prod: 'aws/publish-blueprint-action@v1', + }, }; export function getDefaultActionIdentifier(identifer: string, environmentIdentifier: string = 'default'): string | undefined { @@ -74,7 +80,9 @@ type TypeSupportedActions = | CfnDeployActionConfiguration | TestActionConfiguration | CdkDeployActionYamlOutput - | CdkBootstrapActionConfiguration; + | CdkBootstrapActionConfiguration + | PublishBlueprintActionConfiguration; + export interface ActionDefiniton { Identifier?: string; Compute?: TypeSupportedCompute | string; diff --git a/packages/components/workflows/src/workflow/workflow-builder.ts b/packages/components/workflows/src/workflow/workflow-builder.ts index 0d1ebebd3..7be54a597 100644 --- a/packages/components/workflows/src/workflow/workflow-builder.ts +++ b/packages/components/workflows/src/workflow/workflow-builder.ts @@ -7,6 +7,7 @@ import { addGenericCdkBootstrapAction, CdkBootstrapActionParameters } from '../a import { addGenericCdkDeployAction, CdkDeployActionParameters } from '../actions/action-cdk-deploy'; import { addGenericCloudFormationCleanupAction, CfnCleanupActionParameters } from '../actions/action-cfn-cleanup'; import { addGenericCloudFormationDeployAction, CfnDeployActionParameters } from '../actions/action-cfn-deploy'; +import { addGenericPublishBlueprintAction, PublishBlueprintActionParameters } from '../actions/action-publish-blueprint'; import { addGenericTestReports, TestReportActionParameters } from '../actions/action-test-reports'; export class WorkflowBuilder { @@ -99,4 +100,12 @@ export class WorkflowBuilder { workflow: this.definition, }); } + + addPublishBlueprintAction(configuration: PublishBlueprintActionParameters) { + addGenericPublishBlueprintAction({ + ...configuration, + blueprint: this.blueprint, + workflow: this.definition, + }); + } } diff --git a/packages/top-level/codecatalyst-blueprints/package.json b/packages/top-level/codecatalyst-blueprints/package.json index 61b4640be..a4e9b0ccd 100644 --- a/packages/top-level/codecatalyst-blueprints/package.json +++ b/packages/top-level/codecatalyst-blueprints/package.json @@ -50,7 +50,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "types": "lib/index.d.ts", "preferGlobal": true, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." diff --git a/packages/utils/blueprint-cli/package.json b/packages/utils/blueprint-cli/package.json index 668f5556c..56f220256 100644 --- a/packages/utils/blueprint-cli/package.json +++ b/packages/utils/blueprint-cli/package.json @@ -71,7 +71,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "jest": { "testMatch": [ "/src/**/__tests__/**/*.ts?(x)", diff --git a/packages/utils/projen-blueprint-component/package.json b/packages/utils/projen-blueprint-component/package.json index bd733c804..cf432964c 100644 --- a/packages/utils/projen-blueprint-component/package.json +++ b/packages/utils/projen-blueprint-component/package.json @@ -41,7 +41,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "types": "lib/index.d.ts", "preferGlobal": true, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." diff --git a/packages/utils/projen-blueprint/package.json b/packages/utils/projen-blueprint/package.json index aaf28f201..7f9196b7b 100644 --- a/packages/utils/projen-blueprint/package.json +++ b/packages/utils/projen-blueprint/package.json @@ -43,7 +43,7 @@ }, "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.3.25", + "version": "0.3.26", "types": "lib/index.d.ts", "preferGlobal": true, "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."