From bb46fe8f817c58a9ca9dac5e4367c3e503229642 Mon Sep 17 00:00:00 2001 From: Yong Tao Date: Wed, 6 Nov 2024 12:37:37 -0800 Subject: [PATCH 1/3] initial check-in --- .github/PULL_REQUEST_TEMPLATE.md | 1 + .gitignore | 5 + .npmignore | 4 + README.md | 49 +- assets/icons/appconfig.svg | 10 + assets/icons/cloudformation.svg | 10 + assets/icons/codepipeline.svg | 10 + assets/icons/ec2.svg | 10 + assets/icons/ecr.svg | 10 + assets/icons/ecs.svg | 10 + assets/icons/gradle.svg | 1 + assets/icons/lambda.svg | 10 + assets/icons/maven.svg | 1 + assets/icons/nodejs.svg | 1 + assets/icons/python.svg | 1 + assets/icons/reflect.svg | 12 + package-lock.json | 885 ++++++++++++++++++ package.json | 29 + scripts/merge-cloudformation-templates.ts | 224 +++++ scripts/strip-comments.ts | 27 + scripts/validate-schemas.ts | 109 +++ templates/cloudformation/ci-build-gradle.yaml | 447 +++++++++ templates/cloudformation/ci-build-maven.yaml | 447 +++++++++ templates/cloudformation/ci-build-nodejs.yaml | 453 +++++++++ templates/cloudformation/ci-build-python.yaml | 450 +++++++++ .../ci-schedule-build-gradle.yaml | 510 ++++++++++ .../ci-schedule-build-maven.yaml | 510 ++++++++++ .../ci-schedule-build-nodejs.yaml | 516 ++++++++++ .../ci-schedule-build-python.yaml | 513 ++++++++++ templates/cloudformation/deploy-to-cfn.yaml | 360 +++++++ templates/cloudformation/deploy-to-ecr.yaml | 507 ++++++++++ .../cloudformation/deploy-to-ecs-fargate.yaml | 765 +++++++++++++++ templates/cloudformation/test-on-reflect.yaml | 581 ++++++++++++ templates/metadata/README.md | 17 + templates/metadata/ci-build-gradle.json | 11 + templates/metadata/ci-build-maven.json | 11 + templates/metadata/ci-build-nodejs.json | 11 + templates/metadata/ci-build-python.json | 11 + .../metadata/ci-schedule-build-gradle.json | 11 + .../metadata/ci-schedule-build-maven.json | 11 + .../metadata/ci-schedule-build-nodejs.json | 11 + .../metadata/ci-schedule-build-python.json | 11 + templates/metadata/deploy-to-cfn.json | 11 + templates/metadata/deploy-to-ecr.json | 11 + templates/metadata/deploy-to-ecs-fargate.json | 11 + templates/metadata/schema.json | 39 + templates/metadata/test-on-reflect.json | 11 + templates/ui-hints/README.md | 15 + templates/ui-hints/ci-build-gradle.json | 36 + templates/ui-hints/ci-build-maven.json | 43 + templates/ui-hints/ci-build-nodejs.json | 43 + templates/ui-hints/ci-build-python.json | 43 + .../ui-hints/ci-schedule-build-gradle.json | 53 ++ .../ui-hints/ci-schedule-build-maven.json | 53 ++ .../ui-hints/ci-schedule-build-nodejs.json | 53 ++ .../ui-hints/ci-schedule-build-python.json | 53 ++ templates/ui-hints/deploy-to-cfn.json | 70 ++ templates/ui-hints/deploy-to-ecr.json | 47 + templates/ui-hints/deploy-to-ecs-fargate.json | 31 + templates/ui-hints/schema.json | 70 ++ templates/ui-hints/test-on-reflect.json | 94 ++ tsconfig.json | 10 + 62 files changed, 8375 insertions(+), 5 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 assets/icons/appconfig.svg create mode 100644 assets/icons/cloudformation.svg create mode 100644 assets/icons/codepipeline.svg create mode 100644 assets/icons/ec2.svg create mode 100644 assets/icons/ecr.svg create mode 100644 assets/icons/ecs.svg create mode 100644 assets/icons/gradle.svg create mode 100644 assets/icons/lambda.svg create mode 100644 assets/icons/maven.svg create mode 100644 assets/icons/nodejs.svg create mode 100644 assets/icons/python.svg create mode 100644 assets/icons/reflect.svg create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/merge-cloudformation-templates.ts create mode 100644 scripts/strip-comments.ts create mode 100644 scripts/validate-schemas.ts create mode 100644 templates/cloudformation/ci-build-gradle.yaml create mode 100644 templates/cloudformation/ci-build-maven.yaml create mode 100644 templates/cloudformation/ci-build-nodejs.yaml create mode 100644 templates/cloudformation/ci-build-python.yaml create mode 100644 templates/cloudformation/ci-schedule-build-gradle.yaml create mode 100644 templates/cloudformation/ci-schedule-build-maven.yaml create mode 100644 templates/cloudformation/ci-schedule-build-nodejs.yaml create mode 100644 templates/cloudformation/ci-schedule-build-python.yaml create mode 100644 templates/cloudformation/deploy-to-cfn.yaml create mode 100644 templates/cloudformation/deploy-to-ecr.yaml create mode 100644 templates/cloudformation/deploy-to-ecs-fargate.yaml create mode 100644 templates/cloudformation/test-on-reflect.yaml create mode 100644 templates/metadata/README.md create mode 100644 templates/metadata/ci-build-gradle.json create mode 100644 templates/metadata/ci-build-maven.json create mode 100644 templates/metadata/ci-build-nodejs.json create mode 100644 templates/metadata/ci-build-python.json create mode 100644 templates/metadata/ci-schedule-build-gradle.json create mode 100644 templates/metadata/ci-schedule-build-maven.json create mode 100644 templates/metadata/ci-schedule-build-nodejs.json create mode 100644 templates/metadata/ci-schedule-build-python.json create mode 100644 templates/metadata/deploy-to-cfn.json create mode 100644 templates/metadata/deploy-to-ecr.json create mode 100644 templates/metadata/deploy-to-ecs-fargate.json create mode 100644 templates/metadata/schema.json create mode 100644 templates/metadata/test-on-reflect.json create mode 100644 templates/ui-hints/README.md create mode 100644 templates/ui-hints/ci-build-gradle.json create mode 100644 templates/ui-hints/ci-build-maven.json create mode 100644 templates/ui-hints/ci-build-nodejs.json create mode 100644 templates/ui-hints/ci-build-python.json create mode 100644 templates/ui-hints/ci-schedule-build-gradle.json create mode 100644 templates/ui-hints/ci-schedule-build-maven.json create mode 100644 templates/ui-hints/ci-schedule-build-nodejs.json create mode 100644 templates/ui-hints/ci-schedule-build-python.json create mode 100644 templates/ui-hints/deploy-to-cfn.json create mode 100644 templates/ui-hints/deploy-to-ecr.json create mode 100644 templates/ui-hints/deploy-to-ecs-fargate.json create mode 100644 templates/ui-hints/schema.json create mode 100644 templates/ui-hints/test-on-reflect.json create mode 100644 tsconfig.json diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..3e73255 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1 @@ +By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44347b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/build +/dist +/coverage +/generated-metadata \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..47eecf3 --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +/node_modules +/build +/dist +/coverage \ No newline at end of file diff --git a/README.md b/README.md index 847260c..c6af0af 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,50 @@ -## My Project +# CodePipeline Starter Templates -TODO: Fill this README out! +This repository contains a collection of starter templates for AWS CodePipeline, designed to help users quickly set up and configure their CI/CD pipelines for various project types and deployment scenarios. -Be sure to: +## Repository Structure -* Change the title in this README -* Edit your repository description on GitHub +- `/templates`: Contains the main components of the starter templates + - `/metadata`: JSON files describing each template. These files control how templates are rendered in the CodePipeline console. For more details on the schema and usage, refer to the [metadata README](templates/metadata/README.md). + - `/cloudformation`: CloudFormation templates for each pipeline configuration. + - `/ui-hints`: JSON files controlling the rendering of template configuration in the CodePipeline console. These files define how the template configuration step is displayed. For more information on the schema and usage, refer to the [UI hints README](templates/ui-hints/README.md). +- `assets`: Contains svg icons for the starter templates + + +## Development + +This project uses Node.js for development tasks. To set up the development environment: + +1. Ensure you have Node.js 18 or later installed +2. Run `npm install` to install dependencies +3. Use the provided npm scripts for various tasks: + - `npm run clean`: Remove generated files and directories + - `npm run test`: Run all validation and merging scripts + - `npm run validate-schemas`: Validate JSON schemas + - `npm run merge-cloudformation-templates`: Merge CloudFormation templates + +### Adding new templates + +To add a new template, follow these steps: + +1. Create a new metadata file for the template in the `/templates/metadata` folder. This file should conform to the schema defined in `/templates/metadata/schema.json`. + +2. Add the corresponding CloudFormation template file in the `/templates/cloudformation` folder. + +3. The build script will automatically validate the metadata and CloudFormation template files, and generate the synthesized files for the CodePipeline Console to render. + +### Adding new icons + +You are not required to add a new icon for your template. You can use the existing `codepipeline.svg` icon located in the `assets/icons/` folder. + +If you want to add a new icon to this package, +1. Add the SVG file to the `assets/icons/` folder in this project. +2. The icon-name in the metadata should correspond to the relevant folder, for example, `icon-name: lambda` expects an icon file at `asset/icons/lambda.svg`. + + +## Contributing + +We welcome contributions to this project. Please read our [Contributing Guidelines](CONTRIBUTING.md) for more information on how to add new templates or improve existing ones. ## Security diff --git a/assets/icons/appconfig.svg b/assets/icons/appconfig.svg new file mode 100644 index 0000000..354930b --- /dev/null +++ b/assets/icons/appconfig.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_AWS-AppConfig_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/cloudformation.svg b/assets/icons/cloudformation.svg new file mode 100644 index 0000000..bbc2572 --- /dev/null +++ b/assets/icons/cloudformation.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_AWS-CloudFormation_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/codepipeline.svg b/assets/icons/codepipeline.svg new file mode 100644 index 0000000..9c8e1a8 --- /dev/null +++ b/assets/icons/codepipeline.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_AWS-CodePipeline_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/ec2.svg b/assets/icons/ec2.svg new file mode 100644 index 0000000..31a57ec --- /dev/null +++ b/assets/icons/ec2.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_Amazon-EC2_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/ecr.svg b/assets/icons/ecr.svg new file mode 100644 index 0000000..a889ae6 --- /dev/null +++ b/assets/icons/ecr.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_Amazon-Elastic-Container-Registry_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/ecs.svg b/assets/icons/ecs.svg new file mode 100644 index 0000000..b7c3191 --- /dev/null +++ b/assets/icons/ecs.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_Amazon-Elastic-Container-Service_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/gradle.svg b/assets/icons/gradle.svg new file mode 100644 index 0000000..12dd365 --- /dev/null +++ b/assets/icons/gradle.svg @@ -0,0 +1 @@ +gradle-elephant-icon-gradient-primary diff --git a/assets/icons/lambda.svg b/assets/icons/lambda.svg new file mode 100644 index 0000000..e4d2e7f --- /dev/null +++ b/assets/icons/lambda.svg @@ -0,0 +1,10 @@ + + + Icon-Architecture/64/Arch_AWS-Lambda_64 + + + + + + + \ No newline at end of file diff --git a/assets/icons/maven.svg b/assets/icons/maven.svg new file mode 100644 index 0000000..23ac6fe --- /dev/null +++ b/assets/icons/maven.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/nodejs.svg b/assets/icons/nodejs.svg new file mode 100644 index 0000000..1a75afa --- /dev/null +++ b/assets/icons/nodejs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/python.svg b/assets/icons/python.svg new file mode 100644 index 0000000..a0b9663 --- /dev/null +++ b/assets/icons/python.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/reflect.svg b/assets/icons/reflect.svg new file mode 100644 index 0000000..e8e5891 --- /dev/null +++ b/assets/icons/reflect.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..803d6f9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,885 @@ +{ + "name": "@aws/codepipeline-starter-templates", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@aws/codepipeline-starter-templates", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@tsconfig/node18": "*", + "ajv": "*", + "ajv-draft-04": "*", + "glob": "*", + "js-yaml": "*", + "prettier": "*", + "strip-comments": "*", + "ts-node": "*", + "typescript": "*", + "yaml-cfn": "^0.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node18": { + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", + "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yaml-cfn": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/yaml-cfn/-/yaml-cfn-0.3.2.tgz", + "integrity": "sha512-MvrWhv40GKWHFGCliTGGAMwAeqIXf/bzf6WW48+xND9iMp8cTj0R8xkwM0lX/GzNN/EZKr5gP4Hx63Fn+sICoA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "js-yaml": "^4.0.0" + }, + "bin": { + "yaml-cfn": "cli.js" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..73d6a74 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "@aws/codepipeline-starter-templates", + "version": "1.0.0", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "scripts": { + "clean": "rm -rf node_modules dist build generated-metadata", + "copy-templates": "cp -r templates/metadata generated-metadata", + "strip-comments": "npx ts-node scripts/strip-comments.ts", + "pre-test": "rm -rf generated-metadata && npm run copy-templates && npm run strip-comments", + "merge-cloudformation-templates": "npx ts-node scripts/merge-cloudformation-templates.ts", + "validate-schemas": "npx ts-node scripts/validate-schemas.ts", + "test": "npm run pre-test && npm run validate-schemas && npm run merge-cloudformation-templates" + }, + "devDependencies": { + "@tsconfig/node18": "*", + "ajv": "*", + "ajv-draft-04": "*", + "glob": "*", + "js-yaml": "*", + "prettier": "*", + "strip-comments": "*", + "ts-node": "*", + "typescript": "*", + "yaml-cfn": "^0.3.2" + } +} diff --git a/scripts/merge-cloudformation-templates.ts b/scripts/merge-cloudformation-templates.ts new file mode 100644 index 0000000..6fe2309 --- /dev/null +++ b/scripts/merge-cloudformation-templates.ts @@ -0,0 +1,224 @@ +import * as fs from "fs"; +import { glob } from "glob"; +import * as path from "path"; +import * as yaml from "js-yaml"; +import { schema } from "yaml-cfn"; + +type CloudFormationParameterType = "String" | "Number"; +type CloudFormationParametersAllowedValue = string; +interface CloudFormationParameter { + Description?: string; + Type: CloudFormationParameterType; + Default?: string; + AllowedValues?: CloudFormationParametersAllowedValue[]; +} +type TemplateInputType = + | "text" + | "password" + | "search" + | "number" + | "email" + | "url"; +interface TemplateInputOption { + value: string; + label?: string; +} +interface TextEditorStyle { + mode: string; + minLines: number; + maxLines: number; +} + +/** + * A superset of several Cloudscape component properties. + * + * @see https://cloudscape.aws.dev/components/input/ + */ +interface TemplateInput { + placeholder?: string; + type?: TemplateInputType; + description?: string; + value?: string | TemplateInputOption; + options?: TemplateInputOption[]; +} + +/** + * Removes undefined fields from an object. + * + * @template T - The type of the object to process. It must extend the built-in `Record` type, + * which means it should be an object with string keys and values of any type. + * + * @param obj - The object to remove undefined fields from. + * + * @returns A new object with the same keys as the input object, but with undefined values removed. + * The return type is `Partial`, which means that all properties of the returned object + * are optional (i.e., they can be undefined). + */ +function removeUndefinedFields>( + obj: T +): Partial { + // Convert the input object to an array of key-value pairs using `Object.entries()`. + // Then, filter out the pairs where the value is undefined using the `.filter()` method. + // Finally, convert the filtered array back to an object using `Object.fromEntries()`. + return Object.fromEntries( + Object.entries(obj).filter(([_, v]) => v !== undefined) + ) as Partial; +} + +/** + * Convert a CloudFormation parameter type to a template input type. + * + * @param parameterType - a CloudFormation parameter type to be converted to template input type. + * + * @returns A template input type. + * + * @see https://cloudscape.design/components/input/?tabId=api + */ +function convertToTemplateInputType( + parameterType: CloudFormationParameterType +): TemplateInputType { + switch (parameterType) { + case "Number": + return "number"; + case "String": + return "text"; + default: + throw new Error( + `Unsupported CloudFormation parameter type: ${parameterType}` + ); + } +} + +function convertToTemplateInputOption( + allowedValue: CloudFormationParametersAllowedValue +): TemplateInputOption { + return { + value: allowedValue, + label: allowedValue, + }; +} + +/** + * Convert an object of CloudFormation parameters to template inputs. + * + * @param cloudformationParameters the object of CloudFormation parameters to be converted to template inputs. + */ +function convertToTemplateInputs( + cloudformationParameters: Record, + uiPlaceholders: Record, + textEditorStyles: Record +): TemplateInput[] { + return Object.entries(cloudformationParameters).map( + ([name, cloudformationParameter]) => + removeUndefinedFields({ + name, + type: convertToTemplateInputType(cloudformationParameter["Type"]), + description: cloudformationParameter["Description"], + placeholder: + uiPlaceholders && name in uiPlaceholders + ? uiPlaceholders[name] + : cloudformationParameter["Default"], + value: + cloudformationParameter["AllowedValues"] && + cloudformationParameter["Default"] + ? convertToTemplateInputOption(cloudformationParameter["Default"]) + : cloudformationParameter["Default"], + options: cloudformationParameter["AllowedValues"]?.map( + convertToTemplateInputOption + ), + textEditorStyle: + textEditorStyles && name in textEditorStyles + ? textEditorStyles[name] + : undefined, + }) + ); +} + +/** + * Checks if the provided ui-hints contain any key names that are not defined in the CloudFormation parameters. + * If invalid keys are found, it logs an error message and exits the process with a non-zero status code. + * + * @package uiHintsFileName - The name of the ui-hints file + * @param uiHints - An object containing the ui-hints. + * @param cloudformationParameters - An object containing the CloudFormation parameters. + */ +function checkUiHints( + uiHintsFileName: string, + uiHints: Record, + cloudformationParameters: Record +): void { + const parameterKeys = Object.keys(cloudformationParameters); + const uiHintsKeysToCheck = [ + "constraints", + "placeholders", + "text-editor-styles", + ]; + + for (const uiHintsKey of uiHintsKeysToCheck) { + const hints = uiHints[uiHintsKey]; + if (!hints) { + continue; + } + const invalidKeys = Object.keys(hints).filter( + (key) => !parameterKeys.includes(key) + ); + + if (invalidKeys.length > 0) { + const invalidKeysString = invalidKeys.join(", "); + const errorMessage = `Invalid keys in ${uiHintsFileName} ${uiHintsKey}: ${invalidKeysString}`; + console.error(errorMessage); + process.exit(1); + } + } +} + +function main() { + const metadataFiles = glob.sync("generated-metadata/**/*.json"); + metadataFiles.forEach((metadataFile) => { + if (!metadataFile.endsWith("schema.json")) { + console.log(metadataFile); + const metadataContent = JSON.parse( + fs.readFileSync(metadataFile, "utf-8") + ); + + const uiHintsFile = metadataContent["ui-hints-location"]; + const uiHints = JSON.parse( + fs.readFileSync(path.join("templates", uiHintsFile), "utf-8") + ); + + const cloudformationFile = metadataContent["template-location"]; + if (cloudformationFile && cloudformationFile.endsWith("yaml")) { + const cloudformationContent = fs.readFileSync( + path.join("templates", cloudformationFile), + "utf-8" + ); + metadataContent["template-body"] = cloudformationContent; + + const cloudformationParameters = + yaml.load(cloudformationContent, { schema })["Parameters"] ?? {}; + + checkUiHints(uiHintsFile, uiHints, cloudformationParameters); + + const templateInputs = convertToTemplateInputs( + cloudformationParameters, + uiHints["placeholders"], + uiHints["text-editor-styles"] + ); + metadataContent["template-inputs"] = templateInputs; + } else { + console.log( + `Warning: No 'template-location' key found in ${metadataFile}` + ); + process.exit(1); + } + + const mergedMetadataContent = { ...metadataContent, ...uiHints }; + fs.writeFileSync( + metadataFile, + JSON.stringify(mergedMetadataContent, null, 2) + ); + } + }); +} + +main(); diff --git a/scripts/strip-comments.ts b/scripts/strip-comments.ts new file mode 100644 index 0000000..0895192 --- /dev/null +++ b/scripts/strip-comments.ts @@ -0,0 +1,27 @@ +import * as fs from "fs"; +import { glob } from 'glob'; + +const strip = require('strip-comments'); + +/** + * The main entry-point + */ +function main() { + const jsonFiles = glob.globSync('generated-metadata/**/*.json'); + console.log('\nLOADING CONFIGS:\n'); + jsonFiles.forEach((jsonFile: string) => { + console.log(`- Found File: ${jsonFile}`); + stripJsonComments(jsonFile); + }); +} + +/** + * Reads a file and removes comments, then overwrites the original + */ +function stripJsonComments(jsonFile: string) { + const rawContents = fs.readFileSync(jsonFile).toString('utf-8'); + const strippedContents = strip(rawContents); + fs.writeFileSync(jsonFile, strippedContents); +} + +main(); \ No newline at end of file diff --git a/scripts/validate-schemas.ts b/scripts/validate-schemas.ts new file mode 100644 index 0000000..796ca0b --- /dev/null +++ b/scripts/validate-schemas.ts @@ -0,0 +1,109 @@ +import {ValidateFunction} from "ajv"; +import * as fs from "fs"; +import { glob } from 'glob'; + +/* + * AWS AppConfig only support version JSON Schema version 4.x. + * Ref: https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-creating-configuration-and-profile.html#appconfig-creating-configuration-and-profile-validators + */ +const Ajv = require("ajv-draft-04") +const ajv = new Ajv(); + +/** + * The main entry-point + */ +function main() { + validate('templates/metadata/**/*.json'); + validate('templates/ui-hints/**/*.json'); +} + +/** + * Takes a folder and validate the files within the folder + */ +function validate(filePath: string) { + const jsonFiles = glob.globSync(filePath); + const schemaValidator = findAndCompileJsonSchema(jsonFiles); + if (schemaValidator == null) { + process.exit(1) + } + const metadataFiles = findJsonConfigs(jsonFiles); + if (!validateSchemas(metadataFiles, schemaValidator)) { + process.exit(1); + } +} + +/** + * Takes in a list of json-files, identifies the schema-file, loads+compiles the same. + */ +function findAndCompileJsonSchema(jsonFiles: string[]): ValidateFunction | null { + console.log('\nLOADING SCHEMAS:\n'); + let compiledSchema: ValidateFunction | null = null; + + jsonFiles.forEach((jsonFile) => { + if (jsonFile.endsWith('schema.json')) { + console.log(`- Found Schema: ${jsonFile}`); + const schemaObject = readJsonObjectFromFile(jsonFile); + compiledSchema = ajv.compile(schemaObject); + } + }); + + if (compiledSchema) { + return compiledSchema; + } else { + console.log('- No schema file found.'); + return null; + } +} + +/** + * Reads a file and parses it into a JSON object + */ +function readJsonObjectFromFile(jsonFile: string) { + const fileContents = fs.readFileSync(jsonFile).toString('utf-8'); + return JSON.parse(fileContents); +} + +/** + * Takes in a list of json-files, identifies the (non-schema) config-files, and groups them - to + * return a map of config-name -> list of config-files + */ +function findJsonConfigs(jsonFiles: string[]): string[] { + const fileList: string[] = [] + jsonFiles.forEach((jsonFile) => { + if (!jsonFile.endsWith('schema.json')) { + fileList.push(jsonFile); + } + }); + return fileList; +} + + +/** + * Iterates over the config-files and validates each one with the corresponding schema file. + * Logs a comment if it's not able to find a schema for a given set of config-files. + * Logs the errors if a config file fails the schema validation. + * Returns true if all schema validations pass successfully. + */ +function validateSchemas( + configFiles: string[], + schemaValidator: ValidateFunction +): boolean { + console.log('\nVALIDATING CONFIGS:\n'); + let valid = true; + + configFiles.forEach((configFile) => { + const configObject = readJsonObjectFromFile(configFile); + const validatorResults = schemaValidator(configObject); + if (!validatorResults) { + valid = false; + console.log(`[ERROR] ${configFile}\n`); + console.log(schemaValidator.errors); + console.log('\n'); + } else { + console.log(`[OK] ${configFile}\n`); + } + }) + return valid; +} + +main(); \ No newline at end of file diff --git a/templates/cloudformation/ci-build-gradle.yaml b/templates/cloudformation/ci-build-gradle.yaml new file mode 100644 index 0000000..ff59624 --- /dev/null +++ b/templates/cloudformation/ci-build-gradle.yaml @@ -0,0 +1,447 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your gradle source project. + Type: String + Default: SimpleGradleBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec gradle configuration + Type: String + Default: | + version: 0.2 + + phases: + build: + commands: + - echo "Starting gradle build..." + - ./gradlew build + - echo "Gradle build finished successfully!" + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build gradle source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: GradleBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_Gradle_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-build-maven.yaml b/templates/cloudformation/ci-build-maven.yaml new file mode 100644 index 0000000..eec7f8e --- /dev/null +++ b/templates/cloudformation/ci-build-maven.yaml @@ -0,0 +1,447 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your maven source project. + Type: String + Default: SimpleMavenBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec maven configuration + Type: String + Default: | + version: 0.2 + + phases: + build: + commands: + - echo "Starting maven build" + - mvn -B package --file pom.xml + - echo "Completed maven build successfully!" + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build maven source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: MavenBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_Maven_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-build-nodejs.yaml b/templates/cloudformation/ci-build-nodejs.yaml new file mode 100644 index 0000000..300238d --- /dev/null +++ b/templates/cloudformation/ci-build-nodejs.yaml @@ -0,0 +1,453 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your nodejs source project. + Type: String + Default: SimpleNodeJSBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec nodejs configuration + Type: String + Default: | + version: 0.2 + + phases: + install: + runtime-versions: + nodejs: 18.x + commands: + - echo "Installing dependencies" + - npm install + build: + commands: + - echo "Running tests and type checks" + - npm run build --if-present + - npm test + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build nodejs source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: NodeJSBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_NodeJS_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-build-python.yaml b/templates/cloudformation/ci-build-python.yaml new file mode 100644 index 0000000..14dfde1 --- /dev/null +++ b/templates/cloudformation/ci-build-python.yaml @@ -0,0 +1,450 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your python source project. + Type: String + Default: SimplePythonBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec python configuration + Type: String + Default: | + version: 0.2 + + phases: + build: + commands: + - echo "Install python dependencies" + - python -m pip install --upgrade pip + - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + # - echo "Run tests" + # - python -m pip install flake8 pytest + # - pytest + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build python source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: PythonBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_Python_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimplePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-schedule-build-gradle.yaml b/templates/cloudformation/ci-schedule-build-gradle.yaml new file mode 100644 index 0000000..8597fe3 --- /dev/null +++ b/templates/cloudformation/ci-schedule-build-gradle.yaml @@ -0,0 +1,510 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your gradle source project. + Type: String + Default: SimpleScheduleGradleBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec gradle configuration + Type: String + Default: | + version: 0.2 + + phases: + build: + commands: + - echo "Starting gradle build..." + - ./gradlew build + - echo "Gradle build finished successfully!" + ScheduleExpression: + Description: The amazon event bridge schedule cron expression that would trigger a pipeline periodically. A cron expression consists of five required fields separated by white space (minutes, hours, day-of-month, month, day-of-week, and one optional field, year). The default cron expression would trigger the pipeline at 9AM everyday from Monday to Friday. For scheduling nightly builds you can use (0 0 ? * * *). For scheduling weekly builds you can use (0 0 ? * SUN *) + Type: String + Default: '0 9 ? * MON-FRI *' + ScheduleExpressionTimezone: + Description: The timezone in which the event bridge scheduling expression is evaluated. For example, America/Los_Angeles | America/New_York | UTC + Type: String + Default: 'America/Los_Angeles' + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + SimpleGradleBuildScheduler: + Type: AWS::Scheduler::Schedule + DependsOn: + - CodePipeline + Properties: + Description: "Schedule that would trigger a gradle build pipeline periodically" + Name: + Fn::Join: + - '-' + - - SimpleGradleBuildScheduler + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ScheduleExpression: !Sub + - cron(${scheduleExpression}) + - scheduleExpression: !Ref ScheduleExpression + FlexibleTimeWindow: + Mode: "OFF" + ScheduleExpressionTimezone: !Ref ScheduleExpressionTimezone + State: "ENABLED" + Target: + Arn: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + RoleArn: !GetAtt EventBridgeGradleSchedulerRole.Arn + EventBridgeGradleSchedulerRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: scheduler.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: AmazonCodePipelineGradleEventBridgeSchedulerPolicy + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'codepipeline:StartPipelineExecution' + Resource: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build gradle source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + DetectChanges: 'false' + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: GradleBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_Gradle_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleScheduleGradleBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-schedule-build-maven.yaml b/templates/cloudformation/ci-schedule-build-maven.yaml new file mode 100644 index 0000000..f95dcb2 --- /dev/null +++ b/templates/cloudformation/ci-schedule-build-maven.yaml @@ -0,0 +1,510 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your maven source project. + Type: String + Default: SimpleScheduleMavenBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec maven configuration + Type: String + Default: | + version: 0.2 + + phases: + build: + commands: + - echo "Starting maven build" + - mvn -B package --file pom.xml + - echo "Completed maven build successfully!" + ScheduleExpression: + Description: The amazon event bridge schedule cron expression that would trigger a pipeline periodically. A cron expression consists of five required fields separated by white space (minutes, hours, day-of-month, month, day-of-week, and one optional field, year). The default cron expression would trigger the pipeline at 9AM everyday from Monday to Friday. For scheduling nightly builds you can use (0 0 ? * * *). For scheduling weekly builds you can use (0 0 ? * SUN *) + Type: String + Default: '0 9 ? * MON-FRI *' + ScheduleExpressionTimezone: + Description: The timezone in which the event bridge scheduling expression is evaluated. For example, America/Los_Angeles | America/New_York | UTC + Type: String + Default: 'America/Los_Angeles' + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + SimpleMavenBuildScheduler: + Type: AWS::Scheduler::Schedule + DependsOn: + - CodePipeline + Properties: + Description: "Schedule that would trigger a maven build pipeline periodically" + Name: + Fn::Join: + - '-' + - - SimpleMavenBuildScheduler + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ScheduleExpression: !Sub + - cron(${scheduleExpression}) + - scheduleExpression: !Ref ScheduleExpression + FlexibleTimeWindow: + Mode: "OFF" + ScheduleExpressionTimezone: !Ref ScheduleExpressionTimezone + State: "ENABLED" + Target: + Arn: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + RoleArn: !GetAtt EventBridgeMavenSchedulerRole.Arn + EventBridgeMavenSchedulerRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: scheduler.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: AmazonCodePipelineMavenEventBridgeSchedulerPolicy + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'codepipeline:StartPipelineExecution' + Resource: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build maven source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + DetectChanges: 'false' + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: MavenBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_Maven_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleScheduleMavenBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-schedule-build-nodejs.yaml b/templates/cloudformation/ci-schedule-build-nodejs.yaml new file mode 100644 index 0000000..f995a10 --- /dev/null +++ b/templates/cloudformation/ci-schedule-build-nodejs.yaml @@ -0,0 +1,516 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your nodejs source project. + Type: String + Default: SimpleScheduleNodeJSBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec nodejs configuration + Type: String + Default: | + version: 0.2 + + phases: + install: + runtime-versions: + nodejs: 18.x + commands: + - echo "Installing dependencies" + - npm install + build: + commands: + - echo "Running tests and type checks" + - npm run build --if-present + - npm test + ScheduleExpression: + Description: The amazon event bridge schedule cron expression that would trigger a pipeline periodically. A cron expression consists of five required fields separated by white space (minutes, hours, day-of-month, month, day-of-week, and one optional field, year). The default cron expression would trigger the pipeline at 9AM everyday from Monday to Friday. For scheduling nightly builds you can use (0 0 ? * * *). For scheduling weekly builds you can use (0 0 ? * SUN *) + Type: String + Default: '0 9 ? * MON-FRI *' + ScheduleExpressionTimezone: + Description: The timezone in which the event bridge scheduling expression is evaluated. For example, America/Los_Angeles | America/New_York | UTC + Type: String + Default: 'America/Los_Angeles' + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + SimpleNodeJSBuildScheduler: + Type: AWS::Scheduler::Schedule + DependsOn: + - CodePipeline + Properties: + Description: "Schedule that would trigger a nodejs build pipeline periodically" + Name: + Fn::Join: + - '-' + - - SimpleNodeJSBuildScheduler + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ScheduleExpression: !Sub + - cron(${scheduleExpression}) + - scheduleExpression: !Ref ScheduleExpression + FlexibleTimeWindow: + Mode: "OFF" + ScheduleExpressionTimezone: !Ref ScheduleExpressionTimezone + State: "ENABLED" + Target: + Arn: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + RoleArn: !GetAtt EventBridgeNodeJSSchedulerRole.Arn + EventBridgeNodeJSSchedulerRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: scheduler.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: AmazonCodePipelineNodeJSEventBridgeSchedulerPolicy + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'codepipeline:StartPipelineExecution' + Resource: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build nodejs source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + DetectChanges: 'false' + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: NodeJSBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_NodeJS_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleScheduleNodeJSBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/ci-schedule-build-python.yaml b/templates/cloudformation/ci-schedule-build-python.yaml new file mode 100644 index 0000000..6ccbc9f --- /dev/null +++ b/templates/cloudformation/ci-schedule-build-python.yaml @@ -0,0 +1,513 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build your python source project. + Type: String + Default: SimpleSchedulePythonBuildService + CICodeBuildSpec: + Description: The CodeBuild project build spec python configuration + Type: String + Default: | + version: 0.2 + + phases: + build: + commands: + - echo "Install python dependencies" + - python -m pip install --upgrade pip + - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + # - echo "Run tests" + # - python -m pip install flake8 pytest + # - pytest + ScheduleExpression: + Description: The amazon event bridge schedule cron expression that would trigger a pipeline periodically. A cron expression consists of five required fields separated by white space (minutes, hours, day-of-month, month, day-of-week, and one optional field, year). The default cron expression would trigger the pipeline at 9AM everyday from Monday to Friday. For scheduling nightly builds you can use (0 0 ? * * *). For scheduling weekly builds you can use (0 0 ? * SUN *) + Type: String + Default: '0 9 ? * MON-FRI *' + ScheduleExpressionTimezone: + Description: The timezone in which the event bridge scheduling expression is evaluated. For example, America/Los_Angeles | America/New_York | UTC + Type: String + Default: 'America/Los_Angeles' + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + SimplePythonBuildScheduler: + Type: AWS::Scheduler::Schedule + DependsOn: + - CodePipeline + Properties: + Description: "Schedule that would trigger a python build pipeline periodically" + Name: + Fn::Join: + - '-' + - - SimplePythonBuildScheduler + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ScheduleExpression: !Sub + - cron(${scheduleExpression}) + - scheduleExpression: !Ref ScheduleExpression + FlexibleTimeWindow: + Mode: "OFF" + ScheduleExpressionTimezone: !Ref ScheduleExpressionTimezone + State: "ENABLED" + Target: + Arn: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + RoleArn: !GetAtt EventBridgePythonSchedulerRole.Arn + EventBridgePythonSchedulerRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: scheduler.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: AmazonCodePipelinePythonEventBridgeSchedulerPolicy + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'codepipeline:StartPipelineExecution' + Resource: !Sub + - arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${pipelineName} + - pipelineName: !Ref CodePipelineName + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build python source code + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + DetectChanges: 'false' + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: PythonBuild + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: CI_Python_Build + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleSchedulePythonBuildProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/deploy-to-cfn.yaml b/templates/cloudformation/deploy-to-cfn.yaml new file mode 100644 index 0000000..e00e788 --- /dev/null +++ b/templates/cloudformation/deploy-to-cfn.yaml @@ -0,0 +1,360 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will deploy to your CloudFormation stack. + Type: String + Default: DeployToCloudFormationService + StackName: + Description: The CloudFormation stack name that you want to create or update. + Type: String + TemplatePath: + Description: The path in your source repository to the CloudFormation template file to create or update your stack. + Type: String + OutputFileName: + Description: The path the output from the CloudFormation stack update will be written to. + Type: String + Default: output.json + CloudFormationResourcePermissions: + Description: The permission required by CloudFormation to make resource calls on your behalf. + Type: String + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain + TemplateConfiguration: + Description: The path to a template configuration file containing parameter values and stack policy for creating or updating your stack. + Type: String + Default: '' + ParameterOverrides: + Description: A JSON string to provide parameter values that override defaults in the template or TemplateConfiguration file. + Type: String + Default: '' +Conditions: + HasTemplateConfiguration: !Not [!Equals ['', !Ref TemplateConfiguration]] + HasParameterOverrides: !Not [!Equals ['', !Ref ParameterOverrides]] +Resources: + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodePipelineSourceActionRole.Arn + RunOrder: 1 + - Name: Deploy + Actions: + - Name: CloudFormation + ActionTypeId: + Category: Deploy + Owner: AWS + Provider: CloudFormation + Version: '1' + Configuration: + ActionMode: CREATE_UPDATE + Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND,CAPABILITY_NAMED_IAM + StackName: !Ref StackName + TemplatePath: !Sub SourceOutput::${TemplatePath} + RoleArn: !GetAtt CloudFormationRole.Arn + OutputFileName: !Ref OutputFileName + TemplateConfiguration: + !If [HasTemplateConfiguration, !Sub "SourceOutput::${TemplateConfiguration}", !Ref "AWS::NoValue"] + ParameterOverrides: + !If [HasParameterOverrides, !Ref ParameterOverrides, !Ref "AWS::NoValue"] + InputArtifacts: + - Name: SourceOutput + OutputArtifacts: + - Name: DeployOutput + RoleArn: !GetAtt CodePipelineDeployActionRole.Arn + RunOrder: 1 + OnFailure: + Result: ROLLBACK + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + DependsOn: + - CodePipelineRoleDefaultPolicy + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '/' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodePipelineSourceActionRole.Arn + - !GetAtt CodePipelineDeployActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineRoleDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipelineSourceActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodePipelineSourceActionRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '/' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodePipelineSourceActionRoleDefaultPolicy + Roles: + - !Ref CodePipelineSourceActionRole + CodePipelineDeployActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodePipelineDeployActionRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - cloudformation:* + Effect: Allow + Resource: '*' + - Action: iam:PassRole + Condition: + StringEqualsIfExists: + iam:PassedToService: + - cloudformation.amazonaws.com + Effect: Allow + Resource: '*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '/' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodePipelineDeployActionRoleDefaultPolicy + Roles: + - !Ref CodePipelineDeployActionRole + CloudFormationRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: + - cloudformation.amazonaws.com + - codepipeline.amazonaws.com + Version: '2012-10-17' + CloudFormationRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - cloudformation:* + Effect: Allow + Resource: + - !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${StackName} + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodePipelineRole.Arn + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '/' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CloudFormationDefaultPolicy + Roles: + - !Ref CloudFormationRole + CloudFormationRoleResourceCreationPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: !Ref CloudFormationResourcePermissions + PolicyName: CloudFormationResourceCreationPolicy + Roles: + - !Ref CloudFormationRole + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '/' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' diff --git a/templates/cloudformation/deploy-to-ecr.yaml b/templates/cloudformation/deploy-to-ecr.yaml new file mode 100644 index 0000000..2d5c402 --- /dev/null +++ b/templates/cloudformation/deploy-to-ecr.yaml @@ -0,0 +1,507 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your Docker container source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build and deploy your Docker image from source code. + Type: String + Default: SimpleDockerService + DockerBuildContext: + Description: The set of files Docker build can acccess. + Type: String + Default: . + DockerFilePath: + Description: Path to the Dockerfile. + Type: String + Default: ./Dockerfile + ImageTag: + Description: The image tag to use when building and deploying your Docker image. + Type: String + Default: latest + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + EcrRepository: + Type: AWS::ECR::Repository + Properties: + RepositoryName: + Fn::Join: + - '-' + - - simple-docker-service + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + - Action: + - ecr:BatchCheckLayerAvailability + - ecr:CompleteLayerUpload + - ecr:InitiateLayerUpload + - ecr:PutImage + - ecr:UploadLayerPart + Effect: Allow + Resource: !GetAtt EcrRepository.Arn + - Action: ecr:GetAuthorizationToken + Effect: Allow + Resource: '*' + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Build Docker Image from source code + EncryptionKey: alias/aws/s3 + Environment: + EnvironmentVariables: + - Name: ImageName + Type: PLAINTEXT + Value: + Fn::Join: + - '-' + - - simple-docker-service + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Sub | + version: "0.2" + phases: + pre_build: + commands: + - aws ecr get-login-password --region ${AWS::Region} | docker login --username AWS --password-stdin ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com + build: + commands: + - docker build -t $ImageName -f ${DockerFilePath} ${DockerBuildContext} + - docker images + post_build: + commands: + - docker tag $ImageName:${ImageTag} ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/$ImageName:${ImageTag} + - docker push ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/$ImageName:${ImageTag} + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: Build_and_Deploy + OnFailure: + Result: ROLLBACK + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: Docker_Build_Tag_and_Push + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: + Fn::Join: + - '-' + - - SimpleDockerProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/cloudformation/deploy-to-ecs-fargate.yaml b/templates/cloudformation/deploy-to-ecs-fargate.yaml new file mode 100644 index 0000000..843e46a --- /dev/null +++ b/templates/cloudformation/deploy-to-ecs-fargate.yaml @@ -0,0 +1,765 @@ +Parameters: + RepositoryName: + Description: The repository name to use with your ecr action. + Type: String + ImageTag: + Description: The image tag to use when building and deploying your Docker image. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will build and deploy your Docker image from source code. + Type: String + Default: DeployToEcsFargateService + ContainerPort: + Description: The port the service is using inside of the container. + Type: String + Default: '8080' + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain +Resources: + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + CodeBuildRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - !Ref CodeBuildProject + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - !Ref CodeBuildProject + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - !Ref CodeBuildProject + - '-*' + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '/' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeBuildRoleDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Create an imagedefinitions.json for ECS Deploy action + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + Name: + Fn::Join: + - '-' + - - DeployToEcsFargateProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Sub | + version: "0.2" + phases: + build: + commands: + - echo '[{"name":"${RepositoryName}","imageUri":"${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RepositoryName}:${ImageTag}"}]' > imagedefinitions.json + artifacts: + files: + - imagedefinitions.json + Type: NO_SOURCE + Cluster: + Type: AWS::ECS::Cluster + Properties: + ClusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + Vpc: + Type: AWS::EC2::VPC + Properties: + CidrBlock: 10.0.0.0/16 + EnableDnsHostnames: true + EnableDnsSupport: true + InstanceTenancy: default + Tags: + - Key: Name + Value: !Sub + - ${AWS::StackName}/${clusterName}/Vpc + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + PublicSubnet1: + Type: AWS::EC2::Subnet + Properties: + AvailabilityZone: !Sub ${AWS::Region}a + CidrBlock: 10.0.0.0/18 + MapPublicIpOnLaunch: true + Tags: + - Key: aws-cdk:subnet-name + Value: Public + - Key: aws-cdk:subnet-type + Value: Public + - Key: Name + Value: !Sub + - ${AWS::StackName}/${clusterName}/Vpc/PublicSubnet1 + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + VpcId: !Ref Vpc + PublicSubnet1RouteTable: + Type: AWS::EC2::RouteTable + Properties: + Tags: + - Key: Name + Value: !Sub + - ${AWS::StackName}/${clusterName}/Vpc/PublicSubnet1 + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + VpcId: !Ref Vpc + PublicSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicSubnet1RouteTable + SubnetId: !Ref PublicSubnet1 + PublicSubnet1DefaultRoute: + Type: AWS::EC2::Route + Properties: + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref VpcIGW + RouteTableId: !Ref PublicSubnet1RouteTable + DependsOn: + - VpcGatewayAttachment + PublicSubnet1EIP: + Type: AWS::EC2::EIP + Properties: + Domain: vpc + Tags: + - Key: Name + Value: !Sub + - ${AWS::StackName}/${clusterName}/Vpc/PublicSubnet1 + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + PublicSubnet1NATGateway: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt PublicSubnet1EIP.AllocationId + SubnetId: !Ref PublicSubnet1 + Tags: + - Key: Name + Value: !Sub + - ${AWS::StackName}/${clusterName}/Vpc/PublicSubnet1 + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + DependsOn: + - PublicSubnet1DefaultRoute + - PublicSubnet1RouteTableAssociation + VpcIGW: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Sub + - ${AWS::StackName}/${clusterName}/Vpc + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + VpcGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref VpcIGW + VpcId: !Ref Vpc + TaskDefinitionTaskRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Version: '2012-10-17' + TaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + ContainerDefinitions: + - Essential: true + Image: !Join + - '' + - - !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}. + - !Ref AWS::URLSuffix + - !Sub /${RepositoryName}:${ImageTag} + Name: DeployToEcsFargateContainerName + PortMappings: + - ContainerPort: !Ref ContainerPort + Protocol: tcp + Cpu: '256' + ExecutionRoleArn: !GetAtt TaskDefinitionExecutionRole.Arn + Family: DeployToEcsFargateTaskDefinitionFamily + Memory: '512' + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + RuntimePlatform: + CpuArchitecture: X86_64 + OperatingSystemFamily: LINUX + TaskRoleArn: !GetAtt TaskDefinitionTaskRole.Arn + TaskDefinitionExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Version: '2012-10-17' + TaskDefinitionExecutionRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - ecr:BatchCheckLayerAvailability + - ecr:BatchGetImage + - ecr:GetDownloadUrlForLayer + Effect: Allow + Resource: !Sub arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/${RepositoryName} + - Action: ecr:GetAuthorizationToken + Effect: Allow + Resource: '*' + Version: '2012-10-17' + PolicyName: TaskDefinitionExecutionRoleDefaultPolicy + Roles: + - !Ref TaskDefinitionExecutionRole + Service: + Type: AWS::ECS::Service + Properties: + Cluster: !Ref Cluster + DeploymentConfiguration: + MaximumPercent: 200 + MinimumHealthyPercent: 50 + EnableECSManagedTags: false + LaunchType: FARGATE + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: ENABLED + SecurityGroups: + - !GetAtt ServiceSecurityGroup.GroupId + Subnets: + - !Ref PublicSubnet1 + ServiceName: + Fn::Join: + - '-' + - - SimpleDockerEcsService + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + TaskDefinition: !Ref TaskDefinition + DependsOn: + - TaskDefinitionTaskRole + ServiceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: !Sub + - ${clusterName}/${serviceName}/SecurityGroup + - clusterName: + Fn::Join: + - '-' + - - SimpleDockerEcsCluster + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + serviceName: + Fn::Join: + - '-' + - - SimpleDockerEcsService + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + + SecurityGroupEgress: + - CidrIp: 0.0.0.0/0 + Description: Allow all outbound traffic by default + IpProtocol: '-1' + SecurityGroupIngress: + - CidrIp: 0.0.0.0/0 + Description: !Sub Incoming Web Server connection on port ${ContainerPort}. + FromPort: !Ref ContainerPort + IpProtocol: tcp + ToPort: !Ref ContainerPort + VpcId: !Ref Vpc + DependsOn: + - TaskDefinitionTaskRole + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - /* + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - /* + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodePipelineBuildActionRole.Arn + - !GetAtt CodePipelineDeployActionRole.Arn + - !GetAtt CodePipelineSourceActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineRoleDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Actions: + - ActionTypeId: + Category: Source + Owner: AWS + Provider: ECR + Version: '1' + Configuration: + RepositoryName: !Ref RepositoryName + Name: !Sub ${RepositoryName}-${ImageTag} + OutputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodePipelineSourceActionRole.Arn + RunOrder: 1 + Name: Source + - Actions: + - ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + ProjectName: !Ref CodeBuildProject + InputArtifacts: + - Name: SourceOutput + Name: Build + OutputArtifacts: + - Name: BuildOutput + RoleArn: !GetAtt CodePipelineBuildActionRole.Arn + RunOrder: 1 + Name: Build + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyBuildDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + - Actions: + - ActionTypeId: + Category: Deploy + Owner: AWS + Provider: ECS + Version: '1' + Configuration: + ClusterName: !Ref Cluster + ServiceName: !GetAtt Service.Name + FileName: imagedefinitions.json + InputArtifacts: + - Name: BuildOutput + Name: Deploy + RoleArn: !GetAtt CodePipelineDeployActionRole.Arn + RunOrder: 1 + Name: Deploy + OnFailure: + Result: ROLLBACK + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeployDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + DependsOn: + - CodePipelineRoleDefaultPolicy + CodePipelineSourceActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodePipelineSourceActionRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: ecr:DescribeImages + Effect: Allow + Resource: !Sub arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/${RepositoryName} + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - /* + Version: '2012-10-17' + PolicyName: CodePipelineSourceActionRoleDefaultPolicy + Roles: + - !Ref CodePipelineSourceActionRole + CodePipelineSourceEventRule: + Type: AWS::Events::Rule + Properties: + EventPattern: + detail-type: + - ECR Image Action + source: + - aws.ecr + detail: + result: + - SUCCESS + repository-name: + - !Ref RepositoryName + image-tag: + - !Ref ImageTag + action-type: + - PUSH + State: ENABLED + Targets: + - Arn: !Join + - '' + - - !Sub 'arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:' + - !Ref CodePipeline + Id: Target0 + RoleArn: !GetAtt SourceEventsRole.Arn + SourceEventsRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: events.amazonaws.com + Version: '2012-10-17' + SourceEventsRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codepipeline:StartPipelineExecution + Effect: Allow + Resource: !Join + - '' + - - !Sub 'arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:' + - !Ref CodePipeline + Version: '2012-10-17' + PolicyName: SourceEventsRoleDefaultPolicy + Roles: + - !Ref SourceEventsRole + CodePipelineBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodePipelineBuildActionRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodePipelineBuildActionRoleDefaultPolicy + Roles: + - !Ref CodePipelineBuildActionRole + CodePipelineDeployActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodePipelineDeployActionRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - ecs:DescribeServices + - ecs:DescribeTaskDefinition + - ecs:DescribeTasks + - ecs:ListTasks + - ecs:RegisterTaskDefinition + - ecs:TagResource + - ecs:UpdateService + Effect: Allow + Resource: '*' + - Action: iam:PassRole + Condition: + StringEqualsIfExists: + iam:PassedToService: + - ec2.amazonaws.com + - ecs-tasks.amazonaws.com + Effect: Allow + Resource: '*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - '' + - - !GetAtt CodePipelineArtifactsBucket.Arn + - /* + Version: '2012-10-17' + PolicyName: CodePipelineDeployActionRoleDefaultPolicy + Roles: + - !Ref CodePipelineDeployActionRole \ No newline at end of file diff --git a/templates/cloudformation/test-on-reflect.yaml b/templates/cloudformation/test-on-reflect.yaml new file mode 100644 index 0000000..6c4d976 --- /dev/null +++ b/templates/cloudformation/test-on-reflect.yaml @@ -0,0 +1,581 @@ +Parameters: + ConnectionArn: + Description: The CodeConnections ARN for your source repository. + Type: String + FullRepositoryId: + Description: The full repository ID to use with your CodeConnections connection. + Type: String + BranchName: + Description: The branch name to use with your CodeConnections connection. + Type: String + CodePipelineName: + Description: The CodePipeline pipeline name that will run your Reflect tests. + Type: String + Default: SimpleTestOnReflect + ReflectAPIKeySecretArn: + Description: The ARN of the AWS Secrets Manager secret containing the API key for your Reflect account. + Type: String + ReflectAPIKeySecretJsonKeyName: + Description: The JSON key name within the AWS Secrets Manager secret that holds the value for your Reflect account API key. + Type: String + ReflectSuiteId: + Description: The ID of your Reflect test suite. + Type: String + ReflectWaitForTestResults: + Description: Waits for the Reflect test suite to complete and set the CodePipeline action status based on the test results. + Type: String + Default: 'true' + AllowedValues: + - 'true' + - 'false' + CICodeBuildSpec: + Description: The CodeBuild build specification running your Reflect tests. + Type: String + Default: | + version: 0.2 + + env: + exported-variables: + - REFLECT_TEST_SUITE_URL + + phases: + install: + commands: + - echo "Setting default values for parameters if not provided..." + - | + if [ -z "$PARAM_VARIABLES" ]; then + PARAM_VARIABLES="{}" + fi + + if [ -z "$PARAM_OVERRIDES" ]; then + PARAM_OVERRIDES="{}" + fi + + if [ -z "$PARAM_GITHUB" ]; then + if [ "$SOURCE_VARIABLE_PROVIDER_TYPE" = "GitHub" ]; then + echo "Constructing PARAM_GITHUB based on the CodePipeline source action information..." + REPO_OWNER=$(echo "$SOURCE_VARIABLE_FULL_REPO_NAME" | cut -d'/' -f1) + REPO_NAME=$(echo "$SOURCE_VARIABLE_FULL_REPO_NAME" | cut -d'/' -f2) + PARAM_GITHUB=$(jq -n --arg owner "$REPO_OWNER" --arg repo "$REPO_NAME" --arg sha "$SOURCE_VARIABLE_COMMIT_ID" '{"gitHub": {"owner": $owner, "repo": $repo, "sha": $sha}}') + else + PARAM_GITHUB="{}" + fi + fi + + EXECUTE_SUITE_REQUEST_BODY=$(jq -n \ + --argjson variables "$PARAM_VARIABLES" \ + --argjson overrides "$PARAM_OVERRIDES" \ + --argjson github "$PARAM_GITHUB" \ + '{variables: $variables, overrides: $overrides, gitHub: $github}') + echo "Request body for executing Reflect test suite $EXECUTE_SUITE_REQUEST_BODY" + build: + commands: + - export KEY_HEADER="X-API-KEY:${API_KEY}" + - EXECUTION_RESPONSE=$(curl -X POST -H "$KEY_HEADER" -d "{}" -s "https://api.reflect.run/v1/suites/$SUITE_ID/executions") + - REFLECT_TEST_SUITE_URL=$(echo $EXECUTION_RESPONSE | jq -r '.url') + - | + if [ "$REFLECT_TEST_SUITE_URL" == "null" ]; then + echo "Error: Invalid response. $EXECUTION_RESPONSE" + exit 1 + else + echo "Successfully invoked Reflect test suite. Visit the following URL to view the results:$REFLECT_TEST_SUITE_URL" + fi + - | + EXECUTION_ID=$(echo $EXECUTION_RESPONSE | jq -r '.executionId') + + if [ "$WAIT_FOR_TEST_RESULTS" = "true" ]; then + while true; do + EXECUTION_STATUS=$(curl -H $KEY_HEADER -s "https://api.reflect.run/v1/suites/$SUITE_ID/executions/$EXECUTION_ID" | jq -r '.isFinished') + if [ "$EXECUTION_STATUS" = "true" ]; then + FINAL_STATUS=$(curl -H $KEY_HEADER -s "https://api.reflect.run/v1/suites/$SUITE_ID/executions/$EXECUTION_ID" | jq -r '.status') + if [ "$FINAL_STATUS" = "passed" ]; then + echo "Tests passed successfully." + exit 0 + else + echo "Tests failed with status: $FINAL_STATUS" + exit 1 + fi + fi + sleep 10 + done + else + echo "Skipping waiting for test results." + fi + RetentionPolicy: + Description: Define if you'd like the resource retained or deleted when the + CloudFormation stack is deleted. + Type: String + Default: Delete + AllowedValues: + - Delete + - Retain + ReflectParamOverride: + Description: An optional JSON blob containing overrides for this suite execution. + Type: String + Default: '' + ReflectParamVariables: + Description: An optional JSON blob containing modified variable values for this suite execution. + Type: String + Default: '' + ReflectParamGitHub: + Description: An optional JSON blob specifying the GitHub repository name, its owner, and commit SHA to post the status. + Type: String + Default: '' + +Conditions: + HasReflectParamOverride: !Not [!Equals ['', !Ref ReflectParamOverride]] + HasReflectParamVariables: !Not [!Equals ['', !Ref ReflectParamVariables]] + HasReflectParamGitHub: !Not [!Equals ['', !Ref ReflectParamGitHub]] + +Resources: + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Version: '2012-10-17' + Policies: + - PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName} + - projectName: + Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - !Sub + - arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${projectName}:* + - projectName: + Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Sub + - arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${projectName}-* + - projectName: + Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Sub + - ${arn}/* + - arn: !GetAtt CodePipelineArtifactsBucket.Arn + Version: '2012-10-17' + PolicyName: CodeBuildProjectRoleDefaultPolicy + CodeBuildDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - ':*' + - !Join + - '' + - - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/ + - Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - Action: + - codebuild:BatchPutCodeCoverages + - codebuild:BatchPutTestCases + - codebuild:CreateReport + - codebuild:CreateReportGroup + - codebuild:UpdateReport + Effect: Allow + Resource: !Join + - '' + - - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/ + - Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + - '-*' + - Action: + - s3:GetBucket* + - s3:GetObject* + - s3:List* + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - secretsmanager:GetSecretValue + Effect: Allow + Resource: + - !Ref ReflectAPIKeySecretArn + Version: '2012-10-17' + PolicyName: CodeBuildDefaultPolicy + Roles: + - !Ref CodeBuildRole + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + Cache: + Type: NO_CACHE + Description: Invoke tests on Reflect + EncryptionKey: alias/aws/s3 + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 + ImagePullCredentialsType: CODEBUILD + PrivilegedMode: false + Type: LINUX_CONTAINER + EnvironmentVariables: + - Name: API_KEY + Type: SECRETS_MANAGER + Value: !Join + - ':' + - - !Ref ReflectAPIKeySecretArn + - !Ref ReflectAPIKeySecretJsonKeyName + - Name: SUITE_ID + Type: PLAINTEXT + Value: !Ref ReflectSuiteId + - Name: WAIT_FOR_TEST_RESULTS + Type: PLAINTEXT + Value: !Ref ReflectWaitForTestResults + - Fn::If: + - HasReflectParamOverride + - Name: PARAM_OVERRIDES + Type: PLAINTEXT + Value: !Ref ReflectParamOverride + - Ref: AWS::NoValue + - Fn::If: + - HasReflectParamVariables + - Name: PARAM_VARIABLES + Type: PLAINTEXT + Value: !Ref ReflectParamVariables + - Ref: AWS::NoValue + - Fn::If: + - HasReflectParamGitHub + - Name: PARAM_GITHUB + Type: PLAINTEXT + Value: !Ref ReflectParamGitHub + - Ref: AWS::NoValue + Name: + Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + ServiceRole: !GetAtt CodeBuildRole.Arn + Source: + BuildSpec: !Ref CICodeBuildSpec + Type: NO_SOURCE + CodePipelineArtifactsBucket: + Type: AWS::S3::Bucket + Properties: + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + UpdateReplacePolicy: !Ref RetentionPolicy + DeletionPolicy: !Ref RetentionPolicy + CodePipelineArtifactsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CodePipelineArtifactsBucket + PolicyDocument: + Statement: + - Action: s3:* + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: + AWS: '*' + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + CodePipelineRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: codepipeline.amazonaws.com + Version: '2012-10-17' + CodePipelineDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: sts:AssumeRole + Effect: Allow + Resource: + - !GetAtt CodeBuildActionRole.Arn + - !GetAtt CodeConnectionsActionRole.Arn + Version: '2012-10-17' + PolicyName: CodePipelineDefaultPolicy + Roles: + - !Ref CodePipelineRole + CodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref CodePipelineArtifactsBucket + Type: S3 + ExecutionMode: QUEUED + Name: !Ref CodePipelineName + PipelineType: V2 + RoleArn: !GetAtt CodePipelineRole.Arn + Stages: + - Name: Source + Actions: + - Name: CodeConnections + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeStarSourceConnection + Version: '1' + Configuration: + ConnectionArn: !Ref ConnectionArn + FullRepositoryId: !Ref FullRepositoryId + BranchName: !Ref BranchName + OutputArtifacts: + - Name: SourceOutput + Namespace: SourceVariables + RoleArn: !GetAtt CodeConnectionsActionRole.Arn + RunOrder: 1 + - Name: TestOnReflect + BeforeEntry: + Conditions: + - Result: FAIL + Rules: + - Name: MyDeploymentWindowRule + RuleTypeId: + Category: Rule + Owner: AWS + Provider: DeploymentWindow + Version: '1' + Configuration: + Cron: '* * * * * ? *' + TimeZone: 'PST' + Actions: + - Name: Test_On_Reflect + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + Configuration: + EnvironmentVariables: >- + [{"name":"SOURCE_VARIABLE_PROVIDER_TYPE","value":"#{SourceVariables.ProviderType}","type":"PLAINTEXT"},{"name":"SOURCE_VARIABLE_FULL_REPO_NAME","value":"#{SourceVariables.FullRepositoryName}","type":"PLAINTEXT"},{"name":"SOURCE_VARIABLE_COMMIT_ID","value":"#{SourceVariables.CommitId}","type":"PLAINTEXT"}] + ProjectName: + Fn::Join: + - '-' + - - TestOnReflectProject + - Fn::Select: + - 4 + - Fn::Split: + - '-' + - Fn::Select: + - 2 + - Fn::Split: + - / + - Ref: AWS::StackId + InputArtifacts: + - Name: SourceOutput + RoleArn: !GetAtt CodeBuildActionRole.Arn + RunOrder: 1 + DependsOn: + - CodePipelineDefaultPolicy + CodeConnectionsActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeConnectionsActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: codestar-connections:UseConnection + Effect: Allow + Resource: !Ref ConnectionArn + - Action: + - s3:Abort* + - s3:DeleteObject* + - s3:GetBucket* + - s3:GetObject* + - s3:List* + - s3:PutObject + - s3:PutObjectLegalHold + - s3:PutObjectRetention + - s3:PutObjectTagging + - s3:PutObjectVersionTagging + Effect: Allow + Resource: + - !GetAtt CodePipelineArtifactsBucket.Arn + - !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + - Action: + - s3:PutObjectAcl + - s3:PutObjectVersionAcl + Effect: Allow + Resource: !Join + - / + - - !GetAtt CodePipelineArtifactsBucket.Arn + - '*' + Version: '2012-10-17' + PolicyName: CodeConnectionsActionDefaultPolicy + Roles: + - !Ref CodeConnectionsActionRole + CodeBuildActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Version: '2012-10-17' + CodeBuildActionDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + - codebuild:StopBuild + Effect: Allow + Resource: !GetAtt CodeBuildProject.Arn + Version: '2012-10-17' + PolicyName: CodeBuildActionDefaultPolicy + Roles: + - !Ref CodeBuildActionRole \ No newline at end of file diff --git a/templates/metadata/README.md b/templates/metadata/README.md new file mode 100644 index 0000000..c943e60 --- /dev/null +++ b/templates/metadata/README.md @@ -0,0 +1,17 @@ +# Templates Metadata + +This folder contains metadata that control how templates will be rendered in the template category on the CodePipeline console. + +## Schema + +1. **id**: A unique identifier for the template (string). +2. **name**: The display name of the template (string). +3. **description**: A brief description of what the template does (string). +4. **category**: The category under which the template will be displayed (string). +5. **badge**: An optional badge to highlight the template's status. Possible values are "Coming Soon", "New", "Default", and "Popular" (string). +6. **icon-name**: The name of the icon to be displayed with the template (string). +7. **tags**: An array of strings that can be used for filtering or searching templates. +8. **template-location**: The relative path to the CloudFormation template file (string). +9. **ui-hints-location**: The relative path to the UI hints file for this template (string). + +For more information, see the `schema.json` file in this directory. \ No newline at end of file diff --git a/templates/metadata/ci-build-gradle.json b/templates/metadata/ci-build-gradle.json new file mode 100644 index 0000000..6e3ff5b --- /dev/null +++ b/templates/metadata/ci-build-gradle.json @@ -0,0 +1,11 @@ +{ + "id": "ciBuildGradle", + "name": "CI Build Gradle", + "description": "Build a gradle project", + "category": "Continuous Integration", + "badge": "New", + "icon-name": "gradle", + "tags": ["gradle", "codebuild"], + "template-location": "./cloudformation/ci-build-gradle.yaml", + "ui-hints-location": "./ui-hints/ci-build-gradle.json" +} diff --git a/templates/metadata/ci-build-maven.json b/templates/metadata/ci-build-maven.json new file mode 100644 index 0000000..dcd3fb6 --- /dev/null +++ b/templates/metadata/ci-build-maven.json @@ -0,0 +1,11 @@ +{ + "id": "ciBuildMaven", + "name": "CI Build Maven", + "description": "Build a maven project", + "category": "Continuous Integration", + "badge": "New", + "icon-name": "maven", + "tags": ["maven", "codebuild"], + "template-location": "./cloudformation/ci-build-maven.yaml", + "ui-hints-location": "./ui-hints/ci-build-maven.json" +} diff --git a/templates/metadata/ci-build-nodejs.json b/templates/metadata/ci-build-nodejs.json new file mode 100644 index 0000000..470f69f --- /dev/null +++ b/templates/metadata/ci-build-nodejs.json @@ -0,0 +1,11 @@ +{ + "id": "ciBuildNodeJS", + "name": "CI Build NodeJS", + "description": "Build a node js project", + "category": "Continuous Integration", + "badge": "New", + "icon-name": "nodejs", + "tags": ["nodejs", "codebuild"], + "template-location": "./cloudformation/ci-build-nodejs.yaml", + "ui-hints-location": "./ui-hints/ci-build-nodejs.json" +} diff --git a/templates/metadata/ci-build-python.json b/templates/metadata/ci-build-python.json new file mode 100644 index 0000000..ebbfd26 --- /dev/null +++ b/templates/metadata/ci-build-python.json @@ -0,0 +1,11 @@ +{ + "id": "ciBuildPython", + "name": "CI Build Python", + "description": "Build a python project", + "category": "Continuous Integration", + "badge": "New", + "icon-name": "python", + "tags": ["python", "codebuild"], + "template-location": "./cloudformation/ci-build-python.yaml", + "ui-hints-location": "./ui-hints/ci-build-python.json" +} diff --git a/templates/metadata/ci-schedule-build-gradle.json b/templates/metadata/ci-schedule-build-gradle.json new file mode 100644 index 0000000..d80cd1c --- /dev/null +++ b/templates/metadata/ci-schedule-build-gradle.json @@ -0,0 +1,11 @@ +{ + "id": "ciScheduleBuildGradle", + "name": "Schedule a gradle build pipeline", + "description": "Build a gradle project periodically", + "category": "Automation", + "badge": "New", + "icon-name": "gradle", + "tags": ["gradle", "codebuild", "schedule"], + "template-location": "./cloudformation/ci-schedule-build-gradle.yaml", + "ui-hints-location": "./ui-hints/ci-schedule-build-gradle.json" +} \ No newline at end of file diff --git a/templates/metadata/ci-schedule-build-maven.json b/templates/metadata/ci-schedule-build-maven.json new file mode 100644 index 0000000..ff9753b --- /dev/null +++ b/templates/metadata/ci-schedule-build-maven.json @@ -0,0 +1,11 @@ +{ + "id": "ciScheduleBuildMaven", + "name": "Schedule a maven build pipeline", + "description": "Build a maven project periodically", + "category": "Automation", + "badge": "New", + "icon-name": "maven", + "tags": ["maven", "codebuild", "schedule"], + "template-location": "./cloudformation/ci-schedule-build-maven.yaml", + "ui-hints-location": "./ui-hints/ci-schedule-build-maven.json" +} \ No newline at end of file diff --git a/templates/metadata/ci-schedule-build-nodejs.json b/templates/metadata/ci-schedule-build-nodejs.json new file mode 100644 index 0000000..adefdeb --- /dev/null +++ b/templates/metadata/ci-schedule-build-nodejs.json @@ -0,0 +1,11 @@ +{ + "id": "ciScheduleBuildNodeJS", + "name": "Schedule a nodejs build pipeline", + "description": "Build a nodejs project periodically", + "category": "Automation", + "badge": "New", + "icon-name": "nodejs", + "tags": ["nodejs", "codebuild", "schedule"], + "template-location": "./cloudformation/ci-schedule-build-nodejs.yaml", + "ui-hints-location": "./ui-hints/ci-schedule-build-nodejs.json" +} diff --git a/templates/metadata/ci-schedule-build-python.json b/templates/metadata/ci-schedule-build-python.json new file mode 100644 index 0000000..87b3549 --- /dev/null +++ b/templates/metadata/ci-schedule-build-python.json @@ -0,0 +1,11 @@ +{ + "id": "ciScheduleBuildPython", + "name": "Schedule a python build pipeline", + "description": "Build a python project periodically", + "category": "Automation", + "badge": "New", + "icon-name": "python", + "tags": ["python", "codebuild", "schedule"], + "template-location": "./cloudformation/ci-schedule-build-python.yaml", + "ui-hints-location": "./ui-hints/ci-schedule-build-python.json" +} diff --git a/templates/metadata/deploy-to-cfn.json b/templates/metadata/deploy-to-cfn.json new file mode 100644 index 0000000..b6d83a1 --- /dev/null +++ b/templates/metadata/deploy-to-cfn.json @@ -0,0 +1,11 @@ +{ + "id": "deployToCfn", + "name": "Deploy to CloudFormation", + "description": "Deploy your cloud formation template", + "category": "Deployment", + "badge": "Default", + "icon-name": "cloudformation", + "tags": ["cloudformation", "cf"], + "template-location": "./cloudformation/deploy-to-cfn.yaml", + "ui-hints-location": "./ui-hints/deploy-to-cfn.json" +} diff --git a/templates/metadata/deploy-to-ecr.json b/templates/metadata/deploy-to-ecr.json new file mode 100644 index 0000000..4873544 --- /dev/null +++ b/templates/metadata/deploy-to-ecr.json @@ -0,0 +1,11 @@ +{ + "id": "deployToEcr", + "name": "Push to ECR", + "description": "Build and push a new container image to Amazon ECR", + "category": "Deployment", + "badge": "New", + "icon-name": "ecr", + "tags": ["ecr"], + "template-location": "./cloudformation/deploy-to-ecr.yaml", + "ui-hints-location": "./ui-hints/deploy-to-ecr.json" +} diff --git a/templates/metadata/deploy-to-ecs-fargate.json b/templates/metadata/deploy-to-ecs-fargate.json new file mode 100644 index 0000000..6170bf3 --- /dev/null +++ b/templates/metadata/deploy-to-ecs-fargate.json @@ -0,0 +1,11 @@ +{ + "id": "deployToEcsFargate", + "name": "Deploy to ECS Fargate", + "description": "Deploy a ECR image to Amazon ECS Fargate cluster", + "category": "Deployment", + "badge": "New", + "icon-name": "ecs", + "tags": ["ecr", "ecs", "fargate"], + "template-location": "./cloudformation/deploy-to-ecs-fargate.yaml", + "ui-hints-location": "./ui-hints/deploy-to-ecs-fargate.json" +} diff --git a/templates/metadata/schema.json b/templates/metadata/schema.json new file mode 100644 index 0000000..851a522 --- /dev/null +++ b/templates/metadata/schema.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "category": { + "type": "string", + "enum": ["Deployment", "release", "Automation", "Continuous Integration"] + }, + "description": { + "type": "string" + }, + "badge": { + "type": "string", + "enum": ["Coming Soon", "New", "Default", "Popular"] + }, + "icon-name": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "template-location": { + "type": "string" + }, + "ui-hints-location": { + "type": "string" + } + }, + "required": ["id", "name", "description", "icon-name", "tags", "template-location", "ui-hints-location"] +} diff --git a/templates/metadata/test-on-reflect.json b/templates/metadata/test-on-reflect.json new file mode 100644 index 0000000..194397e --- /dev/null +++ b/templates/metadata/test-on-reflect.json @@ -0,0 +1,11 @@ +{ + "id": "testOnReflect", + "name": "Run Reflect Test", + "description": "Run tests on Reflect", + "category": "Continuous Integration", + "badge": "New", + "icon-name": "reflect", + "tags": ["ui-test", "reflect", "reflect"], + "template-location": "./cloudformation/test-on-reflect.yaml", + "ui-hints-location": "./ui-hints/test-on-reflect.json" +} diff --git a/templates/ui-hints/README.md b/templates/ui-hints/README.md new file mode 100644 index 0000000..cbbfc4d --- /dev/null +++ b/templates/ui-hints/README.md @@ -0,0 +1,15 @@ +# UI Hints + +This folder contains JSON files that control how the template configuration step will be rendered on the CodePipeline console. + +## Schema + +1. **supported-source-filters**: helps filter down the source providers available for a template. When unsure, use `"owner": ["CodeStarConnection"]`. + +2. **constraints**: helps the CodePipeline console validate the input fields. + +3. **placeholders**: provides placeholder text to be rendered in CodePipeline input fields. + +4. **text-editor-styles**: Defines the rendering styles for input fields that should be displayed as text editors in the CodePipeline console. + +For detailed information on the schema and how to use these UI hint files, please refer to the `schema.json` file in this directory. \ No newline at end of file diff --git a/templates/ui-hints/ci-build-gradle.json b/templates/ui-hints/ci-build-gradle.json new file mode 100644 index 0000000..0981243 --- /dev/null +++ b/templates/ui-hints/ci-build-gradle.json @@ -0,0 +1,36 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + } +} diff --git a/templates/ui-hints/ci-build-maven.json b/templates/ui-hints/ci-build-maven.json new file mode 100644 index 0000000..bb17dc8 --- /dev/null +++ b/templates/ui-hints/ci-build-maven.json @@ -0,0 +1,43 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/ci-build-nodejs.json b/templates/ui-hints/ci-build-nodejs.json new file mode 100644 index 0000000..bb17dc8 --- /dev/null +++ b/templates/ui-hints/ci-build-nodejs.json @@ -0,0 +1,43 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/ci-build-python.json b/templates/ui-hints/ci-build-python.json new file mode 100644 index 0000000..bb17dc8 --- /dev/null +++ b/templates/ui-hints/ci-build-python.json @@ -0,0 +1,43 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/ci-schedule-build-gradle.json b/templates/ui-hints/ci-schedule-build-gradle.json new file mode 100644 index 0000000..3ff4c4f --- /dev/null +++ b/templates/ui-hints/ci-schedule-build-gradle.json @@ -0,0 +1,53 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "ScheduleExpression": { + "Required": true, + "MinLength": 1, + "MaxLength": 256 + }, + "ScheduleExpressionTimezone": { + "Required": true, + "MinLength": 1, + "MaxLength": 50 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/ci-schedule-build-maven.json b/templates/ui-hints/ci-schedule-build-maven.json new file mode 100644 index 0000000..3ff4c4f --- /dev/null +++ b/templates/ui-hints/ci-schedule-build-maven.json @@ -0,0 +1,53 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "ScheduleExpression": { + "Required": true, + "MinLength": 1, + "MaxLength": 256 + }, + "ScheduleExpressionTimezone": { + "Required": true, + "MinLength": 1, + "MaxLength": 50 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/ci-schedule-build-nodejs.json b/templates/ui-hints/ci-schedule-build-nodejs.json new file mode 100644 index 0000000..3ff4c4f --- /dev/null +++ b/templates/ui-hints/ci-schedule-build-nodejs.json @@ -0,0 +1,53 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "ScheduleExpression": { + "Required": true, + "MinLength": 1, + "MaxLength": 256 + }, + "ScheduleExpressionTimezone": { + "Required": true, + "MinLength": 1, + "MaxLength": 50 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/ci-schedule-build-python.json b/templates/ui-hints/ci-schedule-build-python.json new file mode 100644 index 0000000..3ff4c4f --- /dev/null +++ b/templates/ui-hints/ci-schedule-build-python.json @@ -0,0 +1,53 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "ScheduleExpression": { + "Required": true, + "MinLength": 1, + "MaxLength": 256 + }, + "ScheduleExpressionTimezone": { + "Required": true, + "MinLength": 1, + "MaxLength": 50 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/deploy-to-cfn.json b/templates/ui-hints/deploy-to-cfn.json new file mode 100644 index 0000000..7e3d802 --- /dev/null +++ b/templates/ui-hints/deploy-to-cfn.json @@ -0,0 +1,70 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "StackName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "TemplatePath": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "TemplateConfiguration": { + "MinLength": 1, + "MaxLength": 255 + }, + "ParameterOverrides": { + "MinLength": 1, + "MaxLength": 255 + }, + "OutputFileName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CloudFormationResourcePermissions": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + }, + "placeholders": { + "TemplatePath": "template.yaml", + "CloudFormationResourcePermissions": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n { \n \"Sid\": \"PermissionsForCloudFormation\",\n \"Effect\": \"Allow\",\n \"Action\": \"*\",\n \"Resource\": \"*\"\n }\n ]\n}\n" + }, + "text-editor-styles": { + "CloudFormationResourcePermissions": { + "mode": "json", + "minLines": 11, + "maxLines": 22 + } + } +} diff --git a/templates/ui-hints/deploy-to-ecr.json b/templates/ui-hints/deploy-to-ecr.json new file mode 100644 index 0000000..7da5b09 --- /dev/null +++ b/templates/ui-hints/deploy-to-ecr.json @@ -0,0 +1,47 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "DockerBuildContext": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "DockerFilePath": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "ImageTag": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + } +} diff --git a/templates/ui-hints/deploy-to-ecs-fargate.json b/templates/ui-hints/deploy-to-ecs-fargate.json new file mode 100644 index 0000000..0919226 --- /dev/null +++ b/templates/ui-hints/deploy-to-ecs-fargate.json @@ -0,0 +1,31 @@ +{ + "supported-source-filters": { + "provider": ["ECR"] + }, + "constraints": { + "RepositoryName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "ImageTag": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "ContainerPort": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + } + } +} diff --git a/templates/ui-hints/schema.json b/templates/ui-hints/schema.json new file mode 100644 index 0000000..64caa9d --- /dev/null +++ b/templates/ui-hints/schema.json @@ -0,0 +1,70 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "supported-source-filters": { + "type": "object", + "patternProperties": { + "^(owner|provider)$": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "constraints": { + "type": "object", + "patternProperties": { + "^.*$": { + "type": "object", + "properties": { + "Required": { + "type": "boolean" + }, + "Arn": { + "type": "boolean" + }, + "MinLength": { + "type": "number" + }, + "MaxLength": { + "type": "number" + }, + "Contains": { + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "placeholders": { + "type": "object" + }, + "text-editor-styles": { + "type": "object", + "patternProperties": { + "^.*$": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": ["yaml", "json"] + }, + "minLines": { + "type": "integer" + }, + "maxLines": { + "type": "integer" + } + }, + "required": ["mode", "minLines", "maxLines"], + "additionalProperties": false + } + } + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/templates/ui-hints/test-on-reflect.json b/templates/ui-hints/test-on-reflect.json new file mode 100644 index 0000000..f8b1af9 --- /dev/null +++ b/templates/ui-hints/test-on-reflect.json @@ -0,0 +1,94 @@ +{ + "supported-source-filters": { + "owner": ["CodeStarConnection"] + }, + "constraints": { + "ConnectionArn": { + "Required": true, + "Arn": true + }, + "FullRepositoryId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255, + "Contains": "/" + }, + "BranchName": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CodePipelineName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "ReflectAPIKeySecretArn": { + "Required": true, + "Arn": true + }, + "ReflectAPIKeySecretJsonKeyName": { + "Required": true, + "MinLength": 1, + "MaxLength": 100 + }, + "ReflectSuiteId": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "ReflectWaitForTestResults": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "CICodeBuildSpec": { + "Required": true, + "MinLength": 1 + }, + "RetentionPolicy": { + "Required": true, + "MinLength": 1, + "MaxLength": 255 + }, + "ReflectParamOverride": { + "MinLength": 1, + "MaxLength": 1000 + }, + "ReflectParamVariables": { + "MinLength": 1, + "MaxLength": 1000 + }, + "ReflectParamGitHub": { + "MinLength": 1, + "MaxLength": 255 + } + }, + "placeholders": { + "ReflectParamOverride": "{\n \"hostnames\": [{\n \"original\": \"prod.myapp.com\",\n \"replacement\": \"staging.myapp.com\"\n }],\n \"cookies\": [{\n \"name\": \"my-favorite-cookie\",\n \"value\": \"chocolate-chip\",\n \"domain\": \"myapp.com\",\n \"expires\": 123456789,\n \"httpOnly\": false,\n \"maxAge\": 123,\n \"path\": \"/\",\n \"secure\": true\n }],\n \"headers\": [{\n \"name\": \"X-Custom-Header\",\n \"value\": \"custom-value\",\n \"persist\": false\n }],\n \"localStorage\": [{\n \"key\": \"my-local-key\",\n \"value\": \"local-value\"\n }],\n \"sessionStorage\": [{\n \"key\": \"my-session-key\",\n \"value\": \"session-value\"\n }]\n}", + "ReflectParamVariables": "{\n \"username1\": \"user+${alpha(8)}@example.com\",\n \"password\": \"acompletelyunguessablepassword\"\n}", + "ReflectParamGitHub": "{\n \"owner\": \"repository-owner\",\n \"repo\": \"my-repository-name\",\n \"sha\": \"0f4212320f2cb6734583ebef3a4928d78d4f3fde\"\n}" + }, + "text-editor-styles": { + "CICodeBuildSpec": { + "mode": "yaml", + "minLines": 1, + "maxLines": 22 + }, + "ReflectParamOverride": { + "mode": "json", + "minLines": 29, + "maxLines": 29 + }, + "ReflectParamVariables": { + "mode": "json", + "minLines": 4, + "maxLines": 22 + }, + "ReflectParamGitHub": { + "mode": "json", + "minLines": 5, + "maxLines": 22 + } + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..598e263 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "declaration": true, + "outDir": "./dist", + "sourceMap": true, + "declarationMap": true + }, + "include": ["src"], + "exclude": ["build","node_modules", "dist"] +} \ No newline at end of file From 1420699299f81708dbc7fcc065ead48393547cfd Mon Sep 17 00:00:00 2001 From: Yong Tao Date: Wed, 6 Nov 2024 12:55:59 -0800 Subject: [PATCH 2/3] Add validation workflow --- .github/workflows/validate-templates.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/validate-templates.yaml diff --git a/.github/workflows/validate-templates.yaml b/.github/workflows/validate-templates.yaml new file mode 100644 index 0000000..8079ec7 --- /dev/null +++ b/.github/workflows/validate-templates.yaml @@ -0,0 +1,21 @@ +name: Validate Templates + +on: [pull_request, push] + +jobs: + validate-templates: + permissions: + contents: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - run: npm ci + - run: npm run test + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + - run: pip install -U cfn-lint + - run: cfn-lint templates/cloudformation/* --non-zero-exit-code warning \ No newline at end of file From 2c3368cb61bcd92bf9050218c7577685a2dccc32 Mon Sep 17 00:00:00 2001 From: Yong Tao Date: Wed, 6 Nov 2024 12:55:59 -0800 Subject: [PATCH 3/3] Add validation workflow --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c6af0af..5bde7db 100644 --- a/README.md +++ b/README.md @@ -17,22 +17,15 @@ This project uses Node.js for development tasks. To set up the development envir 1. Ensure you have Node.js 18 or later installed 2. Run `npm install` to install dependencies -3. Use the provided npm scripts for various tasks: - - `npm run clean`: Remove generated files and directories - - `npm run test`: Run all validation and merging scripts - - `npm run validate-schemas`: Validate JSON schemas - - `npm run merge-cloudformation-templates`: Merge CloudFormation templates ### Adding new templates - + To add a new template, follow these steps: - + 1. Create a new metadata file for the template in the `/templates/metadata` folder. This file should conform to the schema defined in `/templates/metadata/schema.json`. - 2. Add the corresponding CloudFormation template file in the `/templates/cloudformation` folder. - 3. The build script will automatically validate the metadata and CloudFormation template files, and generate the synthesized files for the CodePipeline Console to render. - + ### Adding new icons You are not required to add a new icon for your template. You can use the existing `codepipeline.svg` icon located in the `assets/icons/` folder. @@ -42,6 +35,20 @@ If you want to add a new icon to this package, 2. The icon-name in the metadata should correspond to the relevant folder, for example, `icon-name: lambda` expects an icon file at `asset/icons/lambda.svg`. +### Testing your changes + +Our [template validation workflow](.github/workflows/validate-templates.yaml) involves JSON schema validation using npm and CloudFormation linting using [cfn-lint](https://github.com/aws-cloudformation/cfn-lint). To test your changes locally: + +1. Ensure you have npm and cfn-lint installed on your system. +2. Run the following command to validate the JSON files: + ``` + npm run test + ``` +3. Run the following command to validate the CloudFormation files: + ``` + cfn-lint templates/cloudformation/* + ``` + ## Contributing We welcome contributions to this project. Please read our [Contributing Guidelines](CONTRIBUTING.md) for more information on how to add new templates or improve existing ones.