├── test ├── .gitignore ├── cdk8s.yaml └── cdktf-cdk8s.test.ts ├── .prettierrc.json ├── examples └── typescript │ ├── complex │ ├── .npmrc │ ├── setup.js │ ├── .gitignore │ ├── cdktf.json │ ├── package.json │ ├── help │ ├── __tests__ │ │ └── main-test.ts │ ├── main.ts │ └── jest.config.js │ └── hello-world │ ├── .npmrc │ ├── setup.js │ ├── .gitignore │ ├── cdktf.json │ ├── package.json │ ├── help │ ├── main.ts │ ├── __tests__ │ └── main-test.ts │ └── jest.config.js ├── .prettierignore ├── .github ├── CODEOWNERS ├── workflows │ ├── pull-request-lint.yml │ ├── automerge.yml │ ├── auto-approve.yml │ ├── upgrade-main.yml │ ├── upgrade-cdktf.yml │ ├── upgrade-jsii-typescript.yml │ ├── build.yml │ └── release.yml ├── dependabot.yml └── MAINTENANCE.md ├── .copywrite.hcl ├── scripts ├── update-jsii-typescript.sh ├── update-cdktf.sh └── check-jsii-versions.js ├── .npmignore ├── projenrc ├── customized-license.ts ├── automerge.ts ├── auto-approve.ts ├── upgrade-cdktf.ts └── upgrade-jsii-typescript.ts ├── .projen ├── files.json ├── deps.json └── tasks.json ├── tsconfig.dev.json ├── .gitattributes ├── .gitignore ├── src └── index.ts ├── .eslintrc.json ├── package.json ├── .projenrc.ts ├── README.md └── LICENSE /test/.gitignore: -------------------------------------------------------------------------------- 1 | imports -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [] 3 | } 4 | -------------------------------------------------------------------------------- /examples/typescript/complex/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /examples/typescript/hello-world/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | -------------------------------------------------------------------------------- /test/cdk8s.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) HashiCorp, Inc. 2 | # SPDX-License-Identifier: MPL-2.0 3 | 4 | output: dist 5 | pluginsDirectory: /home/runner/.cdk8s/plugins 6 | imports: 7 | - k8s 8 | -------------------------------------------------------------------------------- /examples/typescript/complex/setup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | const cdktf = require("cdktf"); 7 | cdktf.Testing.setupJest(); 8 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/setup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | const cdktf = require("cdktf"); 7 | cdktf.Testing.setupJest(); 8 | -------------------------------------------------------------------------------- /examples/typescript/complex/.gitignore: -------------------------------------------------------------------------------- 1 | *.d.ts 2 | *.js 3 | node_modules 4 | cdktf.out 5 | cdktf.log 6 | *terraform.*.tfstate* 7 | .gen 8 | .terraform 9 | tsconfig.tsbuildinfo 10 | !jest.config.js 11 | !setup.js 12 | imports -------------------------------------------------------------------------------- /examples/typescript/hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | *.d.ts 2 | *.js 3 | node_modules 4 | cdktf.out 5 | cdktf.log 6 | *terraform.*.tfstate* 7 | .gen 8 | .terraform 9 | tsconfig.tsbuildinfo 10 | !jest.config.js 11 | !setup.js 12 | imports -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # they will be requested for review when someone opens a 4 | # pull request. 5 | * @cdktf/tf-cdk-team 6 | -------------------------------------------------------------------------------- /examples/typescript/complex/cdktf.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "typescript", 3 | "app": "npx ts-node main.ts", 4 | "projectId": "d5ce7cde-d7f4-43cf-baf6-ac62edcba923", 5 | "terraformProviders": [], 6 | "terraformModules": [], 7 | "context": { 8 | "excludeStackIdFromLogicalIds": "true", 9 | "allowSepCharsInLogicalIds": "true" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/cdktf.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "typescript", 3 | "app": "npx ts-node main.ts", 4 | "projectId": "d5ce7cde-d7f4-43cf-baf6-ac62edcba923", 5 | "terraformProviders": ["random@~> 3.1.0"], 6 | "terraformModules": [], 7 | "context": { 8 | "excludeStackIdFromLogicalIds": "true", 9 | "allowSepCharsInLogicalIds": "true" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.copywrite.hcl: -------------------------------------------------------------------------------- 1 | schema_version = 1 2 | 3 | project { 4 | license = "MPL-2.0" 5 | copyright_year = 2022 6 | 7 | # (OPTIONAL) A list of globs that should not have copyright/license headers. 8 | # Supports doublestar glob patterns for more flexibility in defining which 9 | # files or folders should be ignored 10 | header_ignore = [ 11 | # "vendors/**", 12 | # "**autogen**", 13 | "**/node_modules/**", 14 | ".mergify.yml", 15 | "dist/**", 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /scripts/update-jsii-typescript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) HashiCorp, Inc. 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | set -ex 6 | 7 | PROJECT_ROOT=$(cd "$(dirname "${BASH_SOURCE:-$0}")/.." && pwd) 8 | NEW_VERSION=$1 9 | 10 | if [ -z "$NEW_VERSION" ]; then 11 | echo "Usage: $0 " 12 | exit 1 13 | fi 14 | 15 | echo "Updating JSII & TypeScript version to $NEW_VERSION" 16 | yarn 17 | sed -i "s/typescriptVersion = \".*\";/typescriptVersion = \"~$NEW_VERSION\";/" "$PROJECT_ROOT/.projenrc.ts" 18 | CI=0 npx projen 19 | 20 | echo "Done" 21 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | /.projen/ 3 | /test-reports/ 4 | junit.xml 5 | /coverage/ 6 | permissions-backup.acl 7 | /dist/changelog.md 8 | /dist/version.txt 9 | /.prettierignore 10 | /.prettierrc.json 11 | /test/ 12 | /tsconfig.dev.json 13 | /src/ 14 | !/lib/ 15 | !/lib/**/*.js 16 | !/lib/**/*.d.ts 17 | dist 18 | /tsconfig.json 19 | /.github/ 20 | /.vscode/ 21 | /.idea/ 22 | /.projenrc.js 23 | tsconfig.tsbuildinfo 24 | /.eslintrc.json 25 | !.jsii 26 | scripts 27 | examples 28 | projenrc 29 | .copywrite.hcl 30 | /.gitattributes 31 | /.projenrc.ts 32 | /projenrc 33 | -------------------------------------------------------------------------------- /projenrc/customized-license.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { IResolver, License } from "projen"; 7 | import { TypeScriptProject } from "projen/lib/typescript"; 8 | 9 | const SPDX = "MPL-2.0"; 10 | 11 | export class CustomizedLicense extends License { 12 | constructor(project: TypeScriptProject) { 13 | super(project, { spdx: SPDX }); 14 | 15 | project.addFields({ license: SPDX }); 16 | } 17 | 18 | synthesizeContent(resolver: IResolver) { 19 | return ( 20 | "Copyright (c) 2022 HashiCorp, Inc.\n\n" + 21 | super.synthesizeContent(resolver) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".eslintrc.json", 4 | ".gitattributes", 5 | ".github/workflows/auto-approve.yml", 6 | ".github/workflows/automerge.yml", 7 | ".github/workflows/build.yml", 8 | ".github/workflows/pull-request-lint.yml", 9 | ".github/workflows/release.yml", 10 | ".github/workflows/upgrade-cdktf.yml", 11 | ".github/workflows/upgrade-jsii-typescript.yml", 12 | ".github/workflows/upgrade-main.yml", 13 | ".gitignore", 14 | ".prettierignore", 15 | ".prettierrc.json", 16 | ".projen/deps.json", 17 | ".projen/files.json", 18 | ".projen/tasks.json", 19 | "LICENSE", 20 | "tsconfig.dev.json" 21 | ], 22 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | merge_group: {} 14 | jobs: 15 | validate: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | permissions: 19 | pull-requests: write 20 | if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') 21 | steps: 22 | - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | types: |- 27 | feat 28 | fix 29 | chore 30 | requireScope: false 31 | -------------------------------------------------------------------------------- /tsconfig.dev.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "compilerOptions": { 4 | "alwaysStrict": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "experimentalDecorators": true, 8 | "inlineSourceMap": true, 9 | "inlineSources": true, 10 | "lib": [ 11 | "es2020" 12 | ], 13 | "module": "CommonJS", 14 | "noEmitOnError": false, 15 | "noFallthroughCasesInSwitch": true, 16 | "noImplicitAny": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "resolveJsonModule": true, 22 | "strict": true, 23 | "strictNullChecks": true, 24 | "strictPropertyInitialization": true, 25 | "stripInternal": true, 26 | "target": "ES2020" 27 | }, 28 | "include": [ 29 | "src/**/*.ts", 30 | "test/**/*.ts", 31 | ".projenrc.ts", 32 | "projenrc/**/*.ts" 33 | ], 34 | "exclude": [ 35 | "node_modules" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | * text=auto eol=lf 4 | *.snap linguist-generated 5 | /.eslintrc.json linguist-generated 6 | /.gitattributes linguist-generated 7 | /.github/workflows/auto-approve.yml linguist-generated 8 | /.github/workflows/automerge.yml linguist-generated 9 | /.github/workflows/build.yml linguist-generated 10 | /.github/workflows/pull-request-lint.yml linguist-generated 11 | /.github/workflows/release.yml linguist-generated 12 | /.github/workflows/upgrade-cdktf.yml linguist-generated 13 | /.github/workflows/upgrade-jsii-typescript.yml linguist-generated 14 | /.github/workflows/upgrade-main.yml linguist-generated 15 | /.gitignore linguist-generated 16 | /.npmignore linguist-generated 17 | /.prettierignore linguist-generated 18 | /.prettierrc.json linguist-generated 19 | /.projen/** linguist-generated 20 | /.projen/deps.json linguist-generated 21 | /.projen/files.json linguist-generated 22 | /.projen/tasks.json linguist-generated 23 | /LICENSE linguist-generated 24 | /package.json linguist-generated 25 | /tsconfig.dev.json linguist-generated 26 | /yarn.lock linguist-generated -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: automerge 4 | on: 5 | pull_request_target: 6 | types: 7 | - opened 8 | - labeled 9 | - ready_for_review 10 | - reopened 11 | - synchronize 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | jobs: 15 | automerge: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: read 19 | if: contains(github.event.pull_request.labels.*.name, 'automerge') && github.event.pull_request.draft == false 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 23 | - name: Turn on automerge for this PR by a trusted user or bot 24 | if: github.event.pull_request.user.login == 'team-tf-cdk' || contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association) || github.actor == 'dependabot[bot]' 25 | env: 26 | GH_TOKEN: ${{ secrets.PROJEN_GITHUB_TOKEN }} 27 | run: gh pr merge --auto --squash ${{ github.event.pull_request.number }} 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | !/.gitattributes 3 | !/.projen/tasks.json 4 | !/.projen/deps.json 5 | !/.projen/files.json 6 | !/.github/workflows/pull-request-lint.yml 7 | !/package.json 8 | !/.npmignore 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | lerna-debug.log* 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | lib-cov 21 | coverage 22 | *.lcov 23 | .nyc_output 24 | build/Release 25 | node_modules/ 26 | jspm_packages/ 27 | *.tsbuildinfo 28 | .eslintcache 29 | *.tgz 30 | .yarn-integrity 31 | .cache 32 | /test-reports/ 33 | junit.xml 34 | /coverage/ 35 | !/.github/workflows/build.yml 36 | /dist/changelog.md 37 | /dist/version.txt 38 | !/.github/workflows/release.yml 39 | !/.github/workflows/upgrade-main.yml 40 | !/.prettierignore 41 | !/.prettierrc.json 42 | !/test/ 43 | !/tsconfig.dev.json 44 | !/src/ 45 | /lib 46 | /dist/ 47 | !/.eslintrc.json 48 | .jsii 49 | tsconfig.json 50 | !/LICENSE 51 | !/.github/workflows/auto-approve.yml 52 | !/.github/workflows/automerge.yml 53 | !/.github/workflows/upgrade-cdktf.yml 54 | !/.github/workflows/upgrade-jsii-typescript.yml 55 | !/.projenrc.ts 56 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-world", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "types": "main.ts", 6 | "license": "MPL-2.0", 7 | "private": true, 8 | "scripts": { 9 | "postget": "cdk8s import k8s --language typescript", 10 | "get": "cdktf get", 11 | "build": "tsc", 12 | "synth": "cdktf synth", 13 | "predeploy": "yarn get", 14 | "deploy": "cdktf deploy", 15 | "predestroy": "yarn get", 16 | "destroy": "cdktf destroy", 17 | "compile": "tsc --pretty", 18 | "watch": "tsc -w", 19 | "test": "jest", 20 | "test:watch": "jest --watch", 21 | "upgrade": "npm i cdktf@latest cdktf-cli@latest", 22 | "upgrade:next": "npm i cdktf@next cdktf-cli@next" 23 | }, 24 | "engines": { 25 | "node": ">=20.9.0" 26 | }, 27 | "dependencies": { 28 | "@cdktf/provider-kubernetes": ">=11.0.0", 29 | "cdk8s": "^2.8.0", 30 | "cdktf": "^0.21.0", 31 | "cdktf-cdk8s": "latest", 32 | "constructs": "^10.4.2" 33 | }, 34 | "devDependencies": { 35 | "@types/jest": "^30.0.0", 36 | "@types/node": "^20", 37 | "cdk8s-cli": ">=2.3", 38 | "cdktf-cli": "^0.21.0", 39 | "jest": "^30.0.0", 40 | "ts-jest": "^29.3.2", 41 | "ts-node": "^10.4.0", 42 | "typescript": "^5.8.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/typescript/complex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "complex", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "types": "main.ts", 6 | "license": "MPL-2.0", 7 | "private": true, 8 | "scripts": { 9 | "postget": "cdk8s import k8s --language typescript", 10 | "get": "cdktf get", 11 | "build": "tsc", 12 | "synth": "cdktf synth", 13 | "predeploy": "yarn get", 14 | "deploy": "cdktf deploy", 15 | "predestroy": "yarn get", 16 | "destroy": "cdktf destroy", 17 | "compile": "tsc --pretty", 18 | "watch": "tsc -w", 19 | "test": "jest", 20 | "test:watch": "jest --watch", 21 | "upgrade": "npm i cdktf@latest cdktf-cli@latest", 22 | "upgrade:next": "npm i cdktf@next cdktf-cli@next" 23 | }, 24 | "engines": { 25 | "node": ">=20.9.0" 26 | }, 27 | "dependencies": { 28 | "@cdktf/provider-kubernetes": ">=11.0.0", 29 | "@cdktf/provider-random": ">=11.0.0", 30 | "cdk8s": "^2.8.0", 31 | "cdk8s-plus-22": "^2.0.0-rc.158", 32 | "cdktf": "^0.21.0", 33 | "cdktf-cdk8s": "latest", 34 | "constructs": "^10.4.2" 35 | }, 36 | "devDependencies": { 37 | "@types/jest": "^30.0.0", 38 | "@types/node": "^20", 39 | "cdk8s-cli": ">=2.3", 40 | "cdktf-cli": "^0.21.0", 41 | "jest": "^30.0.2", 42 | "ts-jest": "^29.3.2", 43 | "ts-node": "^10.4.0", 44 | "typescript": "^5.8.3" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: auto-approve 4 | on: 5 | pull_request_target: 6 | types: 7 | - opened 8 | - labeled 9 | - ready_for_review 10 | - reopened 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }} 13 | jobs: 14 | approve: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | contents: read 18 | pull-requests: write 19 | if: contains(github.event.pull_request.labels.*.name, 'auto-approve') && github.event.pull_request.draft == false 20 | steps: 21 | - name: Checkout PR 22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 23 | with: 24 | ref: ${{ github.event.pull_request.head.ref }} 25 | repository: ${{ github.event.pull_request.head.repo.full_name }} 26 | - name: Auto-approve PRs by other users as team-tf-cdk 27 | if: github.event.pull_request.user.login != 'team-tf-cdk' && (contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association) || github.actor == 'dependabot[bot]') 28 | env: 29 | GH_TOKEN: ${{ secrets.PROJEN_GITHUB_TOKEN }} 30 | run: gh pr review ${{ github.event.pull_request.number }} --approve 31 | - name: Auto-approve PRs by team-tf-cdk as github-actions[bot] 32 | if: github.event.pull_request.user.login == 'team-tf-cdk' 33 | env: 34 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | run: gh pr review ${{ github.event.pull_request.number }} --approve 36 | -------------------------------------------------------------------------------- /scripts/update-cdktf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) HashiCorp, Inc. 3 | # SPDX-License-Identifier: MPL-2.0 4 | 5 | set -ex 6 | 7 | PROJECT_ROOT=$(cd "$(dirname "${BASH_SOURCE:-$0}")/.." && pwd) 8 | CDKTF_VERSION=$1 9 | CONSTRUCTS_VERSION=$2 10 | 11 | if [ -z "$CDKTF_VERSION" ]; then 12 | echo "Usage: $0 " 13 | exit 1 14 | fi 15 | if [ -z "$CONSTRUCTS_VERSION" ]; then 16 | echo "Usage: $0 " 17 | exit 1 18 | fi 19 | 20 | echo "Updating to cdktf version $CDKTF_VERSION and constructs version $CONSTRUCTS_VERSION" 21 | yarn 22 | sed -i "s/cdktfVersion: \".*\",/cdktfVersion: \"$CDKTF_VERSION\",/" "$PROJECT_ROOT/.projenrc.ts" 23 | sed -i "s/\"cdktf@>=.*\"/\"cdktf@>=$CDKTF_VERSION\"/" "$PROJECT_ROOT/.projenrc.ts" 24 | sed -i "s/constructsVersion = \".*\";/constructsVersion = \"$CONSTRUCTS_VERSION\";/" "$PROJECT_ROOT/.projenrc.ts" 25 | CI=0 npx projen 26 | 27 | echo "Updating README" 28 | sed -i 's/`cdktf` >= .*/`cdktf` >= '"$CDKTF_VERSION"'/' "$PROJECT_ROOT/README.md" 29 | sed -i 's/`constructs` >= .*/`constructs` >= '"$CONSTRUCTS_VERSION"'/' "$PROJECT_ROOT/README.md" 30 | 31 | echo "Updating examples" 32 | # Loop through all examples and update the cdktf version 33 | for example in $(find "$PROJECT_ROOT/examples/typescript" -mindepth 1 -maxdepth 1 -type d); do 34 | echo "Updating example $example to cdktf version $CDKTF_VERSION and constructs version $CONSTRUCTS_VERSION" 35 | cd "$example" 36 | npm install 37 | npm install -D cdktf-cli@^$CDKTF_VERSION 38 | npm install cdktf@^$CDKTF_VERSION constructs@^$CONSTRUCTS_VERSION 39 | done 40 | -------------------------------------------------------------------------------- /examples/typescript/complex/help: -------------------------------------------------------------------------------- 1 | ======================================================================================================== 2 | 3 | Your cdktf typescript project is ready! 4 | 5 | cat help Print this message 6 | 7 | Compile: 8 | npm run get Import/update Terraform providers and modules (you should check-in this directory) 9 | npm run compile Compile typescript code to javascript (or "npm run watch") 10 | npm run watch Watch for changes and compile typescript in the background 11 | npm run build Compile typescript 12 | 13 | Synthesize: 14 | cdktf synth [stack] Synthesize Terraform resources from stacks to cdktf.out/ (ready for 'terraform apply') 15 | 16 | Diff: 17 | cdktf diff [stack] Perform a diff (terraform plan) for the given stack 18 | 19 | Deploy: 20 | cdktf deploy [stack] Deploy the given stack 21 | 22 | Destroy: 23 | cdktf destroy [stack] Destroy the stack 24 | 25 | Test: 26 | npm run test Runs unit tests (edit __tests__/main-test.ts to add your own tests) 27 | npm run test:watch Watches the tests and reruns them on change 28 | 29 | Upgrades: 30 | npm run upgrade Upgrade cdktf modules to latest version 31 | npm run upgrade:next Upgrade cdktf modules to latest "@next" version (last commit) 32 | 33 | Use Prebuilt Providers: 34 | 35 | You can find all prebuilt providers on npm: https://www.npmjs.com/search?q=keywords:cdktf 36 | You can install these providers through npm: 37 | 38 | npm install @cdktf/provider-aws 39 | npm install @cdktf/provider-google 40 | npm install @cdktf/provider-azurerm 41 | npm install @cdktf/provider-docker 42 | npm install @cdktf/provider-github 43 | npm install @cdktf/provider-null 44 | 45 | You can also build any module or provider locally. Learn more https://cdk.tf/modules-and-providers 46 | 47 | ======================================================================================================== 48 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/help: -------------------------------------------------------------------------------- 1 | ======================================================================================================== 2 | 3 | Your cdktf typescript project is ready! 4 | 5 | cat help Print this message 6 | 7 | Compile: 8 | npm run get Import/update Terraform providers and modules (you should check-in this directory) 9 | npm run compile Compile typescript code to javascript (or "npm run watch") 10 | npm run watch Watch for changes and compile typescript in the background 11 | npm run build Compile typescript 12 | 13 | Synthesize: 14 | cdktf synth [stack] Synthesize Terraform resources from stacks to cdktf.out/ (ready for 'terraform apply') 15 | 16 | Diff: 17 | cdktf diff [stack] Perform a diff (terraform plan) for the given stack 18 | 19 | Deploy: 20 | cdktf deploy [stack] Deploy the given stack 21 | 22 | Destroy: 23 | cdktf destroy [stack] Destroy the stack 24 | 25 | Test: 26 | npm run test Runs unit tests (edit __tests__/main-test.ts to add your own tests) 27 | npm run test:watch Watches the tests and reruns them on change 28 | 29 | Upgrades: 30 | npm run upgrade Upgrade cdktf modules to latest version 31 | npm run upgrade:next Upgrade cdktf modules to latest "@next" version (last commit) 32 | 33 | Use Prebuilt Providers: 34 | 35 | You can find all prebuilt providers on npm: https://www.npmjs.com/search?q=keywords:cdktf 36 | You can install these providers through npm: 37 | 38 | npm install @cdktf/provider-aws 39 | npm install @cdktf/provider-google 40 | npm install @cdktf/provider-azurerm 41 | npm install @cdktf/provider-docker 42 | npm install @cdktf/provider-github 43 | npm install @cdktf/provider-null 44 | 45 | You can also build any module or provider locally. Learn more https://cdk.tf/modules-and-providers 46 | 47 | ======================================================================================================== 48 | -------------------------------------------------------------------------------- /projenrc/automerge.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { javascript } from "projen"; 7 | import { JobPermission } from "projen/lib/github/workflows-model"; 8 | 9 | /** 10 | * Enables GitHub's built-in automerge for PRs with the "automerge" label 11 | */ 12 | export class Automerge { 13 | constructor(project: javascript.NodeProject) { 14 | const workflow = project.github?.addWorkflow("automerge"); 15 | 16 | if (!workflow) throw new Error("no workflow defined"); 17 | 18 | workflow.on({ 19 | pullRequestTarget: { 20 | types: [ 21 | "opened", 22 | "labeled", 23 | "ready_for_review", 24 | "reopened", 25 | "synchronize", 26 | ], 27 | }, 28 | }); 29 | 30 | (workflow.concurrency as any) = { 31 | group: "${{ github.workflow }}-${{ github.ref }}", 32 | }; 33 | 34 | const maintainerStatuses = `fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]')`; 35 | workflow.addJobs({ 36 | automerge: { 37 | runsOn: ["ubuntu-latest"], 38 | if: "contains(github.event.pull_request.labels.*.name, 'automerge') && github.event.pull_request.draft == false", 39 | steps: [ 40 | { 41 | name: "Checkout", 42 | uses: "actions/checkout@v3", 43 | }, 44 | { 45 | name: "Turn on automerge for this PR by a trusted user or bot", 46 | if: `github.event.pull_request.user.login == 'team-tf-cdk' || contains(${maintainerStatuses}, github.event.pull_request.author_association) || github.actor == 'dependabot[bot]'`, 47 | run: "gh pr merge --auto --squash ${{ github.event.pull_request.number }}", 48 | env: { 49 | GH_TOKEN: "${{ secrets.PROJEN_GITHUB_TOKEN }}", 50 | }, 51 | }, 52 | ], 53 | permissions: { 54 | contents: JobPermission.READ, 55 | }, 56 | }, 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /scripts/check-jsii-versions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | const today = new Date(); 6 | const oneMonthFromToday = new Date(); 7 | oneMonthFromToday.setDate(today.getDate() + 30); 8 | // console.debug("oneMonthFromToday", oneMonthFromToday.toDateString()); 9 | 10 | /** Return the earliest supported version whose EOS date is at least a month away */ 11 | async function getEarliestSupportedVersion() { 12 | // https://github.com/aws/jsii-compiler/blob/main/releases.json 13 | const response = await fetch("https://raw.githubusercontent.com/aws/jsii-compiler/main/releases.json"); 14 | const data = await response.json(); 15 | const activelySupportedVersions = Object.entries(data.maintenance).filter(([version, supportEndDate]) => { 16 | return new Date(supportEndDate) > oneMonthFromToday; 17 | }).sort((a, b) => { 18 | // Very naive sorting function: treat "5.4" like (int) 54, "5.5" like (int) 55, etc. and compare accordingly 19 | return parseInt(a[0].replace(".", ""), 10) > parseInt(b[0].replace(".", ""), 10); 20 | }); 21 | 22 | console.debug("Actively supported versions with an EOS date at least 1 month away") 23 | console.debug(Object.fromEntries(activelySupportedVersions)); 24 | 25 | return activelySupportedVersions[0][0]; 26 | } 27 | 28 | async function getDesiredVersion() { 29 | const earliestSupportedVersion = await getEarliestSupportedVersion(); 30 | console.debug("earliestSupportedVersion", earliestSupportedVersion); 31 | 32 | return earliestSupportedVersion; 33 | } 34 | 35 | module.exports = async ({github, context, core}) => { 36 | const version = await getDesiredVersion(); 37 | 38 | core.exportVariable('NEW_JSII_VERSION', version + ".0"); // e.g. "5.4.0" 39 | core.exportVariable('NEW_JSII_VERSION_SHORT', version); // e.g. "5.4" 40 | core.exportVariable('NEW_JSII_VERSION_MAJOR', version.split(".")[0]); // e.g. "5" 41 | core.exportVariable('NEW_JSII_VERSION_MINOR', version.split(".")[1]); // e.g. "4" 42 | } 43 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { Construct } from "constructs"; 7 | import { App, TerraformStack } from "cdktf"; 8 | import { App as CDK8sApp, Chart, ChartProps } from "cdk8s"; 9 | import { CDK8sProvider } from "cdktf-cdk8s"; 10 | import * as k8s from "./imports/k8s"; 11 | import { RandomProvider } from "./.gen/providers/random/random-provider"; 12 | import { Password } from "./.gen/providers/random/password/index"; 13 | 14 | interface MyChartProps extends ChartProps { 15 | password: string; 16 | } 17 | 18 | class MyChart extends Chart { 19 | constructor(scope: Construct, id: string, props: MyChartProps) { 20 | super(scope, id, props); 21 | 22 | const labels = { app: "test" }; 23 | new k8s.KubeDeployment(this, "deployment", { 24 | metadata: { 25 | labels, 26 | namespace: "default", 27 | }, 28 | spec: { 29 | selector: { 30 | matchLabels: labels, 31 | }, 32 | template: { 33 | metadata: { 34 | labels, 35 | }, 36 | spec: { 37 | containers: [ 38 | { 39 | name: "nginx", 40 | image: "nginx:latest", 41 | env: [ 42 | { 43 | name: "password", 44 | value: props.password, 45 | }, 46 | ], 47 | }, 48 | ], 49 | }, 50 | }, 51 | }, 52 | }); 53 | } 54 | } 55 | 56 | class MyStack extends TerraformStack { 57 | constructor(scope: Construct, name: string) { 58 | super(scope, name); 59 | new RandomProvider(this, "random", {}); 60 | 61 | const password = new Password(this, "terraform-password", { 62 | length: 42, 63 | }); 64 | 65 | const cdk8s = new CDK8sApp(); 66 | new MyChart(cdk8s, "chart", { password: password.result }); 67 | 68 | new CDK8sProvider(this, "cdk8s-provider", { 69 | cdk8sApp: cdk8s, 70 | configContext: "kind-kind", 71 | configPath: "~/.kube/config", 72 | }); 73 | } 74 | } 75 | 76 | const app = new App(); 77 | new MyStack(app, "hello-world"); 78 | app.synth(); 79 | -------------------------------------------------------------------------------- /projenrc/auto-approve.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { javascript } from "projen"; 7 | import { JobPermission } from "projen/lib/github/workflows-model"; 8 | 9 | /** 10 | * Approves PRs with the "auto-approve" label 11 | */ 12 | export class AutoApprove { 13 | constructor(project: javascript.NodeProject) { 14 | const workflow = project.github?.addWorkflow("auto-approve"); 15 | 16 | if (!workflow) throw new Error("no workflow defined"); 17 | 18 | workflow.on({ 19 | pullRequestTarget: { 20 | types: ["opened", "labeled", "ready_for_review", "reopened"], 21 | }, 22 | }); 23 | 24 | (workflow.concurrency as any) = { 25 | group: "${{ github.workflow }}-${{ github.ref }}", 26 | }; 27 | 28 | const maintainerStatuses = `fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]')`; 29 | workflow.addJobs({ 30 | approve: { 31 | runsOn: ["ubuntu-latest"], 32 | if: "contains(github.event.pull_request.labels.*.name, 'auto-approve') && github.event.pull_request.draft == false", 33 | steps: [ 34 | { 35 | name: "Checkout PR", 36 | uses: "actions/checkout@v3", 37 | with: { 38 | ref: "${{ github.event.pull_request.head.ref }}", 39 | repository: 40 | "${{ github.event.pull_request.head.repo.full_name }}", 41 | }, 42 | }, 43 | { 44 | name: "Auto-approve PRs by other users as team-tf-cdk", 45 | if: `github.event.pull_request.user.login != 'team-tf-cdk' && (contains(${maintainerStatuses}, github.event.pull_request.author_association) || github.actor == 'dependabot[bot]')`, 46 | run: "gh pr review ${{ github.event.pull_request.number }} --approve", 47 | env: { 48 | GH_TOKEN: "${{ secrets.PROJEN_GITHUB_TOKEN }}", 49 | }, 50 | }, 51 | { 52 | name: "Auto-approve PRs by team-tf-cdk as github-actions[bot]", 53 | if: "github.event.pull_request.user.login == 'team-tf-cdk'", 54 | run: "gh pr review ${{ github.event.pull_request.number }} --approve", 55 | env: { 56 | GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}", 57 | }, 58 | }, 59 | ], 60 | permissions: { 61 | contents: JobPermission.READ, 62 | pullRequests: JobPermission.WRITE, 63 | }, 64 | }, 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { provider, manifest } from "@cdktf/provider-kubernetes"; 7 | import { App } from "cdk8s"; 8 | import { Aspects } from "cdktf"; 9 | import { Construct, IConstruct } from "constructs"; 10 | import * as yaml from "yaml"; 11 | 12 | export interface CDK8sProviderConfig extends provider.KubernetesProviderConfig { 13 | readonly cdk8sApp: App; 14 | } 15 | 16 | // TODO: Offer option that base64 encodes the strings and wraps them in btoa 17 | // TODO: Order Terraform Manifests 18 | function wrapLeafStringKeys(object: any): any { 19 | if (typeof object === "string") { 20 | return object 21 | .replace(/\n/g, "\\n") // escape newlines 22 | .replace(/\${/g, "$$${"); // escape ${ to $${; 23 | } 24 | const ret = Object.entries(object).reduce((acc, [key, value]) => { 25 | if (typeof value === "string") { 26 | return { 27 | ...acc, 28 | [key]: wrapLeafStringKeys(value), 29 | }; 30 | } 31 | if (typeof value === "object") { 32 | if (Array.isArray(value)) { 33 | return { 34 | ...acc, 35 | [key]: value.map(wrapLeafStringKeys), 36 | }; 37 | } else { 38 | return { 39 | ...acc, 40 | [key]: wrapLeafStringKeys(value), 41 | }; 42 | } 43 | } 44 | return { ...acc, [key]: value }; 45 | }, {} as Record); 46 | return ret; 47 | } 48 | export class CDK8sProvider extends provider.KubernetesProvider { 49 | constructor(scope: Construct, id: string, config: CDK8sProviderConfig) { 50 | super(scope, id, config); 51 | this.alias = `cdktf-cdk8s-${id}`; 52 | 53 | Aspects.of(scope).add({ 54 | visit: (node: IConstruct) => { 55 | // Only run once 56 | if (node !== this) return; 57 | 58 | const yamlManifests = yaml.parseAllDocuments( 59 | config.cdk8sApp.synthYaml() 60 | ); 61 | 62 | yamlManifests.forEach((yamlManifest) => { 63 | const jsonManifest = yamlManifest.toJSON(); 64 | const type = `${jsonManifest.apiVersion}-${jsonManifest.kind}`; 65 | const namespace = jsonManifest.metadata.namespace || "default"; 66 | const uniqueId = `${ 67 | jsonManifest.metadata.name || jsonManifest.metadata.generateName 68 | }-${namespace}`; 69 | const manifestContent = wrapLeafStringKeys(jsonManifest); 70 | 71 | new manifest.Manifest(this, `${id}-${type}-${uniqueId}`, { 72 | provider: this, 73 | manifest: manifestContent, 74 | }); 75 | }); 76 | }, 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # NOTE: This file is not managed by Projen because if you enable Dependabot through Projen, 2 | # it will delete the upgrade-main job and expect you to only use Dependabot for updates. 3 | # That is not what we want either; we just want to use Dependabot for security updates. 4 | 5 | version: 2 6 | updates: 7 | - package-ecosystem: npm 8 | versioning-strategy: lockfile-only 9 | directory: / 10 | schedule: 11 | interval: daily 12 | ignore: 13 | - dependency-name: projen 14 | labels: 15 | - auto-approve 16 | - automerge 17 | - dependencies 18 | - security 19 | # Disable version updates for npm dependencies, only use Dependabot for security updates 20 | open-pull-requests-limit: 0 21 | - package-ecosystem: npm 22 | versioning-strategy: increase-if-necessary 23 | directory: /examples/typescript/complex 24 | schedule: 25 | interval: weekly 26 | open-pull-requests-limit: 5 27 | ignore: 28 | - dependency-name: "@types/node" 29 | # For providers, ignore all non-breaking updates for version updates only 30 | - dependency-name: "@cdktf/provider-*" 31 | update-types: ["version-update:semver-minor", "version-update:semver-patch"] 32 | groups: 33 | cdktf: 34 | patterns: 35 | - "cdktf" 36 | - "cdktf-cli" 37 | - "@cdktf/*" 38 | jest: 39 | patterns: 40 | - "jest" 41 | - "ts-jest" 42 | - "@types/jest" 43 | - "@jest/*" 44 | cdk8s: 45 | patterns: 46 | - "cdk8s" 47 | - "cdk8s-cli" 48 | - "cdk8s-plus-22" 49 | - "@cdk8s/*" 50 | labels: 51 | - auto-approve 52 | - automerge 53 | - dependencies 54 | - package-ecosystem: npm 55 | versioning-strategy: increase-if-necessary 56 | directory: /examples/typescript/hello-world 57 | schedule: 58 | interval: weekly 59 | open-pull-requests-limit: 5 60 | ignore: 61 | - dependency-name: "@types/node" 62 | # For providers, ignore all non-breaking updates for version updates only 63 | - dependency-name: "@cdktf/provider-*" 64 | update-types: ["version-update:semver-minor", "version-update:semver-patch"] 65 | groups: 66 | cdktf: 67 | patterns: 68 | - "cdktf" 69 | - "cdktf-cli" 70 | - "@cdktf/*" 71 | jest: 72 | patterns: 73 | - "jest" 74 | - "ts-jest" 75 | - "@types/jest" 76 | - "@jest/*" 77 | cdk8s: 78 | patterns: 79 | - "cdk8s" 80 | - "cdk8s-cli" 81 | - "@cdk8s/*" 82 | labels: 83 | - auto-approve 84 | - automerge 85 | - dependencies 86 | -------------------------------------------------------------------------------- /.projen/deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "@types/jest", 5 | "type": "build" 6 | }, 7 | { 8 | "name": "@types/node", 9 | "version": "ts5.8", 10 | "type": "build" 11 | }, 12 | { 13 | "name": "@typescript-eslint/eslint-plugin", 14 | "version": "^8", 15 | "type": "build" 16 | }, 17 | { 18 | "name": "@typescript-eslint/parser", 19 | "version": "^8", 20 | "type": "build" 21 | }, 22 | { 23 | "name": "cdk8s-cli", 24 | "version": ">=2.3", 25 | "type": "build" 26 | }, 27 | { 28 | "name": "commit-and-tag-version", 29 | "version": "^12", 30 | "type": "build" 31 | }, 32 | { 33 | "name": "constructs", 34 | "version": "^10.0.0", 35 | "type": "build" 36 | }, 37 | { 38 | "name": "eslint-config-prettier", 39 | "type": "build" 40 | }, 41 | { 42 | "name": "eslint-import-resolver-typescript", 43 | "type": "build" 44 | }, 45 | { 46 | "name": "eslint-plugin-import", 47 | "type": "build" 48 | }, 49 | { 50 | "name": "eslint-plugin-prettier", 51 | "type": "build" 52 | }, 53 | { 54 | "name": "eslint", 55 | "version": "^9", 56 | "type": "build" 57 | }, 58 | { 59 | "name": "jest", 60 | "type": "build" 61 | }, 62 | { 63 | "name": "jest-junit", 64 | "version": "^16", 65 | "type": "build" 66 | }, 67 | { 68 | "name": "jsii-diff", 69 | "type": "build" 70 | }, 71 | { 72 | "name": "jsii-pacmak", 73 | "type": "build" 74 | }, 75 | { 76 | "name": "jsii-rosetta", 77 | "version": "~5.8.0", 78 | "type": "build" 79 | }, 80 | { 81 | "name": "jsii", 82 | "version": "~5.8.0", 83 | "type": "build" 84 | }, 85 | { 86 | "name": "prettier", 87 | "type": "build" 88 | }, 89 | { 90 | "name": "projen", 91 | "type": "build" 92 | }, 93 | { 94 | "name": "ts-jest", 95 | "type": "build" 96 | }, 97 | { 98 | "name": "ts-node", 99 | "version": "10.9.1", 100 | "type": "build" 101 | }, 102 | { 103 | "name": "typescript", 104 | "version": "~5.8.0", 105 | "type": "build" 106 | }, 107 | { 108 | "name": "yaml", 109 | "version": "2.3.4", 110 | "type": "bundled" 111 | }, 112 | { 113 | "name": "@cdktf/provider-kubernetes", 114 | "version": ">=12.0.0", 115 | "type": "peer" 116 | }, 117 | { 118 | "name": "cdk8s", 119 | "version": ">=2.8.0", 120 | "type": "peer" 121 | }, 122 | { 123 | "name": "cdktf", 124 | "version": ">=0.21.0", 125 | "type": "peer" 126 | }, 127 | { 128 | "name": "constructs", 129 | "version": "^10.4.2", 130 | "type": "peer" 131 | } 132 | ], 133 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 134 | } 135 | -------------------------------------------------------------------------------- /examples/typescript/complex/__tests__/main-test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import "cdktf/lib/testing/adapters/jest"; // Load types for expect matchers 7 | // import { Testing } from "cdktf"; 8 | 9 | describe("My CDKTF Application", () => { 10 | // The tests below are example tests, you can find more information at 11 | // https://cdk.tf/testing 12 | it.todo("should be tested"); 13 | 14 | // // All Unit testst test the synthesised terraform code, it does not create real-world resources 15 | // describe("Unit testing using assertions", () => { 16 | // it("should contain a resource", () => { 17 | // // import { Image,Container } from "./.gen/providers/docker" 18 | // expect( 19 | // Testing.synthScope((scope) => { 20 | // new MyApplicationsAbstraction(scope, "my-app", {}); 21 | // }) 22 | // ).toHaveResource(Container); 23 | 24 | // expect( 25 | // Testing.synthScope((scope) => { 26 | // new MyApplicationsAbstraction(scope, "my-app", {}); 27 | // }) 28 | // ).toHaveResourceWithProperties(Image, { name: "ubuntu:latest" }); 29 | // }); 30 | // }); 31 | 32 | // describe("Unit testing using snapshots", () => { 33 | // it("Tests the snapshot", () => { 34 | // const app = Testing.app(); 35 | // const stack = new TerraformStack(app, "test"); 36 | 37 | // new TestProvider(stack, "provider", { 38 | // accessKey: "1", 39 | // }); 40 | 41 | // new TestResource(stack, "test", { 42 | // name: "my-resource", 43 | // }); 44 | 45 | // expect(Testing.synth(stack)).toMatchSnapshot(); 46 | // }); 47 | 48 | // it("Tests a combination of resources", () => { 49 | // expect( 50 | // Testing.synthScope((stack) => { 51 | // new TestDataSource(stack, "test-data-source", { 52 | // name: "foo", 53 | // }); 54 | 55 | // new TestResource(stack, "test-resource", { 56 | // name: "bar", 57 | // }); 58 | // }) 59 | // ).toMatchInlineSnapshot(); 60 | // }); 61 | // }); 62 | 63 | // describe("Checking validity", () => { 64 | // it("check if the produced terraform configuration is valid", () => { 65 | // const app = Testing.app(); 66 | // const stack = new TerraformStack(app, "test"); 67 | 68 | // new TestDataSource(stack, "test-data-source", { 69 | // name: "foo", 70 | // }); 71 | 72 | // new TestResource(stack, "test-resource", { 73 | // name: "bar", 74 | // }); 75 | // expect(Testing.fullSynth(app)).toBeValidTerraform(); 76 | // }); 77 | 78 | // it("check if this can be planned", () => { 79 | // const app = Testing.app(); 80 | // const stack = new TerraformStack(app, "test"); 81 | 82 | // new TestDataSource(stack, "test-data-source", { 83 | // name: "foo", 84 | // }); 85 | 86 | // new TestResource(stack, "test-resource", { 87 | // name: "bar", 88 | // }); 89 | // expect(Testing.fullSynth(app)).toPlanSuccessfully(); 90 | // }); 91 | // }); 92 | }); 93 | -------------------------------------------------------------------------------- /examples/typescript/complex/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { Construct } from "constructs"; 7 | import { App, TerraformStack, TerraformOutput } from "cdktf"; 8 | import { App as CDK8sApp, Chart, ChartProps } from "cdk8s"; 9 | import { CDK8sProvider } from "cdktf-cdk8s"; 10 | import * as kplus from "cdk8s-plus-22"; 11 | import { RandomProvider } from "@cdktf/provider-random/lib/provider"; 12 | import { Pet } from "@cdktf/provider-random/lib/pet"; 13 | 14 | interface MyChartProps extends ChartProps { 15 | podName: string; 16 | directory: string; 17 | } 18 | 19 | // https://cdk8s.io/docs/latest/plus/config-map/#creating-a-volume-from-a-directory 20 | class PodWithMountedAppDirChart extends Chart { 21 | public podName: string; 22 | constructor(scope: Construct, id: string, props: MyChartProps) { 23 | super(scope, id, props); 24 | 25 | const appMap = new kplus.ConfigMap(this, "Config"); 26 | 27 | appMap.addDirectory(props.directory); 28 | 29 | const appVolume = kplus.Volume.fromConfigMap(this, "app", appMap); 30 | 31 | const mountPath = "/var/app"; 32 | const pod = new kplus.Pod(this, "Pod"); 33 | const container = pod.addContainer({ 34 | image: "node", 35 | command: ["node", "app.js"], 36 | workingDir: mountPath, 37 | }); 38 | 39 | // from here, just mount the volume to a container, and run your app! 40 | container.mount(mountPath, appVolume); 41 | this.podName = pod.name; 42 | } 43 | } 44 | 45 | class MyStack extends TerraformStack { 46 | constructor(scope: Construct, name: string) { 47 | super(scope, name); 48 | 49 | new RandomProvider(this, "random"); 50 | 51 | const cdk8s = new CDK8sApp(); 52 | const chart = new PodWithMountedAppDirChart(cdk8s, "config-map-example", { 53 | podName: new Pet(this, "chart-pet-name").id, // Can use values from the CDKTF context 54 | directory: "./imports", // We don't use TerraformAsset here since the read values are inlined in the configuration 55 | }); 56 | 57 | // Multiple charts of the same kind can be configured in a CDK8s app 58 | new PodWithMountedAppDirChart(cdk8s, "another-config-map-example", { 59 | podName: new Pet(this, "another-chart-pet-name").id, 60 | directory: "./node_modules/cdktf", 61 | }); 62 | 63 | // The adapter can be used in multiple K8s contexts 64 | new CDK8sProvider(this, "cdk8s-provider-for-kind", { 65 | cdk8sApp: cdk8s, 66 | configContext: "kind-kind", 67 | configPath: "$HOME/.kube/config", 68 | }); 69 | 70 | new CDK8sProvider(this, "cdk8s-provider-for-docker-desktop", { 71 | cdk8sApp: cdk8s, 72 | configContext: "docker-desktop", 73 | configPath: "$HOME/.kube/config", 74 | }); 75 | 76 | new TerraformOutput(this, "pod-name", { 77 | // Can use values from the CDK8s context 78 | // While we are able to get static values we'd need to 79 | // use a data source to get dynamic values (e.g. the IP of pod) 80 | value: chart.podName, 81 | }); 82 | } 83 | } 84 | 85 | const app = new App(); 86 | new MyStack(app, "hello-world"); 87 | app.synth(); 88 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/__tests__/main-test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import "cdktf/lib/testing/adapters/jest"; // Load types for expect matchers 7 | // import { Testing } from "cdktf"; 8 | 9 | describe("My CDKTF Application", () => { 10 | // The tests below are example tests, you can find more information at 11 | // https://cdk.tf/testing 12 | it.todo("should be tested"); 13 | 14 | // // All Unit testst test the synthesised terraform code, it does not create real-world resources 15 | // describe("Unit testing using assertions", () => { 16 | // it("should contain a resource", () => { 17 | // // import { Image,Container } from "./.gen/providers/docker" 18 | // expect( 19 | // Testing.synthScope((scope) => { 20 | // new MyApplicationsAbstraction(scope, "my-app", {}); 21 | // }) 22 | // ).toHaveResource(Container); 23 | 24 | // expect( 25 | // Testing.synthScope((scope) => { 26 | // new MyApplicationsAbstraction(scope, "my-app", {}); 27 | // }) 28 | // ).toHaveResourceWithProperties(Image, { name: "ubuntu:latest" }); 29 | // }); 30 | // }); 31 | 32 | // describe("Unit testing using snapshots", () => { 33 | // it("Tests the snapshot", () => { 34 | // const app = Testing.app(); 35 | // const stack = new TerraformStack(app, "test"); 36 | 37 | // new TestProvider(stack, "provider", { 38 | // accessKey: "1", 39 | // }); 40 | 41 | // new TestResource(stack, "test", { 42 | // name: "my-resource", 43 | // }); 44 | 45 | // expect(Testing.synth(stack)).toMatchSnapshot(); 46 | // }); 47 | 48 | // it("Tests a combination of resources", () => { 49 | // expect( 50 | // Testing.synthScope((stack) => { 51 | // new TestDataSource(stack, "test-data-source", { 52 | // name: "foo", 53 | // }); 54 | 55 | // new TestResource(stack, "test-resource", { 56 | // name: "bar", 57 | // }); 58 | // }) 59 | // ).toMatchInlineSnapshot(); 60 | // }); 61 | // }); 62 | 63 | // describe("Checking validity", () => { 64 | // it("check if the produced terraform configuration is valid", () => { 65 | // const app = Testing.app(); 66 | // const stack = new TerraformStack(app, "test"); 67 | 68 | // new TestDataSource(stack, "test-data-source", { 69 | // name: "foo", 70 | // }); 71 | 72 | // new TestResource(stack, "test-resource", { 73 | // name: "bar", 74 | // }); 75 | // expect(Testing.fullSynth(app)).toBeValidTerraform(); 76 | // }); 77 | 78 | // it("check if this can be planned", () => { 79 | // const app = Testing.app(); 80 | // const stack = new TerraformStack(app, "test"); 81 | 82 | // new TestDataSource(stack, "test-data-source", { 83 | // name: "foo", 84 | // }); 85 | 86 | // new TestResource(stack, "test-resource", { 87 | // name: "bar", 88 | // }); 89 | // expect(Testing.fullSynth(app)).toPlanSuccessfully(); 90 | // }); 91 | // }); 92 | }); 93 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "env": { 4 | "jest": true, 5 | "node": true 6 | }, 7 | "root": true, 8 | "plugins": [ 9 | "@typescript-eslint", 10 | "import" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaVersion": 2018, 15 | "sourceType": "module", 16 | "project": "./tsconfig.dev.json" 17 | }, 18 | "extends": [ 19 | "plugin:import/typescript", 20 | "plugin:prettier/recommended" 21 | ], 22 | "settings": { 23 | "import/parsers": { 24 | "@typescript-eslint/parser": [ 25 | ".ts", 26 | ".tsx" 27 | ] 28 | }, 29 | "import/resolver": { 30 | "node": {}, 31 | "typescript": { 32 | "project": "./tsconfig.dev.json", 33 | "alwaysTryTypes": true 34 | } 35 | } 36 | }, 37 | "ignorePatterns": [ 38 | "**/node_modules/**", 39 | "**/test/imports/**", 40 | "!.projenrc.ts", 41 | "!projenrc/**/*.ts" 42 | ], 43 | "rules": { 44 | "curly": [ 45 | "error", 46 | "multi-line", 47 | "consistent" 48 | ], 49 | "@typescript-eslint/no-require-imports": "error", 50 | "import/no-extraneous-dependencies": [ 51 | "error", 52 | { 53 | "devDependencies": [ 54 | "**/test/**", 55 | "**/build-tools/**", 56 | ".projenrc.ts", 57 | "projenrc/**/*.ts" 58 | ], 59 | "optionalDependencies": false, 60 | "peerDependencies": true 61 | } 62 | ], 63 | "import/no-unresolved": [ 64 | "error" 65 | ], 66 | "import/order": [ 67 | "warn", 68 | { 69 | "groups": [ 70 | "builtin", 71 | "external" 72 | ], 73 | "alphabetize": { 74 | "order": "asc", 75 | "caseInsensitive": true 76 | } 77 | } 78 | ], 79 | "import/no-duplicates": [ 80 | "error" 81 | ], 82 | "no-shadow": [ 83 | "off" 84 | ], 85 | "@typescript-eslint/no-shadow": "error", 86 | "@typescript-eslint/no-floating-promises": "error", 87 | "no-return-await": [ 88 | "off" 89 | ], 90 | "@typescript-eslint/return-await": "error", 91 | "dot-notation": [ 92 | "error" 93 | ], 94 | "no-bitwise": [ 95 | "error" 96 | ], 97 | "@typescript-eslint/member-ordering": [ 98 | "error", 99 | { 100 | "default": [ 101 | "public-static-field", 102 | "public-static-method", 103 | "protected-static-field", 104 | "protected-static-method", 105 | "private-static-field", 106 | "private-static-method", 107 | "field", 108 | "constructor", 109 | "method" 110 | ] 111 | } 112 | ] 113 | }, 114 | "overrides": [ 115 | { 116 | "files": [ 117 | ".projenrc.ts" 118 | ], 119 | "rules": { 120 | "@typescript-eslint/no-require-imports": "off", 121 | "import/no-extraneous-dependencies": "off" 122 | } 123 | } 124 | ] 125 | } 126 | -------------------------------------------------------------------------------- /.github/workflows/upgrade-main.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: upgrade-main 4 | on: 5 | workflow_dispatch: {} 6 | schedule: 7 | - cron: 0 0 * * 1 8 | jobs: 9 | upgrade: 10 | name: Upgrade 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: read 14 | outputs: 15 | patch_created: ${{ steps.create_patch.outputs.patch_created }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 19 | with: 20 | ref: main 21 | - name: Install dependencies 22 | run: yarn install --check-files --frozen-lockfile 23 | - name: Upgrade dependencies 24 | run: npx projen upgrade 25 | - name: Find mutations 26 | id: create_patch 27 | run: |- 28 | git add . 29 | git diff --staged --patch --exit-code > repo.patch || echo "patch_created=true" >> $GITHUB_OUTPUT 30 | shell: bash 31 | working-directory: ./ 32 | - name: Upload patch 33 | if: steps.create_patch.outputs.patch_created 34 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 35 | with: 36 | name: repo.patch 37 | path: repo.patch 38 | overwrite: true 39 | pr: 40 | name: Create Pull Request 41 | needs: upgrade 42 | runs-on: ubuntu-latest 43 | permissions: 44 | contents: read 45 | if: ${{ needs.upgrade.outputs.patch_created }} 46 | steps: 47 | - name: Checkout 48 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 49 | with: 50 | ref: main 51 | - name: Download patch 52 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 53 | with: 54 | name: repo.patch 55 | path: ${{ runner.temp }} 56 | - name: Apply patch 57 | run: '[ -s ${{ runner.temp }}/repo.patch ] && git apply ${{ runner.temp }}/repo.patch || echo "Empty patch. Skipping."' 58 | - name: Set git identity 59 | run: |- 60 | git config user.name "team-tf-cdk" 61 | git config user.email "github-team-tf-cdk@hashicorp.com" 62 | - name: Create Pull Request 63 | id: create-pr 64 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e 65 | with: 66 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 67 | commit-message: |- 68 | chore(deps): upgrade dependencies 69 | 70 | Upgrades project dependencies. See details in [workflow run]. 71 | 72 | [Workflow Run]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 73 | 74 | ------ 75 | 76 | *Automatically created by projen via the "upgrade-main" workflow* 77 | branch: github-actions/upgrade-main 78 | title: "chore(deps): upgrade dependencies" 79 | labels: auto-approve,automerge,dependencies 80 | body: |- 81 | Upgrades project dependencies. See details in [workflow run]. 82 | 83 | [Workflow Run]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 84 | 85 | ------ 86 | 87 | *Automatically created by projen via the "upgrade-main" workflow* 88 | author: team-tf-cdk 89 | committer: team-tf-cdk 90 | signoff: true 91 | -------------------------------------------------------------------------------- /.github/workflows/upgrade-cdktf.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: upgrade-cdktf 4 | on: 5 | schedule: 6 | - cron: 55 */6 * * * 7 | workflow_dispatch: {} 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | jobs: 11 | upgrade: 12 | name: Upgrade CDKTF 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: read 16 | env: 17 | CI: "true" 18 | CHECKPOINT_DISABLE: "1" 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 22 | - name: Setup Node.js 23 | uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 24 | with: {} 25 | - name: Install 26 | run: yarn install 27 | - name: Get current CDKTF version 28 | id: current_version 29 | run: |- 30 | OLD_VERSION=$(npm list cdktf --depth=0 --json | jq -r '.dependencies.cdktf.version') 31 | OLD_VERSION_SHORT=$(cut -d "." -f 2 <<< "$OLD_VERSION") 32 | echo "value=$OLD_VERSION" >> $GITHUB_OUTPUT 33 | echo "short=$OLD_VERSION_SHORT" >> $GITHUB_OUTPUT 34 | - name: Get latest CDKTF version 35 | id: latest_version 36 | run: |- 37 | CDKTF_VERSION=$(yarn info cdktf --json | jq -r '.data.version') 38 | CDKTF_VERSION_SHORT=$(cut -d "." -f 2 <<< "$CDKTF_VERSION") 39 | CONSTRUCTS_VERSION=$(yarn info cdktf --json | jq -r '.data.peerDependencies.constructs') 40 | CONSTRUCTS_VERSION_EXACT=$(cut -d "^" -f 2 <<< "$CONSTRUCTS_VERSION") 41 | echo "value=$CDKTF_VERSION" >> $GITHUB_OUTPUT 42 | echo "short=$CDKTF_VERSION_SHORT" >> $GITHUB_OUTPUT 43 | echo "constructs=$CONSTRUCTS_VERSION_EXACT" >> $GITHUB_OUTPUT 44 | - name: Run upgrade script 45 | if: steps.current_version.outputs.short != steps.latest_version.outputs.short 46 | run: scripts/update-cdktf.sh ${{ steps.latest_version.outputs.value }} ${{ steps.latest_version.outputs.constructs }} 47 | - name: Create draft pull request 48 | if: steps.current_version.outputs.short != steps.latest_version.outputs.short 49 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e 50 | with: 51 | commit-message: "chore!: upgrade to cdktf ${{ steps.latest_version.outputs.value }}" 52 | branch: auto/upgrade-cdktf-${{ steps.latest_version.outputs.short }} 53 | base: main 54 | title: "chore!: upgrade to cdktf ${{ steps.latest_version.outputs.value }}" 55 | body: |- 56 | This PR initiates the upgrade of CDKTF from version `${{ steps.current_version.outputs.value }}` to version `${{ steps.latest_version.outputs.value }}`. 57 | Unfortunately, not everything can be automated, and the following steps need to be completed manually: 58 | 59 | - [ ] Update `@cdktf/provider-kubernetes` to a version compatible with `cdktf@${{ steps.latest_version.outputs.value }}` [here](https://github.com/cdktf/cdktf-cdk8s/blob/4d23de9f0dadddb922bf1c44079f08856491f11b/.projenrc.ts#L67). Look up the version [here](https://github.com/cdktf/cdktf-provider-kubernetes/releases/). 60 | - [ ] Run `npx projen` 61 | 62 | Please checkout this PR, complete the above steps, push the changes to this branch, and then mark this PR as ready for review to complete the upgrade. Thanks! 63 | labels: automerge,auto-approve,dependencies 64 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 65 | author: team-tf-cdk 66 | committer: team-tf-cdk 67 | signoff: true 68 | delete-branch: true 69 | draft: true 70 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdktf-cdk8s", 3 | "description": "A compatibility layer for using cdk8s constructs within Terraform CDK.", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/cdktf/cdktf-cdk8s.git" 7 | }, 8 | "scripts": { 9 | "build": "npx projen build", 10 | "bump": "npx projen bump", 11 | "clobber": "npx projen clobber", 12 | "compat": "npx projen compat", 13 | "compile": "npx projen compile", 14 | "default": "npx projen default", 15 | "eject": "npx projen eject", 16 | "eslint": "npx projen eslint", 17 | "package": "npx projen package", 18 | "package-all": "npx projen package-all", 19 | "package:js": "npx projen package:js", 20 | "package:python": "npx projen package:python", 21 | "post-compile": "npx projen post-compile", 22 | "post-upgrade": "npx projen post-upgrade", 23 | "pre-compile": "npx projen pre-compile", 24 | "release": "npx projen release", 25 | "test": "npx projen test", 26 | "test:watch": "npx projen test:watch", 27 | "unbump": "npx projen unbump", 28 | "upgrade": "npx projen upgrade", 29 | "watch": "npx projen watch", 30 | "projen": "npx projen" 31 | }, 32 | "author": { 33 | "name": "HashiCorp", 34 | "url": "https://hashicorp.com", 35 | "organization": true 36 | }, 37 | "devDependencies": { 38 | "@cdktf/provider-kubernetes": "12.0.0", 39 | "@types/jest": "^29", 40 | "@types/node": "ts5.8", 41 | "@typescript-eslint/eslint-plugin": "^8", 42 | "@typescript-eslint/parser": "^8", 43 | "cdk8s": "2.8.0", 44 | "cdk8s-cli": ">=2.3", 45 | "cdktf": "0.21.0", 46 | "commit-and-tag-version": "^12", 47 | "constructs": "10.4.2", 48 | "eslint": "^9", 49 | "eslint-config-prettier": "^8.10.2", 50 | "eslint-import-resolver-typescript": "^2.7.1", 51 | "eslint-plugin-import": "^2.32.0", 52 | "eslint-plugin-prettier": "^4.2.5", 53 | "jest": "^29", 54 | "jest-junit": "^16", 55 | "jsii": "~5.8.0", 56 | "jsii-diff": "^1.120.0", 57 | "jsii-pacmak": "^1.120.0", 58 | "jsii-rosetta": "~5.8.0", 59 | "prettier": "^2.8.8", 60 | "projen": "^0.98.28", 61 | "ts-jest": "^29.4.6", 62 | "ts-node": "10.9.1", 63 | "typescript": "~5.8.0" 64 | }, 65 | "peerDependencies": { 66 | "@cdktf/provider-kubernetes": ">=12.0.0", 67 | "cdk8s": ">=2.8.0", 68 | "cdktf": ">=0.21.0", 69 | "constructs": "^10.4.2" 70 | }, 71 | "dependencies": { 72 | "yaml": "2.3.4" 73 | }, 74 | "bundledDependencies": [ 75 | "yaml" 76 | ], 77 | "keywords": [ 78 | "cdk", 79 | "cdktf" 80 | ], 81 | "main": "lib/index.js", 82 | "license": "MPL-2.0", 83 | "publishConfig": { 84 | "access": "public" 85 | }, 86 | "version": "0.0.0", 87 | "jest": { 88 | "coverageProvider": "v8", 89 | "testMatch": [ 90 | "/@(src|test)/**/*(*.)@(spec|test).ts?(x)", 91 | "/@(src|test)/**/__tests__/**/*.ts?(x)", 92 | "/@(projenrc)/**/*(*.)@(spec|test).ts?(x)", 93 | "/@(projenrc)/**/__tests__/**/*.ts?(x)" 94 | ], 95 | "clearMocks": true, 96 | "collectCoverage": true, 97 | "coverageReporters": [ 98 | "json", 99 | "lcov", 100 | "clover", 101 | "cobertura", 102 | "text" 103 | ], 104 | "coverageDirectory": "coverage", 105 | "coveragePathIgnorePatterns": [ 106 | "/node_modules/" 107 | ], 108 | "testPathIgnorePatterns": [ 109 | "/node_modules/" 110 | ], 111 | "watchPathIgnorePatterns": [ 112 | "/node_modules/" 113 | ], 114 | "reporters": [ 115 | "default", 116 | [ 117 | "jest-junit", 118 | { 119 | "outputDirectory": "test-reports" 120 | } 121 | ] 122 | ], 123 | "transform": { 124 | "^.+\\.[t]sx?$": [ 125 | "ts-jest", 126 | { 127 | "tsconfig": "tsconfig.dev.json" 128 | } 129 | ] 130 | } 131 | }, 132 | "types": "lib/index.d.ts", 133 | "stability": "experimental", 134 | "jsii": { 135 | "outdir": "dist", 136 | "targets": { 137 | "python": { 138 | "distName": "cdktf-cdk8s", 139 | "module": "cdktf_cdk8s" 140 | } 141 | }, 142 | "tsc": { 143 | "outDir": "lib", 144 | "rootDir": "src" 145 | } 146 | }, 147 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 148 | } 149 | -------------------------------------------------------------------------------- /.projenrc.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { Stability } from "projen/lib/cdk"; 7 | import { ConstructLibraryCdktf } from "projen/lib/cdktf"; 8 | import { UpgradeDependenciesSchedule } from "projen/lib/javascript"; 9 | import { AutoApprove } from "./projenrc/auto-approve"; 10 | import { Automerge } from "./projenrc/automerge"; 11 | import { CustomizedLicense } from "./projenrc/customized-license"; 12 | import { UpgradeCDKTF } from "./projenrc/upgrade-cdktf"; 13 | import { UpgradeJSIIAndTypeScript } from "./projenrc/upgrade-jsii-typescript"; 14 | 15 | const name = "cdktf-cdk8s"; 16 | const constructsVersion = "10.4.2"; 17 | /** JSII and TS should always use the same major/minor version range */ 18 | const typescriptVersion = "~5.8.0"; 19 | 20 | const githubActionPinnedVersions = { 21 | "actions/checkout": "11bd71901bbe5b1630ceea73d27597364c9af683", // v4.2.2 22 | "actions/download-artifact": "95815c38cf2ff2164869cbab79da8d1f422bc89e", // v4.2.1 23 | "actions/github-script": "60a0d83039c74a4aee543508d2ffcb1c3799cdea", // v7.0.1 24 | "actions/setup-node": "cdca7365b2dadb8aad0a33bc7601856ffabcc48e", // v4.3.0 25 | "actions/setup-python": "42375524e23c412d93fb67b49958b491fce71c38", // v5.4.0 26 | "actions/upload-artifact": "ea165f8d65b6e75b540449e92b4886f43607fa02", // v4.6.2 27 | "amannn/action-semantic-pull-request": 28 | "0723387faaf9b38adef4775cd42cfd5155ed6017", // v5.5.3 29 | "hashicorp/setup-copywrite": "32638da2d4e81d56a0764aa1547882fc4d209636", // v1.1.3 30 | "peter-evans/create-pull-request": "271a8d0340265f705b14b6d32b9829c1cb33d45e", // v7.0.8 31 | }; 32 | 33 | const project = new ConstructLibraryCdktf({ 34 | name, 35 | repositoryUrl: "https://github.com/cdktf/cdktf-cdk8s.git", 36 | description: 37 | "A compatibility layer for using cdk8s constructs within Terraform CDK.", 38 | author: "HashiCorp", 39 | authorAddress: "https://hashicorp.com", 40 | authorOrganization: true, 41 | defaultReleaseBranch: "main", 42 | bundledDeps: ["yaml@2.3.4"], 43 | licensed: false, 44 | projenrcTs: true, 45 | prettier: true, 46 | eslintOptions: { 47 | dirs: ["src"], 48 | ignorePatterns: ["**/node_modules/**", "**/test/imports/**"], 49 | }, 50 | pullRequestTemplate: false, 51 | docgen: false, 52 | mergify: false, 53 | depsUpgradeOptions: { 54 | workflowOptions: { 55 | labels: ["auto-approve", "automerge", "dependencies"], 56 | schedule: UpgradeDependenciesSchedule.WEEKLY, 57 | }, 58 | }, 59 | workflowGitIdentity: { 60 | name: "team-tf-cdk", 61 | email: "github-team-tf-cdk@hashicorp.com", 62 | }, 63 | stability: Stability.EXPERIMENTAL, 64 | publishToPypi: { 65 | distName: name, 66 | module: name.replace(/-/g, "_"), 67 | }, 68 | cdktfVersion: "0.21.0", 69 | typescriptVersion, 70 | jsiiVersion: typescriptVersion, 71 | }); 72 | 73 | new CustomizedLicense(project); 74 | new AutoApprove(project); 75 | new Automerge(project); 76 | new UpgradeCDKTF(project); 77 | new UpgradeJSIIAndTypeScript(project, typescriptVersion); 78 | 79 | project.addPeerDeps( 80 | `constructs@^${constructsVersion}`, 81 | "@cdktf/provider-kubernetes@>=12.0.0", 82 | "cdk8s@>=2.8.0", 83 | "cdktf@>=0.21.0" 84 | ); 85 | 86 | project.addDevDeps("cdk8s-cli@>=2.3", "ts-node@10.9.1"); 87 | 88 | project.testTask.prependExec( 89 | `cd ./test && cdk8s import k8s --language typescript` 90 | ); 91 | 92 | project.addPackageIgnore("scripts"); 93 | project.addPackageIgnore("examples"); 94 | project.addPackageIgnore("projenrc"); 95 | project.addPackageIgnore("/.projenrc.ts"); 96 | 97 | project.addPackageIgnore(".copywrite.hcl"); 98 | // Run copywrite tool to add copyright headers to all files 99 | project.buildWorkflow?.addPostBuildSteps( 100 | { 101 | name: "Setup Copywrite tool", 102 | uses: "hashicorp/setup-copywrite", 103 | }, 104 | { name: "Add headers using Copywrite tool", run: "copywrite headers" } 105 | ); 106 | 107 | // Use pinned versions of github actions 108 | Object.entries(githubActionPinnedVersions).forEach(([action, sha]) => { 109 | project.github?.actions.set(action, `${action}@${sha}`); 110 | }); 111 | 112 | const releaseWorkflow = project.tryFindObjectFile( 113 | ".github/workflows/release.yml" 114 | ); 115 | releaseWorkflow?.addOverride("on.push", { 116 | branches: ["main"], 117 | "paths-ignore": [ 118 | // don't do a release if the change was only to these files/directories 119 | "examples/**", 120 | ".github/ISSUE_TEMPLATE/**", 121 | ".github/CODEOWNERS", 122 | ".github/dependabot.yml", 123 | ".github/**/*.md", 124 | ], 125 | }); 126 | // always publish a new GitHub release, even when publishing to a particular package manager fails 127 | releaseWorkflow?.addOverride("jobs.release_github.needs", "release"); 128 | 129 | project.synth(); 130 | -------------------------------------------------------------------------------- /.github/workflows/upgrade-jsii-typescript.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: upgrade-jsii-typescript 4 | on: 5 | schedule: 6 | - cron: 12 14 * * * 7 | workflow_dispatch: 8 | inputs: 9 | version: 10 | description: New JSII/TypeScript version (e.g. "5.8.0"), without carets or tildes 11 | required: false 12 | type: string 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | jobs: 16 | version: 17 | name: Determine version to upgrade to 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: read 21 | outputs: 22 | current: ${{ steps.current_version.outputs.value }} 23 | latest: ${{ steps.latest_version.outputs.value }} 24 | short: ${{ steps.latest_version.outputs.short }} 25 | should_upgrade: ${{ steps.latest_version.outputs.is_newer }} 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 29 | - name: Setup Node.js 30 | uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 31 | with: {} 32 | - name: Install 33 | run: yarn install 34 | - name: Get current JSII version 35 | id: current_version 36 | run: |- 37 | CURRENT_VERSION=$(npm list jsii --depth=0 --json | jq -r '.dependencies.jsii.version') 38 | CURRENT_VERSION_SHORT=$(cut -d "." -f 1,2 <<< "$CURRENT_VERSION") 39 | CURRENT_VERSION_MAJOR=$(cut -d "." -f 1 <<< "$CURRENT_VERSION") 40 | CURRENT_VERSION_MINOR=$(cut -d "." -f 2 <<< "$CURRENT_VERSION") 41 | echo "CURRENT_JSII_VERSION=$CURRENT_VERSION" >> $GITHUB_ENV 42 | echo "CURRENT_JSII_VERSION_SHORT=$CURRENT_VERSION_SHORT" >> $GITHUB_ENV 43 | echo "CURRENT_JSII_VERSION_MAJOR=$CURRENT_VERSION_MAJOR" >> $GITHUB_ENV 44 | echo "CURRENT_JSII_VERSION_MINOR=$CURRENT_VERSION_MINOR" >> $GITHUB_ENV 45 | echo "value=$CURRENT_VERSION" >> $GITHUB_OUTPUT 46 | - name: Get the earliest supported JSII version whose EOS date is at least a month away 47 | if: ${{ ! inputs.version }} 48 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea 49 | with: 50 | script: |- 51 | const script = require('./scripts/check-jsii-versions.js') 52 | await script({github, context, core}) 53 | - name: Save the manually-input version to environment variables for comparison 54 | if: ${{ inputs.version }} 55 | env: 56 | NEW_VERSION: ${{ inputs.version }} 57 | run: |- 58 | NEW_VERSION_SHORT=$(cut -d "." -f 1,2 <<< "$NEW_VERSION") 59 | NEW_VERSION_MAJOR=$(cut -d "." -f 1 <<< "$NEW_VERSION") 60 | NEW_VERSION_MINOR=$(cut -d "." -f 2 <<< "$NEW_VERSION") 61 | echo "NEW_JSII_VERSION=$NEW_VERSION" >> $GITHUB_ENV 62 | echo "NEW_JSII_VERSION_SHORT=$NEW_VERSION_SHORT" >> $GITHUB_ENV 63 | echo "NEW_JSII_VERSION_MAJOR=$NEW_VERSION_MAJOR" >> $GITHUB_ENV 64 | echo "NEW_JSII_VERSION_MINOR=$NEW_VERSION_MINOR" >> $GITHUB_ENV 65 | - name: Output env variables for use in the next job 66 | id: latest_version 67 | run: |- 68 | echo "value=$NEW_JSII_VERSION" >> $GITHUB_OUTPUT 69 | echo "short=$NEW_JSII_VERSION_SHORT" >> $GITHUB_OUTPUT 70 | [[ "$NEW_JSII_VERSION_MAJOR" > "$CURRENT_JSII_VERSION_MAJOR" || ("$NEW_JSII_VERSION_MAJOR" == "$CURRENT_JSII_VERSION_MAJOR" && "$NEW_JSII_VERSION_MINOR" > "$CURRENT_JSII_VERSION_MINOR") ]] && IS_NEWER=true 71 | echo "is_newer=$IS_NEWER" >> $GITHUB_OUTPUT 72 | upgrade: 73 | name: Upgrade JSII & TypeScript 74 | needs: version 75 | runs-on: ubuntu-latest 76 | permissions: 77 | contents: read 78 | env: 79 | CI: "true" 80 | CHECKPOINT_DISABLE: "1" 81 | if: always() && needs.version.outputs.should_upgrade 82 | steps: 83 | - name: Checkout 84 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 85 | - name: Setup Node.js 86 | uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 87 | with: {} 88 | - name: Install 89 | run: yarn install 90 | - name: Run upgrade script 91 | run: scripts/update-jsii-typescript.sh ${{ needs.version.outputs.latest }} 92 | - name: Create Pull Request 93 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e 94 | with: 95 | base: main 96 | branch: auto/upgrade-jsii-ts-${{ needs.version.outputs.short }} 97 | commit-message: "chore(deps): upgrade jsii & typescript to v${{ needs.version.outputs.short }}" 98 | title: "chore(deps): upgrade jsii & typescript to v${{ needs.version.outputs.short }}" 99 | body: "This PR increases the version of JSII and TypeScript to `~${{ needs.version.outputs.latest }}` because the previous version is close to EOL or no longer supported. Support timeline: https://github.com/aws/jsii-compiler/blob/main/README.md#gear-maintenance--support" 100 | labels: auto-approve,automerge,automated 101 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 102 | author: team-tf-cdk 103 | committer: team-tf-cdk 104 | signoff: true 105 | delete-branch: true 106 | -------------------------------------------------------------------------------- /projenrc/upgrade-cdktf.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { javascript } from "projen"; 7 | import { JobPermission } from "projen/lib/github/workflows-model"; 8 | 9 | /** 10 | * Checks for new versions of CDKTF and creates a PR with an upgrade change if there are changes. 11 | */ 12 | export class UpgradeCDKTF { 13 | constructor(project: javascript.NodeProject) { 14 | const workflow = project.github?.addWorkflow("upgrade-cdktf"); 15 | 16 | if (!workflow) throw new Error("no workflow defined"); 17 | 18 | workflow.on({ 19 | schedule: [{ cron: "55 */6 * * *" }], // Runs four times a day 20 | workflowDispatch: {}, // allow manual triggering 21 | }); 22 | 23 | (workflow.concurrency as any) = { 24 | group: "${{ github.workflow }}-${{ github.ref }}", 25 | }; 26 | 27 | workflow.addJobs({ 28 | upgrade: { 29 | name: "Upgrade CDKTF", 30 | runsOn: ["ubuntu-latest"], 31 | steps: [ 32 | { 33 | name: "Checkout", 34 | uses: "actions/checkout", 35 | }, 36 | { 37 | name: "Setup Node.js", 38 | uses: "actions/setup-node", 39 | with: { 40 | "node-version": project.minNodeVersion, 41 | }, 42 | }, 43 | { 44 | name: "Install", 45 | run: "yarn install", 46 | }, 47 | { 48 | name: "Get current CDKTF version", 49 | id: "current_version", 50 | run: [ 51 | `OLD_VERSION=$(npm list cdktf --depth=0 --json | jq -r '.dependencies.cdktf.version')`, 52 | `OLD_VERSION_SHORT=$(cut -d "." -f 2 <<< "$OLD_VERSION")`, 53 | `echo "value=$OLD_VERSION" >> $GITHUB_OUTPUT`, 54 | `echo "short=$OLD_VERSION_SHORT" >> $GITHUB_OUTPUT`, 55 | ].join("\n"), 56 | // NOTE: No, there is no good way to do this in Yarn, until (if) we upgrade to Yarn 2+ (see below) 57 | }, 58 | { 59 | name: "Get latest CDKTF version", 60 | id: "latest_version", 61 | run: [ 62 | `CDKTF_VERSION=$(yarn info cdktf --json | jq -r '.data.version')`, 63 | `CDKTF_VERSION_SHORT=$(cut -d "." -f 2 <<< "$CDKTF_VERSION")`, 64 | `CONSTRUCTS_VERSION=$(yarn info cdktf --json | jq -r '.data.peerDependencies.constructs')`, 65 | `CONSTRUCTS_VERSION_EXACT=$(cut -d "^" -f 2 <<< "$CONSTRUCTS_VERSION")`, // strip the caret off the beginning 66 | `echo "value=$CDKTF_VERSION" >> $GITHUB_OUTPUT`, 67 | `echo "short=$CDKTF_VERSION_SHORT" >> $GITHUB_OUTPUT`, 68 | `echo "constructs=$CONSTRUCTS_VERSION_EXACT" >> $GITHUB_OUTPUT`, 69 | ].join("\n"), 70 | // IMPORTANT: the above behavior changed in Yarn 2+; `yarn info` instead gives the version of the installed package 71 | // If/when we upgrade we'll likely want to switch to `yarn npm info`: https://yarnpkg.com/cli/npm/info 72 | }, 73 | { 74 | name: "Run upgrade script", 75 | if: "steps.current_version.outputs.short != steps.latest_version.outputs.short", 76 | run: "scripts/update-cdktf.sh ${{ steps.latest_version.outputs.value }} ${{ steps.latest_version.outputs.constructs }}", 77 | }, 78 | { 79 | name: "Create draft pull request", 80 | if: "steps.current_version.outputs.short != steps.latest_version.outputs.short", 81 | uses: "peter-evans/create-pull-request", 82 | with: { 83 | "commit-message": 84 | "chore!: upgrade to cdktf ${{ steps.latest_version.outputs.value }}", 85 | branch: 86 | "auto/upgrade-cdktf-${{ steps.latest_version.outputs.short }}", 87 | base: "main", 88 | title: 89 | "chore!: upgrade to cdktf ${{ steps.latest_version.outputs.value }}", 90 | body: [ 91 | "This PR initiates the upgrade of CDKTF from version `${{ steps.current_version.outputs.value }}` to version `${{ steps.latest_version.outputs.value }}`.", 92 | "Unfortunately, not everything can be automated, and the following steps need to be completed manually:", 93 | " ", 94 | "- [ ] Update `@cdktf/provider-kubernetes` to a version compatible with `cdktf@${{ steps.latest_version.outputs.value }}` [here](https://github.com/cdktf/cdktf-cdk8s/blob/4d23de9f0dadddb922bf1c44079f08856491f11b/.projenrc.ts#L67). Look up the version [here](https://github.com/cdktf/cdktf-provider-kubernetes/releases/).", 95 | "- [ ] Run `npx projen`", 96 | " ", 97 | "Please checkout this PR, complete the above steps, push the changes to this branch, and then mark this PR as ready for review to complete the upgrade. Thanks!", 98 | ].join("\n"), 99 | labels: "automerge,auto-approve,dependencies", 100 | token: "${{ secrets.PROJEN_GITHUB_TOKEN }}", 101 | author: "team-tf-cdk ", 102 | committer: "team-tf-cdk ", 103 | signoff: true, 104 | "delete-branch": true, 105 | draft: true, 106 | }, 107 | }, 108 | ], 109 | env: { 110 | CI: "true", 111 | CHECKPOINT_DISABLE: "1", 112 | }, 113 | permissions: { 114 | contents: JobPermission.READ, 115 | }, 116 | }, 117 | }); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: build 4 | on: 5 | pull_request: {} 6 | workflow_dispatch: {} 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: write 12 | outputs: 13 | self_mutation_happened: ${{ steps.self_mutation.outputs.self_mutation_happened }} 14 | env: 15 | CI: "true" 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 19 | with: 20 | ref: ${{ github.event.pull_request.head.ref }} 21 | repository: ${{ github.event.pull_request.head.repo.full_name }} 22 | - name: Install dependencies 23 | run: yarn install --check-files 24 | - name: build 25 | run: npx projen build 26 | - name: Setup Copywrite tool 27 | uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 28 | - name: Add headers using Copywrite tool 29 | run: copywrite headers 30 | - name: Find mutations 31 | id: self_mutation 32 | run: |- 33 | git add . 34 | git diff --staged --patch --exit-code > repo.patch || echo "self_mutation_happened=true" >> $GITHUB_OUTPUT 35 | shell: bash 36 | working-directory: ./ 37 | - name: Upload patch 38 | if: steps.self_mutation.outputs.self_mutation_happened 39 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 40 | with: 41 | name: repo.patch 42 | path: repo.patch 43 | overwrite: true 44 | - name: Fail build on mutation 45 | if: steps.self_mutation.outputs.self_mutation_happened 46 | run: |- 47 | echo "::error::Files were changed during build (see build log). If this was triggered from a fork, you will need to update your branch." 48 | cat repo.patch 49 | exit 1 50 | - name: Backup artifact permissions 51 | run: cd dist && getfacl -R . > permissions-backup.acl 52 | continue-on-error: true 53 | - name: Upload artifact 54 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 55 | with: 56 | name: build-artifact 57 | path: dist 58 | overwrite: true 59 | self-mutation: 60 | needs: build 61 | runs-on: ubuntu-latest 62 | permissions: 63 | contents: write 64 | if: always() && needs.build.outputs.self_mutation_happened && !(github.event.pull_request.head.repo.full_name != github.repository) 65 | steps: 66 | - name: Checkout 67 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 68 | with: 69 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }} 70 | ref: ${{ github.event.pull_request.head.ref }} 71 | repository: ${{ github.event.pull_request.head.repo.full_name }} 72 | - name: Download patch 73 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 74 | with: 75 | name: repo.patch 76 | path: ${{ runner.temp }} 77 | - name: Apply patch 78 | run: '[ -s ${{ runner.temp }}/repo.patch ] && git apply ${{ runner.temp }}/repo.patch || echo "Empty patch. Skipping."' 79 | - name: Set git identity 80 | run: |- 81 | git config user.name "team-tf-cdk" 82 | git config user.email "github-team-tf-cdk@hashicorp.com" 83 | - name: Push changes 84 | env: 85 | PULL_REQUEST_REF: ${{ github.event.pull_request.head.ref }} 86 | run: |- 87 | git add . 88 | git commit -s -m "chore: self mutation" 89 | git push origin "HEAD:$PULL_REQUEST_REF" 90 | package-js: 91 | needs: build 92 | runs-on: ubuntu-latest 93 | permissions: 94 | contents: read 95 | if: ${{ !needs.build.outputs.self_mutation_happened }} 96 | steps: 97 | - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 98 | with: 99 | node-version: lts/* 100 | - name: Download build artifacts 101 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 102 | with: 103 | name: build-artifact 104 | path: dist 105 | - name: Restore build artifact permissions 106 | run: cd dist && setfacl --restore=permissions-backup.acl 107 | continue-on-error: true 108 | - name: Checkout 109 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 110 | with: 111 | ref: ${{ github.event.pull_request.head.ref }} 112 | repository: ${{ github.event.pull_request.head.repo.full_name }} 113 | path: .repo 114 | - name: Install Dependencies 115 | run: cd .repo && yarn install --check-files --frozen-lockfile 116 | - name: Extract build artifact 117 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo 118 | - name: Move build artifact out of the way 119 | run: mv dist dist.old 120 | - name: Create js artifact 121 | run: cd .repo && npx projen package:js 122 | - name: Collect js artifact 123 | run: mv .repo/dist dist 124 | package-python: 125 | needs: build 126 | runs-on: ubuntu-latest 127 | permissions: 128 | contents: read 129 | if: ${{ !needs.build.outputs.self_mutation_happened }} 130 | steps: 131 | - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 132 | with: 133 | node-version: lts/* 134 | - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 135 | with: 136 | python-version: 3.x 137 | - name: Download build artifacts 138 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 139 | with: 140 | name: build-artifact 141 | path: dist 142 | - name: Restore build artifact permissions 143 | run: cd dist && setfacl --restore=permissions-backup.acl 144 | continue-on-error: true 145 | - name: Checkout 146 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 147 | with: 148 | ref: ${{ github.event.pull_request.head.ref }} 149 | repository: ${{ github.event.pull_request.head.repo.full_name }} 150 | path: .repo 151 | - name: Install Dependencies 152 | run: cd .repo && yarn install --check-files --frozen-lockfile 153 | - name: Extract build artifact 154 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo 155 | - name: Move build artifact out of the way 156 | run: mv dist dist.old 157 | - name: Create python artifact 158 | run: cd .repo && npx projen package:python 159 | - name: Collect python artifact 160 | run: mv .repo/dist dist 161 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: release 4 | on: 5 | push: 6 | branches: 7 | - main 8 | paths-ignore: 9 | - examples/** 10 | - .github/ISSUE_TEMPLATE/** 11 | - .github/CODEOWNERS 12 | - .github/dependabot.yml 13 | - .github/**/*.md 14 | workflow_dispatch: {} 15 | concurrency: 16 | group: ${{ github.workflow }} 17 | cancel-in-progress: false 18 | jobs: 19 | release: 20 | runs-on: ubuntu-latest 21 | permissions: 22 | contents: write 23 | outputs: 24 | latest_commit: ${{ steps.git_remote.outputs.latest_commit }} 25 | tag_exists: ${{ steps.check_tag_exists.outputs.exists }} 26 | env: 27 | CI: "true" 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 31 | with: 32 | fetch-depth: 0 33 | - name: Set git identity 34 | run: |- 35 | git config user.name "github-actions[bot]" 36 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 37 | - name: Install dependencies 38 | run: yarn install --check-files --frozen-lockfile 39 | - name: release 40 | run: npx projen release 41 | - name: Check if version has already been tagged 42 | id: check_tag_exists 43 | run: |- 44 | TAG=$(cat dist/releasetag.txt) 45 | ([ ! -z "$TAG" ] && git ls-remote -q --exit-code --tags origin $TAG && (echo "exists=true" >> $GITHUB_OUTPUT)) || (echo "exists=false" >> $GITHUB_OUTPUT) 46 | cat $GITHUB_OUTPUT 47 | - name: Check for new commits 48 | id: git_remote 49 | run: |- 50 | echo "latest_commit=$(git ls-remote origin -h ${{ github.ref }} | cut -f1)" >> $GITHUB_OUTPUT 51 | cat $GITHUB_OUTPUT 52 | shell: bash 53 | - name: Backup artifact permissions 54 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} 55 | run: cd dist && getfacl -R . > permissions-backup.acl 56 | continue-on-error: true 57 | - name: Upload artifact 58 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }} 59 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 60 | with: 61 | name: build-artifact 62 | path: dist 63 | overwrite: true 64 | release_github: 65 | name: Publish to GitHub Releases 66 | needs: release 67 | runs-on: ubuntu-latest 68 | permissions: 69 | contents: write 70 | if: needs.release.outputs.tag_exists != 'true' && needs.release.outputs.latest_commit == github.sha 71 | steps: 72 | - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 73 | with: 74 | node-version: lts/* 75 | - name: Download build artifacts 76 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 77 | with: 78 | name: build-artifact 79 | path: dist 80 | - name: Restore build artifact permissions 81 | run: cd dist && setfacl --restore=permissions-backup.acl 82 | continue-on-error: true 83 | - name: Release 84 | env: 85 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 86 | run: errout=$(mktemp); gh release create $(cat dist/releasetag.txt) -R $GITHUB_REPOSITORY -F dist/changelog.md -t $(cat dist/releasetag.txt) --target $GITHUB_SHA 2> $errout && true; exitcode=$?; if [ $exitcode -ne 0 ] && ! grep -q "Release.tag_name already exists" $errout; then cat $errout; exit $exitcode; fi 87 | release_npm: 88 | name: Publish to npm 89 | needs: release 90 | runs-on: ubuntu-latest 91 | permissions: 92 | id-token: write 93 | contents: read 94 | if: needs.release.outputs.tag_exists != 'true' && needs.release.outputs.latest_commit == github.sha 95 | steps: 96 | - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 97 | with: 98 | node-version: lts/* 99 | - name: Download build artifacts 100 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 101 | with: 102 | name: build-artifact 103 | path: dist 104 | - name: Restore build artifact permissions 105 | run: cd dist && setfacl --restore=permissions-backup.acl 106 | continue-on-error: true 107 | - name: Checkout 108 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 109 | with: 110 | path: .repo 111 | - name: Install Dependencies 112 | run: cd .repo && yarn install --check-files --frozen-lockfile 113 | - name: Extract build artifact 114 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo 115 | - name: Move build artifact out of the way 116 | run: mv dist dist.old 117 | - name: Create js artifact 118 | run: cd .repo && npx projen package:js 119 | - name: Collect js artifact 120 | run: mv .repo/dist dist 121 | - name: Release 122 | env: 123 | NPM_DIST_TAG: latest 124 | NPM_REGISTRY: registry.npmjs.org 125 | NPM_CONFIG_PROVENANCE: "true" 126 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 127 | run: npx -p publib@latest publib-npm 128 | release_pypi: 129 | name: Publish to PyPI 130 | needs: release 131 | runs-on: ubuntu-latest 132 | permissions: 133 | contents: read 134 | if: needs.release.outputs.tag_exists != 'true' && needs.release.outputs.latest_commit == github.sha 135 | steps: 136 | - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e 137 | with: 138 | node-version: lts/* 139 | - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 140 | with: 141 | python-version: 3.x 142 | - name: Download build artifacts 143 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e 144 | with: 145 | name: build-artifact 146 | path: dist 147 | - name: Restore build artifact permissions 148 | run: cd dist && setfacl --restore=permissions-backup.acl 149 | continue-on-error: true 150 | - name: Checkout 151 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 152 | with: 153 | path: .repo 154 | - name: Install Dependencies 155 | run: cd .repo && yarn install --check-files --frozen-lockfile 156 | - name: Extract build artifact 157 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo 158 | - name: Move build artifact out of the way 159 | run: mv dist dist.old 160 | - name: Create python artifact 161 | run: cd .repo && npx projen package:python 162 | - name: Collect python artifact 163 | run: mv .repo/dist dist 164 | - name: Release 165 | env: 166 | TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} 167 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} 168 | run: npx -p publib@latest publib-pypi 169 | -------------------------------------------------------------------------------- /examples/typescript/complex/jest.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 7 | /* 8 | * For a detailed explanation regarding each configuration property, visit: 9 | * https://jestjs.io/docs/configuration 10 | */ 11 | 12 | module.exports = { 13 | 14 | // All imported modules in your tests should be mocked automatically 15 | // automock: false, 16 | 17 | // Stop running tests after `n` failures 18 | // bail: 0, 19 | 20 | // The directory where Jest should store its cached dependency information 21 | // cacheDirectory: "/private/var/folders/z_/v03l33d55fb57nrr3b1q03ch0000gq/T/jest_dz", 22 | 23 | // Automatically clear mock calls and instances between every test 24 | clearMocks: true, 25 | 26 | // Indicates whether the coverage information should be collected while executing the test 27 | // collectCoverage: false, 28 | 29 | // An array of glob patterns indicating a set of files for which coverage information should be collected 30 | // collectCoverageFrom: undefined, 31 | 32 | // The directory where Jest should output its coverage files 33 | // coverageDirectory: undefined, 34 | 35 | // An array of regexp pattern strings used to skip coverage collection 36 | // coveragePathIgnorePatterns: [ 37 | // "/node_modules/" 38 | // ], 39 | 40 | // Indicates which provider should be used to instrument code for coverage 41 | coverageProvider: "v8", 42 | 43 | // A list of reporter names that Jest uses when writing coverage reports 44 | // coverageReporters: [ 45 | // "json", 46 | // "text", 47 | // "lcov", 48 | // "clover" 49 | // ], 50 | 51 | // An object that configures minimum threshold enforcement for coverage results 52 | // coverageThreshold: undefined, 53 | 54 | // A path to a custom dependency extractor 55 | // dependencyExtractor: undefined, 56 | 57 | // Make calling deprecated APIs throw helpful error messages 58 | // errorOnDeprecated: false, 59 | 60 | // Force coverage collection from ignored files using an array of glob patterns 61 | // forceCoverageMatch: [], 62 | 63 | // A path to a module which exports an async function that is triggered once before all test suites 64 | // globalSetup: undefined, 65 | 66 | // A path to a module which exports an async function that is triggered once after all test suites 67 | // globalTeardown: undefined, 68 | 69 | // A set of global variables that need to be available in all test environments 70 | // globals: {}, 71 | 72 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 73 | // maxWorkers: "50%", 74 | 75 | // An array of directory names to be searched recursively up from the requiring module's location 76 | // moduleDirectories: [ 77 | // "node_modules" 78 | // ], 79 | 80 | // An array of file extensions your modules use 81 | moduleFileExtensions: ["ts", "js", "json", "node"], 82 | 83 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 84 | // moduleNameMapper: {}, 85 | 86 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 87 | // modulePathIgnorePatterns: [], 88 | 89 | // Activates notifications for test results 90 | // notify: false, 91 | 92 | // An enum that specifies notification mode. Requires { notify: true } 93 | // notifyMode: "failure-change", 94 | 95 | // A preset that is used as a base for Jest's configuration 96 | preset: "ts-jest", 97 | 98 | // Run tests from one or more projects 99 | // projects: undefined, 100 | 101 | // Use this configuration option to add custom reporters to Jest 102 | // reporters: undefined, 103 | 104 | // Automatically reset mock state between every test 105 | // resetMocks: false, 106 | 107 | // Reset the module registry before running each individual test 108 | // resetModules: false, 109 | 110 | // A path to a custom resolver 111 | // resolver: undefined, 112 | 113 | // Automatically restore mock state between every test 114 | // restoreMocks: false, 115 | 116 | // The root directory that Jest should scan for tests and modules within 117 | // rootDir: undefined, 118 | 119 | // A list of paths to directories that Jest should use to search for files in 120 | // roots: [ 121 | // "" 122 | // ], 123 | 124 | // Allows you to use a custom runner instead of Jest's default test runner 125 | // runner: "jest-runner", 126 | 127 | // The paths to modules that run some code to configure or set up the testing environment before each test 128 | // setupFiles: [], 129 | 130 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 131 | setupFilesAfterEnv: ["/setup.js"], 132 | 133 | // The number of seconds after which a test is considered as slow and reported as such in the results. 134 | // slowTestThreshold: 5, 135 | 136 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 137 | // snapshotSerializers: [], 138 | 139 | // The test environment that will be used for testing 140 | testEnvironment: "node", 141 | 142 | // Options that will be passed to the testEnvironment 143 | // testEnvironmentOptions: {}, 144 | 145 | // Adds a location field to test results 146 | // testLocationInResults: false, 147 | 148 | // The glob patterns Jest uses to detect test files 149 | testMatch: [ 150 | "**/__tests__/**/*.ts", 151 | "**/?(*.)+(spec|test).ts" 152 | ], 153 | 154 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 155 | testPathIgnorePatterns: ["/node_modules/", ".d.ts", ".js"], 156 | 157 | // The regexp pattern or array of patterns that Jest uses to detect test files 158 | // testRegex: [], 159 | 160 | // This option allows the use of a custom results processor 161 | // testResultsProcessor: undefined, 162 | 163 | // This option allows use of a custom test runner 164 | // testRunner: "jest-circus/runner", 165 | 166 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 167 | // testURL: "http://localhost", 168 | 169 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 170 | // timers: "real", 171 | 172 | // A map from regular expressions to paths to transformers 173 | // transform: undefined, 174 | 175 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 176 | // transformIgnorePatterns: [ 177 | // "/node_modules/", 178 | // "\\.pnp\\.[^\\/]+$" 179 | // ], 180 | 181 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 182 | // unmockedModulePathPatterns: undefined, 183 | 184 | // Indicates whether each individual test should be reported during the run 185 | // verbose: undefined, 186 | 187 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 188 | // watchPathIgnorePatterns: [], 189 | 190 | // Whether to use watchman for file crawling 191 | // watchman: true, 192 | }; 193 | -------------------------------------------------------------------------------- /examples/typescript/hello-world/jest.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 7 | /* 8 | * For a detailed explanation regarding each configuration property, visit: 9 | * https://jestjs.io/docs/configuration 10 | */ 11 | 12 | module.exports = { 13 | 14 | // All imported modules in your tests should be mocked automatically 15 | // automock: false, 16 | 17 | // Stop running tests after `n` failures 18 | // bail: 0, 19 | 20 | // The directory where Jest should store its cached dependency information 21 | // cacheDirectory: "/private/var/folders/z_/v03l33d55fb57nrr3b1q03ch0000gq/T/jest_dz", 22 | 23 | // Automatically clear mock calls and instances between every test 24 | clearMocks: true, 25 | 26 | // Indicates whether the coverage information should be collected while executing the test 27 | // collectCoverage: false, 28 | 29 | // An array of glob patterns indicating a set of files for which coverage information should be collected 30 | // collectCoverageFrom: undefined, 31 | 32 | // The directory where Jest should output its coverage files 33 | // coverageDirectory: undefined, 34 | 35 | // An array of regexp pattern strings used to skip coverage collection 36 | // coveragePathIgnorePatterns: [ 37 | // "/node_modules/" 38 | // ], 39 | 40 | // Indicates which provider should be used to instrument code for coverage 41 | coverageProvider: "v8", 42 | 43 | // A list of reporter names that Jest uses when writing coverage reports 44 | // coverageReporters: [ 45 | // "json", 46 | // "text", 47 | // "lcov", 48 | // "clover" 49 | // ], 50 | 51 | // An object that configures minimum threshold enforcement for coverage results 52 | // coverageThreshold: undefined, 53 | 54 | // A path to a custom dependency extractor 55 | // dependencyExtractor: undefined, 56 | 57 | // Make calling deprecated APIs throw helpful error messages 58 | // errorOnDeprecated: false, 59 | 60 | // Force coverage collection from ignored files using an array of glob patterns 61 | // forceCoverageMatch: [], 62 | 63 | // A path to a module which exports an async function that is triggered once before all test suites 64 | // globalSetup: undefined, 65 | 66 | // A path to a module which exports an async function that is triggered once after all test suites 67 | // globalTeardown: undefined, 68 | 69 | // A set of global variables that need to be available in all test environments 70 | // globals: {}, 71 | 72 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 73 | // maxWorkers: "50%", 74 | 75 | // An array of directory names to be searched recursively up from the requiring module's location 76 | // moduleDirectories: [ 77 | // "node_modules" 78 | // ], 79 | 80 | // An array of file extensions your modules use 81 | moduleFileExtensions: ["ts", "js", "json", "node"], 82 | 83 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 84 | // moduleNameMapper: {}, 85 | 86 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 87 | // modulePathIgnorePatterns: [], 88 | 89 | // Activates notifications for test results 90 | // notify: false, 91 | 92 | // An enum that specifies notification mode. Requires { notify: true } 93 | // notifyMode: "failure-change", 94 | 95 | // A preset that is used as a base for Jest's configuration 96 | preset: "ts-jest", 97 | 98 | // Run tests from one or more projects 99 | // projects: undefined, 100 | 101 | // Use this configuration option to add custom reporters to Jest 102 | // reporters: undefined, 103 | 104 | // Automatically reset mock state between every test 105 | // resetMocks: false, 106 | 107 | // Reset the module registry before running each individual test 108 | // resetModules: false, 109 | 110 | // A path to a custom resolver 111 | // resolver: undefined, 112 | 113 | // Automatically restore mock state between every test 114 | // restoreMocks: false, 115 | 116 | // The root directory that Jest should scan for tests and modules within 117 | // rootDir: undefined, 118 | 119 | // A list of paths to directories that Jest should use to search for files in 120 | // roots: [ 121 | // "" 122 | // ], 123 | 124 | // Allows you to use a custom runner instead of Jest's default test runner 125 | // runner: "jest-runner", 126 | 127 | // The paths to modules that run some code to configure or set up the testing environment before each test 128 | // setupFiles: [], 129 | 130 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 131 | setupFilesAfterEnv: ["/setup.js"], 132 | 133 | // The number of seconds after which a test is considered as slow and reported as such in the results. 134 | // slowTestThreshold: 5, 135 | 136 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 137 | // snapshotSerializers: [], 138 | 139 | // The test environment that will be used for testing 140 | testEnvironment: "node", 141 | 142 | // Options that will be passed to the testEnvironment 143 | // testEnvironmentOptions: {}, 144 | 145 | // Adds a location field to test results 146 | // testLocationInResults: false, 147 | 148 | // The glob patterns Jest uses to detect test files 149 | testMatch: [ 150 | "**/__tests__/**/*.ts", 151 | "**/?(*.)+(spec|test).ts" 152 | ], 153 | 154 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 155 | testPathIgnorePatterns: ["/node_modules/", ".d.ts", ".js"], 156 | 157 | // The regexp pattern or array of patterns that Jest uses to detect test files 158 | // testRegex: [], 159 | 160 | // This option allows the use of a custom results processor 161 | // testResultsProcessor: undefined, 162 | 163 | // This option allows use of a custom test runner 164 | // testRunner: "jest-circus/runner", 165 | 166 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 167 | // testURL: "http://localhost", 168 | 169 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 170 | // timers: "real", 171 | 172 | // A map from regular expressions to paths to transformers 173 | // transform: undefined, 174 | 175 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 176 | // transformIgnorePatterns: [ 177 | // "/node_modules/", 178 | // "\\.pnp\\.[^\\/]+$" 179 | // ], 180 | 181 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 182 | // unmockedModulePathPatterns: undefined, 183 | 184 | // Indicates whether each individual test should be reported during the run 185 | // verbose: undefined, 186 | 187 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 188 | // watchPathIgnorePatterns: [], 189 | 190 | // Whether to use watchman for file crawling 191 | // watchman: true, 192 | }; 193 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Future of Terraform CDK 2 | 3 | ## Sunset Notice 4 | 5 | Terraform CDK (CDKTF) will sunset and be archived on December 10, 2025. HashiCorp, an IBM Company, will no longer maintain or develop the project after that date. Unfortunately, Terraform CDK did not find product-market fit at scale. HashiCorp, an IBM Company, has chosen to focus its investments on Terraform core and its broader ecosystem. 6 | 7 | As of December 10, 2025, Terraform CDK will be archived on GitHub, and the documentation will reflect its deprecated status. The archived code will remain available on GitHub, but it will be read-only. No further updates, fixes, or improvements (including compatibility updates) will be made. 8 | 9 | You will be able to continue to use Terraform CDK at your own risk. Terraform CDK is licensed under the Mozilla Public License (MPL). HashiCorp, an IBM Company, does not apply any additional restrictions. We encourage community forks if there’s interest in continuing development independently. 10 | 11 | ## Migration to HCL 12 | 13 | You can use the following command to generate Terraform-compatible .tf files directly from your Terraform CDK project: 14 | 15 | `cdktf synth --hcl` 16 | 17 | This will produce readable HCL configuration files, making it easier to migrate away from Terraform CDK. After running the command, you can use standard Terraform CLI commands (`terraform init`, `terraform plan`, `terraform apply`) to continue managing your infrastructure. Please note that while this helps bootstrap your configuration, you may still need to review and adjust the generated files for clarity, organization, or best practices. 18 | 19 | ### Note on AWS CDK 20 | 21 | If your infrastructure is defined in Terraform CDK but also tightly integrated with AWS CDK, you may find it more consistent to migrate directly to the AWS CDK ecosystem. If you are not using AWS CDK, we highly recommend migrating to standard Terraform and HCL for long-term support and ecosystem alignment. 22 | 23 | ## FAQ 24 | 25 | Q: Is CDKTF still being developed? 26 | 27 | A: No. CDKTF will sunset and be archived on December 10, 2025. HashiCorp, an IBM Company, will no longer maintain or develop the project after that date. 28 | 29 | Q: Why is CDKTF being sunset? 30 | 31 | A: CDKTF did not find product-market fit at scale. We’ve chosen to focus our investments on Terraform core and its broader ecosystem. 32 | 33 | Q: Will CDKTF be removed from GitHub? 34 | 35 | A: CDKTF will be archived on GitHub, and documentation will reflect its deprecated status. 36 | 37 | Q: Can I still use CDKTF after it's sunset? 38 | 39 | A: Yes, the archived code will remain available on GitHub, but it will be read-only. No further updates, fixes, or improvements will be made. 40 | 41 | Q: Will CDKTF continue to support new versions of Terraform or providers? 42 | 43 | A: No. Compatibility updates will not be made after the EOL date. 44 | 45 | Q: Can I fork CDKTF and maintain it myself? 46 | 47 | A: Yes. CDKTF is open source, and we encourage community forks if there’s interest in continuing development independently. 48 | 49 | Q: Can I keep using CDKTF? 50 | 51 | A: You may continue to use it at your own risk. HashiCorp, an IBM Company, will no longer be maintaining it. 52 | 53 | Q: Is there a migration tool? 54 | 55 | A: You can use the following command to generate Terraform-compatible .tf files directly from your CDKTF project: 56 | 57 | `cdktf synth --hcl` 58 | 59 | This will produce readable HCL configuration files, making it easier to migrate away from CDKTF. After running the command, you can use standard Terraform CLI commands (terraform init, terraform plan, terraform apply) to continue managing your infrastructure. Please note that while this helps bootstrap your configuration, you may still need to review and adjust the generated files for clarity, organization, or best practices. 60 | 61 | Q: What migration guidance can we provide to customers? 62 | 63 | A: For users looking to migrate away from CDKTF: 64 | 65 | If your infrastructure is defined in CDKTF but also tightly integrated with AWS CDK, you may find it more consistent to migrate directly to the AWS CDK ecosystem. 66 | 67 | If you are not using AWS CDK, we highly recommend migrating to standard Terraform and HCL for long-term support and ecosystem alignment. 68 | 69 | --- 70 | 71 | # CDKTF CDK8s 72 | 73 | ![Status: Tech Preview](https://img.shields.io/badge/status-experimental-EAAA32) [![Releases](https://img.shields.io/github/release/cdktf/cdktf-cdk8s.svg)](https://github.com/cdktf/cdktf-cdk8s/releases) 74 | [![LICENSE](https://img.shields.io/github/license/cdktf/cdktf-cdk8s.svg)](https://github.com/cdktf/cdktf-cdk8s/blob/main/LICENSE) 75 | [![build](https://github.com/cdktf/cdktf-cdk8s/actions/workflows/build.yml/badge.svg)](https://github.com/cdktf/cdktf-cdk8s/actions/workflows/build.yml) 76 | 77 | A compatibility layer for using [cdk8s](https://cdk8s.io/) constructs within Terraform CDK. 78 | 79 | The cdk8s adapter is in technical preview, which means it's a community supported project. It still requires extensive testing and polishing to mature into a HashiCorp officially supported project. Please [file issues](https://github.com/cdktf/cdktf-cdk8s/issues/new/choose) generously and detail your experience while using the library. We welcome your feedback. 80 | 81 | By using the software in this repository, you acknowledge that: 82 | * The cdk8s adapter is still in development, may change, and has not been released as a commercial product by HashiCorp and is not currently supported in any way by HashiCorp. 83 | * The cdk8s adapter is provided on an "as-is" basis, and may include bugs, errors, or other issues. 84 | * The cdk8s adapter is NOT INTENDED FOR PRODUCTION USE, use of the Software may result in unexpected results, loss of data, or other unexpected results, and HashiCorp disclaims any and all liability resulting from use of the cdk8s adapter. 85 | * HashiCorp reserves all rights to make all decisions about the features, functionality and commercial release (or non-release) of the cdk8s adapter, at any time and without any obligation or liability whatsoever. 86 | 87 | ## Compatibility 88 | 89 | - `cdktf` >= 0.21.0 90 | - `cdk8s` >= 2.8.0 91 | - `constructs` >= 10.4.2 92 | 93 | ## Usage 94 | 95 | ```ts 96 | import { App, TerraformStack } from "cdktf"; 97 | import { App as CDK8sApp, Chart } from "cdk8s"; 98 | import { CDK8sProvider } from "cdktf-cdk8s"; 99 | 100 | import { MyCdk8sChart } from "./my-cdk8s-chart"; 101 | 102 | export class MyKubernetesStack extends TerraformStack { 103 | constructor(scope: Construct, name: string) { 104 | super(scope, name); 105 | 106 | const cdk8sApp = new CDK8sApp(); 107 | 108 | // Configure your cdk8s application like usual 109 | new HelloKube(cdk8sApp, "my-chart"); 110 | 111 | // For properties see https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs 112 | // Extends on the Provider class from @cdktf/provider-kubernetes 113 | new CDK8sProvider(this, "cdk8s-dev", { 114 | configPath: "./kubeconfig.yaml", 115 | configContext: "my-dev-cluster", 116 | 117 | // Only the cdk8sApp property is added 118 | // There is no need to run synth on the cdk8sApp, this is done by the provider 119 | cdk8sApp, 120 | }); 121 | } 122 | } 123 | 124 | const app = new App(); 125 | new MyStack(app, "cdktf-cdk8s"); 126 | app.synth(); 127 | ``` 128 | 129 | ## Contributing 130 | 131 | We welcome your contribution. Please understand that the experimental nature of this repository means that contributing code may be a bit of a moving target. If you have an idea for an enhancement or bug fix, and want to take on the work yourself, please first [create an issue](https://github.com/cdktf/cdktf-cdk8s/issues/new/choose) so that we can discuss the implementation with you before you proceed with the work. 132 | 133 | You can review our [contribution guide](https://github.com/cdktf/.github/blob/main/CONTRIBUTING.md) to begin. 134 | -------------------------------------------------------------------------------- /.github/MAINTENANCE.md: -------------------------------------------------------------------------------- 1 | # Maintenance Guide 2 | 3 | This document is intended for maintainers of this repository and outlines how to perform various maintenance-related activities, including descriptions of what processes are currently automated and which are not (yet). 4 | 5 | This repository contains extensive GitHub Actions [workflows](https://github.com/cdktf/cdktf-cdk8s/tree/main/.github/workflows) that automate as much of the project's lifecycle as possible. The project is built using [Projen](https://projen.io/) and as such **these workflows should not be edited directly**. Their sources can be found in the [`.projenrc/`](https://github.com/cdktf/cdktf-cdk8s/tree/main/projenrc) directory, and new workflows are added to the project in [`.projenrc.ts`](https://github.com/cdktf/cdktf-cdk8s/blob/main/.projenrc.ts). 6 | 7 | This project is considered experimental, and does not offer any support or maintenance guarantees. 8 | 9 | 10 | ## Security & Dependency Management 11 | 12 | Dependency upgrades (for security purposes as well as a best practice) can be divided into three categories: fully-automated, semi-automated, and not automated. 13 | 14 | ### Fully Automated 15 | 16 | The following Actions exist to automate various dependency upgrades: 17 | 18 | - [upgrade-jsii-typescript](https://github.com/cdktf/cdktf-cdk8s/actions/workflows/upgrade-jsii-typescript.yml): This is a custom workflow (source [here](https://github.com/cdktf/cdktf-cdk8s/blob/main/projenrc/upgrade-jsii-typescript.ts)) that checks the [JSII support timeline](https://github.com/aws/jsii-compiler/blob/main/README.md#gear-maintenance--support) daily via [this](https://github.com/cdktf/cdktf-cdk8s/blob/main/scripts/check-jsii-versions.js) script to see if the current version is less than 30 days away from EOS, and if so, creates a PR upgrading to the next supported version. The code for the upgrade itself lives in [this](https://github.com/cdktf/cdktf-cdk8s/blob/main/scripts/update-jsii-typescript.sh) script. This process is 100% automated; as long as the build succeeds and any tests pass, the PR will be automatically merged without any human intervention. 19 | - This workflow can also be manually triggered, optionally taking a hard-coded JSII/TypeScript version as input in case we ever want to upgrade to a newer version without waiting until the old one is less than 30 days away from EOS. 20 | - [upgrade-main](https://github.com/cdktf/cdktf-cdk8s/actions/workflows/upgrade-main.yml): This is a Projen built-in/default workflow that handles automated dependency updates. It currently runs on a weekly basis, which can be configured [here](https://github.com/cdktf/cdktf-cdk8s/blob/341c9668dcf16c80fc999f852244c7119914e5f9/.projenrc.ts#L55). Projen will upgrade itself as part of this process. This process is 100% automated; as long as the build succeeds and any tests pass, the PR that is generated will be automatically merged without any human intervention. 21 | 22 | Dependabot is also [configured](https://github.com/cdktf/cdktf-cdk8s/blob/main/.github/dependabot.yml) to check for new security updates daily and, if found, make changes to the lockfile only. This is because Dependabot can sometimes address security issues in dependencies more quickly than Projen due to its atomic nature. While you could tweak the Dependabot settings, note that Projen and Dependabot do not generally play nicely together; in particular, Dependabot cannot make changes to `package.json` because Projen would just override these changes (hence the reason why Dependabot is currently limited to lockfile-only). If you wanted to fully automate dependency management using Dependabot, you would want to disable Projen's [automatic updates](https://projen.io/docs/api/typescript#projen.typescript.TypeScriptProjectOptions.property.depsUpgrade). 23 | 24 | ### Semi-Automated 25 | 26 | The following Actions either need to be manually triggered or require significant manual effort as part of the upgrade process: 27 | 28 | - [upgrade-cdktf](https://github.com/cdktf/cdktf-cdk8s/actions/workflows/upgrade-cdktf.yml): This is a custom workflow (source [here](https://github.com/cdktf/cdktf-cdk8s/blob/main/projenrc/upgrade-cdktf.ts)) that runs four times a day and checks whether there is a new minor version of CDKTF itself (e.g. `0.19`, `0.20`, `0.21`, etc.), using the latest version published to npm as the source of truth. If a new version is found, it runs [this](https://github.com/cdktf/cdktf-cdk8s/blob/main/scripts/update-cdktf.sh) script to update the CDKTF version in all the right places, and then it creates a draft PR. The reason for the draft status is because a few steps related to the upgrade cannot be automated and must be done manually by an engineer; these are outlined step-by-step in the PR body. Once the steps are completed, the PR can be marked as ready for review & approved in order to complete the upgrade. 29 | 30 | ### Not Automated 31 | 32 | - **GitHub Actions version pinning**: Because this project leverages Projen, HashiCorp Security's [tsccr-helper](https://github.com/hashicorp/security-tsccr?tab=readme-ov-file#tsccr-helper-cli) CLI and other tooling cannot be used to manage/upgrade GitHub Actions versions. Instead, we have consolidated all of the versions into a single [object](https://github.com/cdktf/cdktf-cdk8s/blob/341c9668dcf16c80fc999f852244c7119914e5f9/.projenrc.ts#L19-L30) in code that must be manually updated. Historically, one of the maintainers has followed these manual steps on a roughly monthly basis: 33 | 1. Look up the latest supported versions [here](https://github.com/hashicorp/security-tsccr/tree/main/components/github_actions) 34 | 2. Update the [object](https://github.com/cdktf/cdktf-cdk8s/blob/341c9668dcf16c80fc999f852244c7119914e5f9/.projenrc.ts#L19-L30) 35 | 3. Run `npx projen` 36 | 4. Create a new PR with the title `chore(deps): update pinned versions of GitHub Actions` 37 | - **`cdk8s` library upgrades**: Because `cdk8s` is a peer dependency, the `upgrade-main` script described above will _never_ increment its version; this will always need to be done manually by [editing](https://github.com/cdktf/cdktf-cdk8s/blob/341c9668dcf16c80fc999f852244c7119914e5f9/.projenrc.ts#L81) `.projenrc.ts`. This could _in theory_ be (semi)automated like some of our other upgrade workflows described above for things like CDKTF, Node, and JSII, but in practice we currently have no logic or criteria that governs when `cdk8s` should be updated; as such, creating a custom workflow for it felt like more effort than it's really worth. 38 | 39 | Also worth noting: Unlike many of our other Projen-based projects, this one does not have a script that automatically upgrades Node.js because this library does not enforce a `minNodeVersion`. If we did at some point want to start enforcing a `minNodeVersion`, we should copy over the `upgrade-node` script that our other Projen projects use. 40 | 41 | 42 | ## Releasing 43 | 44 | Releases are fully automated by Projen and require no manual intervention whatsoever. In general, this repository is configured to publish a new release for each pull request that gets merged. The only way to force it to create one release that combines multiple merged PRs is to ensure that all of these PRs get merged into `main` at exactly the same time. The new version number is automatically calculated by Projen using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) and [Semantic Versioning](https://semver.org/). 45 | 46 | If you wanted to change the logic that governs when releases are triggered (such as running them on a schedule, or only for certain types of commits), see Projen's [documentation](https://projen.io/docs/publishing/releases-and-versioning) on this subject. 47 | 48 | ### Package Managers 49 | 50 | This library is currently published to these package managers: 51 | 52 | - **npm**: The package is called [cdktf-cdk8s](https://www.npmjs.com/package/cdktf-cdk8s), and publishing is done using an access token associated with the shared [cdktf-team](https://www.npmjs.com/~cdktf-team) account. Credentials to access this account can be found in the CDK for Terraform Team 1Password Vault. 53 | - **PyPi**: The package is called [cdktf-cdk8s](https://pypi.org/project/cdktf-cdk8s), and publishing is done using an access token associated with the shared [cdktf-team](https://pypi.org/user/cdktf-team/) account. Credentials to access this account can be found in the CDK for Terraform Team 1Password Vault. 54 | -------------------------------------------------------------------------------- /projenrc/upgrade-jsii-typescript.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { javascript } from "projen"; 7 | import { JobPermission } from "projen/lib/github/workflows-model"; 8 | 9 | /** 10 | * Helper script for upgrading JSII and TypeScript in the right way. 11 | * Auto-updates to the next version a month before the previous JSII version goes EOS 12 | * Can also be triggered manually with a hard-coded version of JSII/TypeScript as input 13 | * https://github.com/aws/jsii-compiler/blob/main/README.md#gear-maintenance--support 14 | */ 15 | export class UpgradeJSIIAndTypeScript { 16 | constructor(project: javascript.NodeProject, typescriptVersion: string) { 17 | const workflow = project.github?.addWorkflow("upgrade-jsii-typescript"); 18 | if (!workflow) throw new Error("no workflow defined"); 19 | 20 | const plainVersion = typescriptVersion.replace("~", ""); 21 | workflow.on({ 22 | schedule: [{ cron: "12 14 * * *" }], // Runs once a day 23 | workflowDispatch: { 24 | inputs: { 25 | version: { 26 | description: `New JSII/TypeScript version (e.g. "${plainVersion}"), without carets or tildes`, 27 | required: false, 28 | type: "string", 29 | }, 30 | }, 31 | }, 32 | }); 33 | 34 | (workflow.concurrency as any) = { 35 | group: "${{ github.workflow }}-${{ github.ref }}", 36 | }; 37 | 38 | workflow.addJobs({ 39 | version: { 40 | name: "Determine version to upgrade to", 41 | runsOn: ["ubuntu-latest"], 42 | steps: [ 43 | { 44 | name: "Checkout", 45 | uses: "actions/checkout", 46 | }, 47 | { 48 | name: "Setup Node.js", 49 | uses: "actions/setup-node", 50 | with: { 51 | "node-version": project.minNodeVersion, 52 | }, 53 | }, 54 | { 55 | name: "Install", 56 | run: "yarn install", 57 | }, 58 | { 59 | name: "Get current JSII version", 60 | id: "current_version", 61 | run: [ 62 | `CURRENT_VERSION=$(npm list jsii --depth=0 --json | jq -r '.dependencies.jsii.version')`, 63 | `CURRENT_VERSION_SHORT=$(cut -d "." -f 1,2 <<< "$CURRENT_VERSION")`, 64 | `CURRENT_VERSION_MAJOR=$(cut -d "." -f 1 <<< "$CURRENT_VERSION")`, 65 | `CURRENT_VERSION_MINOR=$(cut -d "." -f 2 <<< "$CURRENT_VERSION")`, 66 | `echo "CURRENT_JSII_VERSION=$CURRENT_VERSION" >> $GITHUB_ENV`, 67 | `echo "CURRENT_JSII_VERSION_SHORT=$CURRENT_VERSION_SHORT" >> $GITHUB_ENV`, 68 | `echo "CURRENT_JSII_VERSION_MAJOR=$CURRENT_VERSION_MAJOR" >> $GITHUB_ENV`, 69 | `echo "CURRENT_JSII_VERSION_MINOR=$CURRENT_VERSION_MINOR" >> $GITHUB_ENV`, 70 | `echo "value=$CURRENT_VERSION" >> $GITHUB_OUTPUT`, 71 | ].join("\n"), 72 | }, 73 | { 74 | name: "Get the earliest supported JSII version whose EOS date is at least a month away", 75 | if: "${{ ! inputs.version }}", 76 | uses: "actions/github-script", 77 | with: { 78 | script: [ 79 | `const script = require('./scripts/check-jsii-versions.js')`, 80 | `await script({github, context, core})`, 81 | ].join("\n"), 82 | }, 83 | }, 84 | { 85 | // In an ideal world this is where we'd validate that the manually-input version actually exists 86 | // In practice, I couldn't figure out how to do this properly and it wasn't worth the effort 87 | // name: "Check if the manually-input version actually exists (has been published to NPM)", 88 | name: "Save the manually-input version to environment variables for comparison", 89 | if: "${{ inputs.version }}", 90 | env: { 91 | NEW_VERSION: "${{ inputs.version }}", 92 | }, 93 | run: [ 94 | // My command line skillz aren't good enough to figure out how to make the below work (error if the version doesn't exist) 95 | // `yarn info jsii versions --json | jq -e 'select(.data | index("$NEW_VERSION"))`, 96 | `NEW_VERSION_SHORT=$(cut -d "." -f 1,2 <<< "$NEW_VERSION")`, 97 | `NEW_VERSION_MAJOR=$(cut -d "." -f 1 <<< "$NEW_VERSION")`, 98 | `NEW_VERSION_MINOR=$(cut -d "." -f 2 <<< "$NEW_VERSION")`, 99 | `echo "NEW_JSII_VERSION=$NEW_VERSION" >> $GITHUB_ENV`, 100 | `echo "NEW_JSII_VERSION_SHORT=$NEW_VERSION_SHORT" >> $GITHUB_ENV`, 101 | `echo "NEW_JSII_VERSION_MAJOR=$NEW_VERSION_MAJOR" >> $GITHUB_ENV`, 102 | `echo "NEW_JSII_VERSION_MINOR=$NEW_VERSION_MINOR" >> $GITHUB_ENV`, 103 | ].join("\n"), 104 | }, 105 | { 106 | name: "Output env variables for use in the next job", 107 | id: "latest_version", 108 | run: [ 109 | `echo "value=$NEW_JSII_VERSION" >> $GITHUB_OUTPUT`, 110 | `echo "short=$NEW_JSII_VERSION_SHORT" >> $GITHUB_OUTPUT`, 111 | `[[ "$NEW_JSII_VERSION_MAJOR" > "$CURRENT_JSII_VERSION_MAJOR" || ("$NEW_JSII_VERSION_MAJOR" == "$CURRENT_JSII_VERSION_MAJOR" && "$NEW_JSII_VERSION_MINOR" > "$CURRENT_JSII_VERSION_MINOR") ]] && IS_NEWER=true`, 112 | `echo "is_newer=$IS_NEWER" >> $GITHUB_OUTPUT`, 113 | ].join("\n"), 114 | }, 115 | ], 116 | outputs: { 117 | current: { 118 | stepId: "current_version", 119 | outputName: "value", 120 | }, 121 | latest: { 122 | stepId: "latest_version", 123 | outputName: "value", 124 | }, 125 | short: { 126 | stepId: "latest_version", 127 | outputName: "short", 128 | }, 129 | should_upgrade: { 130 | stepId: "latest_version", 131 | outputName: "is_newer", 132 | }, 133 | }, 134 | permissions: { 135 | contents: JobPermission.READ, 136 | }, 137 | }, 138 | upgrade: { 139 | name: "Upgrade JSII & TypeScript", 140 | runsOn: ["ubuntu-latest"], 141 | needs: ["version"], 142 | if: "always() && needs.version.outputs.should_upgrade", 143 | steps: [ 144 | { 145 | name: "Checkout", 146 | uses: "actions/checkout", 147 | }, 148 | { 149 | name: "Setup Node.js", 150 | uses: "actions/setup-node", 151 | with: { 152 | "node-version": project.minNodeVersion, 153 | }, 154 | }, 155 | { 156 | name: "Install", 157 | run: "yarn install", 158 | }, 159 | { 160 | name: "Run upgrade script", 161 | run: "scripts/update-jsii-typescript.sh ${{ needs.version.outputs.latest }}", 162 | }, 163 | { 164 | name: "Create Pull Request", 165 | uses: "peter-evans/create-pull-request", 166 | with: { 167 | base: "main", 168 | branch: "auto/upgrade-jsii-ts-${{ needs.version.outputs.short }}", 169 | "commit-message": 170 | "chore(deps): upgrade jsii & typescript to v${{ needs.version.outputs.short }}", 171 | title: 172 | "chore(deps): upgrade jsii & typescript to v${{ needs.version.outputs.short }}", 173 | body: [ 174 | "This PR increases the version of JSII and TypeScript to `~${{ needs.version.outputs.latest }}` ", 175 | "because the previous version is close to EOL or no longer supported. Support timeline: ", 176 | "https://github.com/aws/jsii-compiler/blob/main/README.md#gear-maintenance--support", 177 | ].join(" "), 178 | labels: "auto-approve,automerge,automated", 179 | token: "${{ secrets.PROJEN_GITHUB_TOKEN }}", 180 | author: "team-tf-cdk ", 181 | committer: "team-tf-cdk ", 182 | signoff: true, 183 | "delete-branch": true, 184 | }, 185 | }, 186 | ], 187 | env: { 188 | CI: "true", 189 | CHECKPOINT_DISABLE: "1", 190 | }, 191 | permissions: { 192 | contents: JobPermission.READ, 193 | }, 194 | }, 195 | }); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /.projen/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "build": { 4 | "name": "build", 5 | "description": "Full release build", 6 | "steps": [ 7 | { 8 | "spawn": "default" 9 | }, 10 | { 11 | "spawn": "pre-compile" 12 | }, 13 | { 14 | "spawn": "compile" 15 | }, 16 | { 17 | "spawn": "post-compile" 18 | }, 19 | { 20 | "spawn": "test" 21 | }, 22 | { 23 | "spawn": "package" 24 | } 25 | ] 26 | }, 27 | "bump": { 28 | "name": "bump", 29 | "description": "Bumps version based on latest git tag and generates a changelog entry", 30 | "env": { 31 | "OUTFILE": "package.json", 32 | "CHANGELOG": "dist/changelog.md", 33 | "BUMPFILE": "dist/version.txt", 34 | "RELEASETAG": "dist/releasetag.txt", 35 | "RELEASE_TAG_PREFIX": "", 36 | "BUMP_PACKAGE": "commit-and-tag-version@^12" 37 | }, 38 | "steps": [ 39 | { 40 | "builtin": "release/bump-version" 41 | } 42 | ], 43 | "condition": "git log --oneline -1 | grep -qv \"chore(release):\"" 44 | }, 45 | "clobber": { 46 | "name": "clobber", 47 | "description": "hard resets to HEAD of origin and cleans the local repo", 48 | "env": { 49 | "BRANCH": "$(git branch --show-current)" 50 | }, 51 | "steps": [ 52 | { 53 | "exec": "git checkout -b scratch", 54 | "name": "save current HEAD in \"scratch\" branch" 55 | }, 56 | { 57 | "exec": "git checkout $BRANCH" 58 | }, 59 | { 60 | "exec": "git fetch origin", 61 | "name": "fetch latest changes from origin" 62 | }, 63 | { 64 | "exec": "git reset --hard origin/$BRANCH", 65 | "name": "hard reset to origin commit" 66 | }, 67 | { 68 | "exec": "git clean -fdx", 69 | "name": "clean all untracked files" 70 | }, 71 | { 72 | "say": "ready to rock! (unpushed commits are under the \"scratch\" branch)" 73 | } 74 | ], 75 | "condition": "git diff --exit-code > /dev/null" 76 | }, 77 | "compat": { 78 | "name": "compat", 79 | "description": "Perform API compatibility check against latest version", 80 | "steps": [ 81 | { 82 | "exec": "jsii-diff npm:$(node -p \"require('./package.json').name\") -k --ignore-file .compatignore || (echo \"\nUNEXPECTED BREAKING CHANGES: add keys such as 'removed:constructs.Node.of' to .compatignore to skip.\n\" && exit 1)" 83 | } 84 | ] 85 | }, 86 | "compile": { 87 | "name": "compile", 88 | "description": "Only compile", 89 | "steps": [ 90 | { 91 | "exec": "jsii --silence-warnings=reserved-word" 92 | } 93 | ] 94 | }, 95 | "default": { 96 | "name": "default", 97 | "description": "Synthesize project files", 98 | "steps": [ 99 | { 100 | "exec": "ts-node --project tsconfig.dev.json .projenrc.ts" 101 | } 102 | ] 103 | }, 104 | "eject": { 105 | "name": "eject", 106 | "description": "Remove projen from the project", 107 | "env": { 108 | "PROJEN_EJECTING": "true" 109 | }, 110 | "steps": [ 111 | { 112 | "spawn": "default" 113 | } 114 | ] 115 | }, 116 | "eslint": { 117 | "name": "eslint", 118 | "description": "Runs eslint against the codebase", 119 | "env": { 120 | "ESLINT_USE_FLAT_CONFIG": "false", 121 | "NODE_NO_WARNINGS": "1" 122 | }, 123 | "steps": [ 124 | { 125 | "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern $@ src test build-tools projenrc .projenrc.ts", 126 | "receiveArgs": true 127 | } 128 | ] 129 | }, 130 | "install": { 131 | "name": "install", 132 | "description": "Install project dependencies and update lockfile (non-frozen)", 133 | "steps": [ 134 | { 135 | "exec": "yarn install --check-files" 136 | } 137 | ] 138 | }, 139 | "install:ci": { 140 | "name": "install:ci", 141 | "description": "Install project dependencies using frozen lockfile", 142 | "steps": [ 143 | { 144 | "exec": "yarn install --check-files --frozen-lockfile" 145 | } 146 | ] 147 | }, 148 | "package": { 149 | "name": "package", 150 | "description": "Creates the distribution package", 151 | "steps": [ 152 | { 153 | "spawn": "package:js", 154 | "condition": "node -e \"if (!process.env.CI) process.exit(1)\"" 155 | }, 156 | { 157 | "spawn": "package-all", 158 | "condition": "node -e \"if (process.env.CI) process.exit(1)\"" 159 | } 160 | ] 161 | }, 162 | "package-all": { 163 | "name": "package-all", 164 | "description": "Packages artifacts for all target languages", 165 | "steps": [ 166 | { 167 | "spawn": "package:js" 168 | }, 169 | { 170 | "spawn": "package:python" 171 | } 172 | ] 173 | }, 174 | "package:js": { 175 | "name": "package:js", 176 | "description": "Create js language bindings", 177 | "steps": [ 178 | { 179 | "exec": "jsii-pacmak -v --target js" 180 | } 181 | ] 182 | }, 183 | "package:python": { 184 | "name": "package:python", 185 | "description": "Create python language bindings", 186 | "steps": [ 187 | { 188 | "exec": "jsii-pacmak -v --target python" 189 | } 190 | ] 191 | }, 192 | "post-compile": { 193 | "name": "post-compile", 194 | "description": "Runs after successful compilation" 195 | }, 196 | "post-upgrade": { 197 | "name": "post-upgrade", 198 | "description": "Runs after upgrading dependencies" 199 | }, 200 | "pre-compile": { 201 | "name": "pre-compile", 202 | "description": "Prepare the project for compilation" 203 | }, 204 | "release": { 205 | "name": "release", 206 | "description": "Prepare a release from \"main\" branch", 207 | "env": { 208 | "RELEASE": "true" 209 | }, 210 | "steps": [ 211 | { 212 | "exec": "rm -fr dist" 213 | }, 214 | { 215 | "spawn": "bump" 216 | }, 217 | { 218 | "spawn": "build" 219 | }, 220 | { 221 | "spawn": "unbump" 222 | }, 223 | { 224 | "exec": "git diff --ignore-space-at-eol --exit-code" 225 | } 226 | ] 227 | }, 228 | "test": { 229 | "name": "test", 230 | "description": "Run tests", 231 | "steps": [ 232 | { 233 | "exec": "cd ./test && cdk8s import k8s --language typescript" 234 | }, 235 | { 236 | "exec": "jest --passWithNoTests --updateSnapshot", 237 | "receiveArgs": true 238 | }, 239 | { 240 | "spawn": "eslint" 241 | } 242 | ] 243 | }, 244 | "test:watch": { 245 | "name": "test:watch", 246 | "description": "Run jest in watch mode", 247 | "steps": [ 248 | { 249 | "exec": "jest --watch" 250 | } 251 | ] 252 | }, 253 | "unbump": { 254 | "name": "unbump", 255 | "description": "Restores version to 0.0.0", 256 | "env": { 257 | "OUTFILE": "package.json", 258 | "CHANGELOG": "dist/changelog.md", 259 | "BUMPFILE": "dist/version.txt", 260 | "RELEASETAG": "dist/releasetag.txt", 261 | "RELEASE_TAG_PREFIX": "", 262 | "BUMP_PACKAGE": "commit-and-tag-version@^12" 263 | }, 264 | "steps": [ 265 | { 266 | "builtin": "release/reset-version" 267 | } 268 | ] 269 | }, 270 | "upgrade": { 271 | "name": "upgrade", 272 | "description": "upgrade dependencies", 273 | "env": { 274 | "CI": "0" 275 | }, 276 | "steps": [ 277 | { 278 | "exec": "npx npm-check-updates@18 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@types/jest,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-prettier,jest,jsii-diff,jsii-pacmak,prettier,projen,ts-jest" 279 | }, 280 | { 281 | "exec": "yarn install --check-files" 282 | }, 283 | { 284 | "exec": "yarn upgrade @types/jest @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser cdk8s-cli commit-and-tag-version constructs eslint-config-prettier eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-prettier eslint jest jest-junit jsii-diff jsii-pacmak jsii-rosetta jsii prettier projen ts-jest ts-node typescript yaml @cdktf/provider-kubernetes cdk8s cdktf" 285 | }, 286 | { 287 | "exec": "npx projen" 288 | }, 289 | { 290 | "spawn": "post-upgrade" 291 | } 292 | ] 293 | }, 294 | "watch": { 295 | "name": "watch", 296 | "description": "Watch & compile in the background", 297 | "steps": [ 298 | { 299 | "exec": "jsii -w --silence-warnings=reserved-word" 300 | } 301 | ] 302 | } 303 | }, 304 | "env": { 305 | "PATH": "$(npx -c \"node --print process.env.PATH\")" 306 | }, 307 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 308 | } 309 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 HashiCorp, Inc. 2 | 3 | Mozilla Public License, version 2.0 4 | 5 | 1. Definitions 6 | 7 | 1.1. “Contributor” 8 | 9 | means each individual or legal entity that creates, contributes to the 10 | creation of, or owns Covered Software. 11 | 12 | 1.2. “Contributor Version” 13 | 14 | means the combination of the Contributions of others (if any) used by a 15 | Contributor and that particular Contributor’s Contribution. 16 | 17 | 1.3. “Contribution” 18 | 19 | means Covered Software of a particular Contributor. 20 | 21 | 1.4. “Covered Software” 22 | 23 | means Source Code Form to which the initial Contributor has attached the 24 | notice in Exhibit A, the Executable Form of such Source Code Form, and 25 | Modifications of such Source Code Form, in each case including portions 26 | thereof. 27 | 28 | 1.5. “Incompatible With Secondary Licenses” 29 | means 30 | 31 | a. that the initial Contributor has attached the notice described in 32 | Exhibit B to the Covered Software; or 33 | 34 | b. that the Covered Software was made available under the terms of version 35 | 1.1 or earlier of the License, but not also under the terms of a 36 | Secondary License. 37 | 38 | 1.6. “Executable Form” 39 | 40 | means any form of the work other than Source Code Form. 41 | 42 | 1.7. “Larger Work” 43 | 44 | means a work that combines Covered Software with other material, in a separate 45 | file or files, that is not Covered Software. 46 | 47 | 1.8. “License” 48 | 49 | means this document. 50 | 51 | 1.9. “Licensable” 52 | 53 | means having the right to grant, to the maximum extent possible, whether at the 54 | time of the initial grant or subsequently, any and all of the rights conveyed by 55 | this License. 56 | 57 | 1.10. “Modifications” 58 | 59 | means any of the following: 60 | 61 | a. any file in Source Code Form that results from an addition to, deletion 62 | from, or modification of the contents of Covered Software; or 63 | 64 | b. any new file in Source Code Form that contains any Covered Software. 65 | 66 | 1.11. “Patent Claims” of a Contributor 67 | 68 | means any patent claim(s), including without limitation, method, process, 69 | and apparatus claims, in any patent Licensable by such Contributor that 70 | would be infringed, but for the grant of the License, by the making, 71 | using, selling, offering for sale, having made, import, or transfer of 72 | either its Contributions or its Contributor Version. 73 | 74 | 1.12. “Secondary License” 75 | 76 | means either the GNU General Public License, Version 2.0, the GNU Lesser 77 | General Public License, Version 2.1, the GNU Affero General Public 78 | License, Version 3.0, or any later versions of those licenses. 79 | 80 | 1.13. “Source Code Form” 81 | 82 | means the form of the work preferred for making modifications. 83 | 84 | 1.14. “You” (or “Your”) 85 | 86 | means an individual or a legal entity exercising rights under this 87 | License. For legal entities, “You” includes any entity that controls, is 88 | controlled by, or is under common control with You. For purposes of this 89 | definition, “control” means (a) the power, direct or indirect, to cause 90 | the direction or management of such entity, whether by contract or 91 | otherwise, or (b) ownership of more than fifty percent (50%) of the 92 | outstanding shares or beneficial ownership of such entity. 93 | 94 | 95 | 2. License Grants and Conditions 96 | 97 | 2.1. Grants 98 | 99 | Each Contributor hereby grants You a world-wide, royalty-free, 100 | non-exclusive license: 101 | 102 | a. under intellectual property rights (other than patent or trademark) 103 | Licensable by such Contributor to use, reproduce, make available, 104 | modify, display, perform, distribute, and otherwise exploit its 105 | Contributions, either on an unmodified basis, with Modifications, or as 106 | part of a Larger Work; and 107 | 108 | b. under Patent Claims of such Contributor to make, use, sell, offer for 109 | sale, have made, import, and otherwise transfer either its Contributions 110 | or its Contributor Version. 111 | 112 | 2.2. Effective Date 113 | 114 | The licenses granted in Section 2.1 with respect to any Contribution become 115 | effective for each Contribution on the date the Contributor first distributes 116 | such Contribution. 117 | 118 | 2.3. Limitations on Grant Scope 119 | 120 | The licenses granted in this Section 2 are the only rights granted under this 121 | License. No additional rights or licenses will be implied from the distribution 122 | or licensing of Covered Software under this License. Notwithstanding Section 123 | 2.1(b) above, no patent license is granted by a Contributor: 124 | 125 | a. for any code that a Contributor has removed from Covered Software; or 126 | 127 | b. for infringements caused by: (i) Your and any other third party’s 128 | modifications of Covered Software, or (ii) the combination of its 129 | Contributions with other software (except as part of its Contributor 130 | Version); or 131 | 132 | c. under Patent Claims infringed by Covered Software in the absence of its 133 | Contributions. 134 | 135 | This License does not grant any rights in the trademarks, service marks, or 136 | logos of any Contributor (except as may be necessary to comply with the 137 | notice requirements in Section 3.4). 138 | 139 | 2.4. Subsequent Licenses 140 | 141 | No Contributor makes additional grants as a result of Your choice to 142 | distribute the Covered Software under a subsequent version of this License 143 | (see Section 10.2) or under the terms of a Secondary License (if permitted 144 | under the terms of Section 3.3). 145 | 146 | 2.5. Representation 147 | 148 | Each Contributor represents that the Contributor believes its Contributions 149 | are its original creation(s) or it has sufficient rights to grant the 150 | rights to its Contributions conveyed by this License. 151 | 152 | 2.6. Fair Use 153 | 154 | This License is not intended to limit any rights You have under applicable 155 | copyright doctrines of fair use, fair dealing, or other equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under the 169 | terms of this License. You must inform recipients that the Source Code Form 170 | of the Covered Software is governed by the terms of this License, and how 171 | they can obtain a copy of this License. You may not attempt to alter or 172 | restrict the recipients’ rights in the Source Code Form. 173 | 174 | 3.2. Distribution of Executable Form 175 | 176 | If You distribute Covered Software in Executable Form then: 177 | 178 | a. such Covered Software must also be made available in Source Code Form, 179 | as described in Section 3.1, and You must inform recipients of the 180 | Executable Form how they can obtain a copy of such Source Code Form by 181 | reasonable means in a timely manner, at a charge no more than the cost 182 | of distribution to the recipient; and 183 | 184 | b. You may distribute such Executable Form under the terms of this License, 185 | or sublicense it under different terms, provided that the license for 186 | the Executable Form does not attempt to limit or alter the recipients’ 187 | rights in the Source Code Form under this License. 188 | 189 | 3.3. Distribution of a Larger Work 190 | 191 | You may create and distribute a Larger Work under terms of Your choice, 192 | provided that You also comply with the requirements of this License for the 193 | Covered Software. If the Larger Work is a combination of Covered Software 194 | with a work governed by one or more Secondary Licenses, and the Covered 195 | Software is not Incompatible With Secondary Licenses, this License permits 196 | You to additionally distribute such Covered Software under the terms of 197 | such Secondary License(s), so that the recipient of the Larger Work may, at 198 | their option, further distribute the Covered Software under the terms of 199 | either this License or such Secondary License(s). 200 | 201 | 3.4. Notices 202 | 203 | You may not remove or alter the substance of any license notices (including 204 | copyright notices, patent notices, disclaimers of warranty, or limitations 205 | of liability) contained within the Source Code Form of the Covered 206 | Software, except that You may alter any license notices to the extent 207 | required to remedy known factual inaccuracies. 208 | 209 | 3.5. Application of Additional Terms 210 | 211 | You may choose to offer, and to charge a fee for, warranty, support, 212 | indemnity or liability obligations to one or more recipients of Covered 213 | Software. However, You may do so only on Your own behalf, and not on behalf 214 | of any Contributor. You must make it absolutely clear that any such 215 | warranty, support, indemnity, or liability obligation is offered by You 216 | alone, and You hereby agree to indemnify every Contributor for any 217 | liability incurred by such Contributor as a result of warranty, support, 218 | indemnity or liability terms You offer. You may include additional 219 | disclaimers of warranty and limitations of liability specific to any 220 | jurisdiction. 221 | 222 | 4. Inability to Comply Due to Statute or Regulation 223 | 224 | If it is impossible for You to comply with any of the terms of this License 225 | with respect to some or all of the Covered Software due to statute, judicial 226 | order, or regulation then You must: (a) comply with the terms of this License 227 | to the maximum extent possible; and (b) describe the limitations and the code 228 | they affect. Such description must be placed in a text file included with all 229 | distributions of the Covered Software under this License. Except to the 230 | extent prohibited by statute or regulation, such description must be 231 | sufficiently detailed for a recipient of ordinary skill to be able to 232 | understand it. 233 | 234 | 5. Termination 235 | 236 | 5.1. The rights granted under this License will terminate automatically if You 237 | fail to comply with any of its terms. However, if You become compliant, 238 | then the rights granted under this License from a particular Contributor 239 | are reinstated (a) provisionally, unless and until such Contributor 240 | explicitly and finally terminates Your grants, and (b) on an ongoing basis, 241 | if such Contributor fails to notify You of the non-compliance by some 242 | reasonable means prior to 60 days after You have come back into compliance. 243 | Moreover, Your grants from a particular Contributor are reinstated on an 244 | ongoing basis if such Contributor notifies You of the non-compliance by 245 | some reasonable means, this is the first time You have received notice of 246 | non-compliance with this License from such Contributor, and You become 247 | compliant prior to 30 days after Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, counter-claims, 251 | and cross-claims) alleging that a Contributor Version directly or 252 | indirectly infringes any patent, then the rights granted to You by any and 253 | all Contributors for the Covered Software under Section 2.1 of this License 254 | shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 257 | license agreements (excluding distributors and resellers) which have been 258 | validly granted by You or Your distributors under this License prior to 259 | termination shall survive termination. 260 | 261 | 6. Disclaimer of Warranty 262 | 263 | Covered Software is provided under this License on an “as is” basis, without 264 | warranty of any kind, either expressed, implied, or statutory, including, 265 | without limitation, warranties that the Covered Software is free of defects, 266 | merchantable, fit for a particular purpose or non-infringing. The entire 267 | risk as to the quality and performance of the Covered Software is with You. 268 | Should any Covered Software prove defective in any respect, You (not any 269 | Contributor) assume the cost of any necessary servicing, repair, or 270 | correction. This disclaimer of warranty constitutes an essential part of this 271 | License. No use of any Covered Software is authorized under this License 272 | except under this disclaimer. 273 | 274 | 7. Limitation of Liability 275 | 276 | Under no circumstances and under no legal theory, whether tort (including 277 | negligence), contract, or otherwise, shall any Contributor, or anyone who 278 | distributes Covered Software as permitted above, be liable to You for any 279 | direct, indirect, special, incidental, or consequential damages of any 280 | character including, without limitation, damages for lost profits, loss of 281 | goodwill, work stoppage, computer failure or malfunction, or any and all 282 | other commercial damages or losses, even if such party shall have been 283 | informed of the possibility of such damages. This limitation of liability 284 | shall not apply to liability for death or personal injury resulting from such 285 | party’s negligence to the extent applicable law prohibits such limitation. 286 | Some jurisdictions do not allow the exclusion or limitation of incidental or 287 | consequential damages, so this exclusion and limitation may not apply to You. 288 | 289 | 8. Litigation 290 | 291 | Any litigation relating to this License may be brought only in the courts of 292 | a jurisdiction where the defendant maintains its principal place of business 293 | and such litigation shall be governed by laws of that jurisdiction, without 294 | reference to its conflict-of-law provisions. Nothing in this Section shall 295 | prevent a party’s ability to bring cross-claims or counter-claims. 296 | 297 | 9. Miscellaneous 298 | 299 | This License represents the complete agreement concerning the subject matter 300 | hereof. If any provision of this License is held to be unenforceable, such 301 | provision shall be reformed only to the extent necessary to make it 302 | enforceable. Any law or regulation which provides that the language of a 303 | contract shall be construed against the drafter shall not be used to construe 304 | this License against a Contributor. 305 | 306 | 307 | 10. Versions of the License 308 | 309 | 10.1. New Versions 310 | 311 | Mozilla Foundation is the license steward. Except as provided in Section 312 | 10.3, no one other than the license steward has the right to modify or 313 | publish new versions of this License. Each version will be given a 314 | distinguishing version number. 315 | 316 | 10.2. Effect of New Versions 317 | 318 | You may distribute the Covered Software under the terms of the version of 319 | the License under which You originally received the Covered Software, or 320 | under the terms of any subsequent version published by the license 321 | steward. 322 | 323 | 10.3. Modified Versions 324 | 325 | If you create software not governed by this License, and you want to 326 | create a new license for such software, you may create and use a modified 327 | version of this License if you rename the license and remove any 328 | references to the name of the license steward (except to note that such 329 | modified license differs from this License). 330 | 331 | 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 332 | If You choose to distribute Source Code Form that is Incompatible With 333 | Secondary Licenses under the terms of this version of the License, the 334 | notice described in Exhibit B of this License must be attached. 335 | 336 | Exhibit A - Source Code Form License Notice 337 | 338 | This Source Code Form is subject to the 339 | terms of the Mozilla Public License, v. 340 | 2.0. If a copy of the MPL was not 341 | distributed with this file, You can 342 | obtain one at 343 | http://mozilla.org/MPL/2.0/. 344 | 345 | If it is not possible or desirable to put the notice in a particular file, then 346 | You may include the notice in a location (such as a LICENSE file in a relevant 347 | directory) where a recipient would be likely to look for such a notice. 348 | 349 | You may add additional accurate notices of copyright ownership. 350 | 351 | Exhibit B - “Incompatible With Secondary Licenses” Notice 352 | 353 | This Source Code Form is “Incompatible 354 | With Secondary Licenses”, as defined by 355 | the Mozilla Public License, v. 2.0. 356 | -------------------------------------------------------------------------------- /test/cdktf-cdk8s.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) HashiCorp, Inc. 3 | * SPDX-License-Identifier: MPL-2.0 4 | */ 5 | 6 | import { App, Chart } from "cdk8s"; 7 | import { Testing } from "cdktf"; 8 | import { CDK8sProvider } from "../src"; 9 | import { KubeDeployment, KubeNamespace } from "./imports/k8s"; 10 | 11 | describe("CDK8sProvider", () => { 12 | test("synthesises YAML into CDKTF plan", () => { 13 | expect( 14 | Testing.synthScope((scope) => { 15 | const cdk8sApp = new App(); 16 | const chart = new Chart(cdk8sApp, "chart"); 17 | const label = { app: "test" }; 18 | new KubeDeployment(chart, "deployment", { 19 | spec: { 20 | replicas: 1, 21 | selector: { 22 | matchLabels: label, 23 | }, 24 | 25 | template: { 26 | metadata: { labels: label }, 27 | spec: { 28 | containers: [ 29 | { 30 | name: "hello-kubernetes", 31 | image: "paulbouwer/hello-kubernetes:1.7", 32 | ports: [{ containerPort: 8080 }], 33 | }, 34 | ], 35 | }, 36 | }, 37 | }, 38 | }); 39 | 40 | new CDK8sProvider(scope, "cdk8s-provider", { 41 | cdk8sApp, 42 | }); 43 | }) 44 | ).toMatchInlineSnapshot(` 45 | "{ 46 | "provider": { 47 | "kubernetes": [ 48 | { 49 | "alias": "cdktf-cdk8s-cdk8s-provider" 50 | } 51 | ] 52 | }, 53 | "resource": { 54 | "kubernetes_manifest": { 55 | "cdk8s-provider_cdk8s-provider-apps--v1-Deployment-chart-deployment-c8b75089-default_ABFFC36F": { 56 | "manifest": { 57 | "apiVersion": "apps/v1", 58 | "kind": "Deployment", 59 | "metadata": { 60 | "name": "chart-deployment-c8b75089" 61 | }, 62 | "spec": { 63 | "replicas": 1, 64 | "selector": { 65 | "matchLabels": { 66 | "app": "test" 67 | } 68 | }, 69 | "template": { 70 | "metadata": { 71 | "labels": { 72 | "app": "test" 73 | } 74 | }, 75 | "spec": { 76 | "containers": [ 77 | { 78 | "image": "paulbouwer/hello-kubernetes:1.7", 79 | "name": "hello-kubernetes", 80 | "ports": [ 81 | { 82 | "containerPort": 8080 83 | } 84 | ] 85 | } 86 | ] 87 | } 88 | } 89 | } 90 | }, 91 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider" 92 | } 93 | } 94 | }, 95 | "terraform": { 96 | "required_providers": { 97 | "kubernetes": { 98 | "source": "kubernetes", 99 | "version": "2.37.1" 100 | } 101 | } 102 | } 103 | }" 104 | `); 105 | }); 106 | 107 | test("synthesises multiple YAMLs into CDKTF plan", () => { 108 | expect( 109 | Testing.synthScope((scope) => { 110 | const cdk8sApp = new App(); 111 | const chart = new Chart(cdk8sApp, "chart"); 112 | const label = { app: "test" }; 113 | new KubeDeployment(chart, "deployment", { 114 | spec: { 115 | replicas: 1, 116 | selector: { 117 | matchLabels: label, 118 | }, 119 | 120 | template: { 121 | metadata: { labels: label }, 122 | spec: { 123 | containers: [ 124 | { 125 | name: "hello-kubernetes", 126 | image: "paulbouwer/hello-kubernetes:1.7", 127 | ports: [{ containerPort: 8080 }], 128 | }, 129 | ], 130 | }, 131 | }, 132 | }, 133 | }); 134 | 135 | new KubeNamespace(chart, "ns", { 136 | metadata: { name: "my-namespace" }, 137 | }); 138 | 139 | new KubeDeployment(chart, "deployment2", { 140 | metadata: { 141 | namespace: "my-namespace", 142 | }, 143 | 144 | spec: { 145 | replicas: 1, 146 | selector: { 147 | matchLabels: label, 148 | }, 149 | 150 | template: { 151 | metadata: { labels: label }, 152 | spec: { 153 | containers: [ 154 | { 155 | name: "hello-kubernetes2", 156 | image: "paulbouwer/hello-kubernetes:1.8", 157 | ports: [{ containerPort: 8080 }], 158 | }, 159 | ], 160 | }, 161 | }, 162 | }, 163 | }); 164 | 165 | new CDK8sProvider(scope, "cdk8s-provider", { 166 | cdk8sApp, 167 | }); 168 | }) 169 | ).toMatchInlineSnapshot(` 170 | "{ 171 | "provider": { 172 | "kubernetes": [ 173 | { 174 | "alias": "cdktf-cdk8s-cdk8s-provider" 175 | } 176 | ] 177 | }, 178 | "resource": { 179 | "kubernetes_manifest": { 180 | "cdk8s-provider_cdk8s-provider-apps--v1-Deployment-chart-deployment-c8b75089-default_ABFFC36F": { 181 | "manifest": { 182 | "apiVersion": "apps/v1", 183 | "kind": "Deployment", 184 | "metadata": { 185 | "name": "chart-deployment-c8b75089" 186 | }, 187 | "spec": { 188 | "replicas": 1, 189 | "selector": { 190 | "matchLabels": { 191 | "app": "test" 192 | } 193 | }, 194 | "template": { 195 | "metadata": { 196 | "labels": { 197 | "app": "test" 198 | } 199 | }, 200 | "spec": { 201 | "containers": [ 202 | { 203 | "image": "paulbouwer/hello-kubernetes:1.7", 204 | "name": "hello-kubernetes", 205 | "ports": [ 206 | { 207 | "containerPort": 8080 208 | } 209 | ] 210 | } 211 | ] 212 | } 213 | } 214 | } 215 | }, 216 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider" 217 | }, 218 | "cdk8s-provider_cdk8s-provider-apps--v1-Deployment-chart-deployment2-c898e6fb-my-namespace_65896BBD": { 219 | "manifest": { 220 | "apiVersion": "apps/v1", 221 | "kind": "Deployment", 222 | "metadata": { 223 | "name": "chart-deployment2-c898e6fb", 224 | "namespace": "my-namespace" 225 | }, 226 | "spec": { 227 | "replicas": 1, 228 | "selector": { 229 | "matchLabels": { 230 | "app": "test" 231 | } 232 | }, 233 | "template": { 234 | "metadata": { 235 | "labels": { 236 | "app": "test" 237 | } 238 | }, 239 | "spec": { 240 | "containers": [ 241 | { 242 | "image": "paulbouwer/hello-kubernetes:1.8", 243 | "name": "hello-kubernetes2", 244 | "ports": [ 245 | { 246 | "containerPort": 8080 247 | } 248 | ] 249 | } 250 | ] 251 | } 252 | } 253 | } 254 | }, 255 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider" 256 | }, 257 | "cdk8s-provider_cdk8s-provider-v1-Namespace-my-namespace-default_BA2401B1": { 258 | "manifest": { 259 | "apiVersion": "v1", 260 | "kind": "Namespace", 261 | "metadata": { 262 | "name": "my-namespace" 263 | } 264 | }, 265 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider" 266 | } 267 | } 268 | }, 269 | "terraform": { 270 | "required_providers": { 271 | "kubernetes": { 272 | "source": "kubernetes", 273 | "version": "2.37.1" 274 | } 275 | } 276 | } 277 | }" 278 | `); 279 | }); 280 | 281 | test("escapes values against terraform", () => { 282 | expect( 283 | Testing.synthScope((scope) => { 284 | const cdk8sApp = new App(); 285 | const chart = new Chart(cdk8sApp, "chart"); 286 | const label = { app: "test" }; 287 | new KubeDeployment(chart, "deployment", { 288 | spec: { 289 | replicas: 1, 290 | selector: { 291 | matchLabels: label, 292 | }, 293 | 294 | template: { 295 | metadata: { labels: label }, 296 | spec: { 297 | containers: [ 298 | { 299 | name: "hello-kubernetes", 300 | image: 301 | "pau${var.notTerraformJustLooksLikeIt}lbouwer/hello-kubernetes:1.7", 302 | ports: [{ containerPort: 8080 }], 303 | }, 304 | ], 305 | }, 306 | }, 307 | }, 308 | }); 309 | 310 | new CDK8sProvider(scope, "cdk8s-provider", { 311 | cdk8sApp, 312 | }); 313 | }) 314 | ).toMatchInlineSnapshot(` 315 | "{ 316 | "provider": { 317 | "kubernetes": [ 318 | { 319 | "alias": "cdktf-cdk8s-cdk8s-provider" 320 | } 321 | ] 322 | }, 323 | "resource": { 324 | "kubernetes_manifest": { 325 | "cdk8s-provider_cdk8s-provider-apps--v1-Deployment-chart-deployment-c8b75089-default_ABFFC36F": { 326 | "manifest": { 327 | "apiVersion": "apps/v1", 328 | "kind": "Deployment", 329 | "metadata": { 330 | "name": "chart-deployment-c8b75089" 331 | }, 332 | "spec": { 333 | "replicas": 1, 334 | "selector": { 335 | "matchLabels": { 336 | "app": "test" 337 | } 338 | }, 339 | "template": { 340 | "metadata": { 341 | "labels": { 342 | "app": "test" 343 | } 344 | }, 345 | "spec": { 346 | "containers": [ 347 | { 348 | "image": "pau$\${var.notTerraformJustLooksLikeIt}lbouwer/hello-kubernetes:1.7", 349 | "name": "hello-kubernetes", 350 | "ports": [ 351 | { 352 | "containerPort": 8080 353 | } 354 | ] 355 | } 356 | ] 357 | } 358 | } 359 | } 360 | }, 361 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider" 362 | } 363 | } 364 | }, 365 | "terraform": { 366 | "required_providers": { 367 | "kubernetes": { 368 | "source": "kubernetes", 369 | "version": "2.37.1" 370 | } 371 | } 372 | } 373 | }" 374 | `); 375 | }); 376 | 377 | test("can use multiple against different clusters", () => { 378 | expect( 379 | Testing.synthScope((scope) => { 380 | const cdk8sApp = new App(); 381 | const chart = new Chart(cdk8sApp, "chart"); 382 | const label = { app: "test" }; 383 | new KubeDeployment(chart, "deployment", { 384 | spec: { 385 | replicas: 1, 386 | selector: { 387 | matchLabels: label, 388 | }, 389 | 390 | template: { 391 | metadata: { labels: label }, 392 | spec: { 393 | containers: [ 394 | { 395 | name: "hello-kubernetes", 396 | image: "paulbouwer/hello-kubernetes:1.7", 397 | ports: [{ containerPort: 8080 }], 398 | }, 399 | ], 400 | }, 401 | }, 402 | }, 403 | }); 404 | 405 | new CDK8sProvider(scope, "cdk8s-provider", { 406 | cdk8sApp, 407 | }); 408 | 409 | new CDK8sProvider(scope, "cdk8s-provider-2", { 410 | cdk8sApp, 411 | configContext: "my-other-context", 412 | }); 413 | }) 414 | ).toMatchInlineSnapshot(` 415 | "{ 416 | "provider": { 417 | "kubernetes": [ 418 | { 419 | "alias": "cdktf-cdk8s-cdk8s-provider" 420 | }, 421 | { 422 | "alias": "cdktf-cdk8s-cdk8s-provider-2", 423 | "config_context": "my-other-context" 424 | } 425 | ] 426 | }, 427 | "resource": { 428 | "kubernetes_manifest": { 429 | "cdk8s-provider-2_cdk8s-provider-2-apps--v1-Deployment-chart-deployment-c8b75089-default_03050E76": { 430 | "manifest": { 431 | "apiVersion": "apps/v1", 432 | "kind": "Deployment", 433 | "metadata": { 434 | "name": "chart-deployment-c8b75089" 435 | }, 436 | "spec": { 437 | "replicas": 1, 438 | "selector": { 439 | "matchLabels": { 440 | "app": "test" 441 | } 442 | }, 443 | "template": { 444 | "metadata": { 445 | "labels": { 446 | "app": "test" 447 | } 448 | }, 449 | "spec": { 450 | "containers": [ 451 | { 452 | "image": "paulbouwer/hello-kubernetes:1.7", 453 | "name": "hello-kubernetes", 454 | "ports": [ 455 | { 456 | "containerPort": 8080 457 | } 458 | ] 459 | } 460 | ] 461 | } 462 | } 463 | } 464 | }, 465 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider-2" 466 | }, 467 | "cdk8s-provider_cdk8s-provider-apps--v1-Deployment-chart-deployment-c8b75089-default_ABFFC36F": { 468 | "manifest": { 469 | "apiVersion": "apps/v1", 470 | "kind": "Deployment", 471 | "metadata": { 472 | "name": "chart-deployment-c8b75089" 473 | }, 474 | "spec": { 475 | "replicas": 1, 476 | "selector": { 477 | "matchLabels": { 478 | "app": "test" 479 | } 480 | }, 481 | "template": { 482 | "metadata": { 483 | "labels": { 484 | "app": "test" 485 | } 486 | }, 487 | "spec": { 488 | "containers": [ 489 | { 490 | "image": "paulbouwer/hello-kubernetes:1.7", 491 | "name": "hello-kubernetes", 492 | "ports": [ 493 | { 494 | "containerPort": 8080 495 | } 496 | ] 497 | } 498 | ] 499 | } 500 | } 501 | } 502 | }, 503 | "provider": "kubernetes.cdktf-cdk8s-cdk8s-provider" 504 | } 505 | } 506 | }, 507 | "terraform": { 508 | "required_providers": { 509 | "kubernetes": { 510 | "source": "kubernetes", 511 | "version": "2.37.1" 512 | } 513 | } 514 | } 515 | }" 516 | `); 517 | }); 518 | }); 519 | --------------------------------------------------------------------------------