├── .eslintrc.json
├── .gitattributes
├── .github
├── FUNDING.yml
├── pull_request_template.md
└── workflows
│ ├── build.yml
│ ├── pull-request-lint.yml
│ └── release.yml
├── .gitignore
├── .idea
├── .gitignore
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── modules.xml
├── state-machine.iml
└── vcs.xml
├── .mergify.yml
├── .npmignore
├── .projen
├── deps.json
├── files.json
└── tasks.json
├── .projenrc.ts
├── API.md
├── LICENSE
├── README.md
├── package.json
├── src
├── BuildStateType.ts
├── StateMachine.ts
├── StepFunctionsAutoDiscover.ts
└── index.ts
├── test
├── StateMachine.test.ts
├── StateMachineAutoDiscover.test.ts
├── __snapshots__
│ ├── StateMachine.test.ts.snap
│ └── StateMachineAutoDiscover.test.ts.snap
├── sample.json
└── step-functions
│ ├── test.json.asl
│ ├── test.workflow.json
│ ├── test.yaml.asl
│ └── test2.workflow.json
├── tsconfig.dev.json
└── yarn.lock
/.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 | ],
21 | "settings": {
22 | "import/parsers": {
23 | "@typescript-eslint/parser": [
24 | ".ts",
25 | ".tsx"
26 | ]
27 | },
28 | "import/resolver": {
29 | "node": {},
30 | "typescript": {
31 | "project": "./tsconfig.dev.json",
32 | "alwaysTryTypes": true
33 | }
34 | }
35 | },
36 | "ignorePatterns": [
37 | "*.js",
38 | "*.d.ts",
39 | "node_modules/",
40 | "*.generated.ts",
41 | "coverage",
42 | "!.projenrc.ts",
43 | "!projenrc/**/*.ts"
44 | ],
45 | "rules": {
46 | "indent": [
47 | "off"
48 | ],
49 | "@typescript-eslint/indent": [
50 | "error",
51 | 2
52 | ],
53 | "quotes": [
54 | "error",
55 | "single",
56 | {
57 | "avoidEscape": true
58 | }
59 | ],
60 | "comma-dangle": [
61 | "error",
62 | "always-multiline"
63 | ],
64 | "comma-spacing": [
65 | "error",
66 | {
67 | "before": false,
68 | "after": true
69 | }
70 | ],
71 | "no-multi-spaces": [
72 | "error",
73 | {
74 | "ignoreEOLComments": false
75 | }
76 | ],
77 | "array-bracket-spacing": [
78 | "error",
79 | "never"
80 | ],
81 | "array-bracket-newline": [
82 | "error",
83 | "consistent"
84 | ],
85 | "object-curly-spacing": [
86 | "error",
87 | "always"
88 | ],
89 | "object-curly-newline": [
90 | "error",
91 | {
92 | "multiline": true,
93 | "consistent": true
94 | }
95 | ],
96 | "object-property-newline": [
97 | "error",
98 | {
99 | "allowAllPropertiesOnSameLine": true
100 | }
101 | ],
102 | "keyword-spacing": [
103 | "error"
104 | ],
105 | "brace-style": [
106 | "error",
107 | "1tbs",
108 | {
109 | "allowSingleLine": true
110 | }
111 | ],
112 | "space-before-blocks": [
113 | "error"
114 | ],
115 | "curly": [
116 | "error",
117 | "multi-line",
118 | "consistent"
119 | ],
120 | "@typescript-eslint/member-delimiter-style": [
121 | "error"
122 | ],
123 | "semi": [
124 | "error",
125 | "always"
126 | ],
127 | "max-len": [
128 | "error",
129 | {
130 | "code": 150,
131 | "ignoreUrls": true,
132 | "ignoreStrings": true,
133 | "ignoreTemplateLiterals": true,
134 | "ignoreComments": true,
135 | "ignoreRegExpLiterals": true
136 | }
137 | ],
138 | "quote-props": [
139 | "error",
140 | "consistent-as-needed"
141 | ],
142 | "@typescript-eslint/no-require-imports": [
143 | "error"
144 | ],
145 | "import/no-extraneous-dependencies": [
146 | "error",
147 | {
148 | "devDependencies": [
149 | "**/test/**",
150 | "**/build-tools/**",
151 | ".projenrc.ts",
152 | "projenrc/**/*.ts"
153 | ],
154 | "optionalDependencies": false,
155 | "peerDependencies": true
156 | }
157 | ],
158 | "import/no-unresolved": [
159 | "error"
160 | ],
161 | "import/order": [
162 | "warn",
163 | {
164 | "groups": [
165 | "builtin",
166 | "external"
167 | ],
168 | "alphabetize": {
169 | "order": "asc",
170 | "caseInsensitive": true
171 | }
172 | }
173 | ],
174 | "import/no-duplicates": [
175 | "error"
176 | ],
177 | "no-shadow": [
178 | "off"
179 | ],
180 | "@typescript-eslint/no-shadow": [
181 | "error"
182 | ],
183 | "key-spacing": [
184 | "error"
185 | ],
186 | "no-multiple-empty-lines": [
187 | "error"
188 | ],
189 | "@typescript-eslint/no-floating-promises": [
190 | "error"
191 | ],
192 | "no-return-await": [
193 | "off"
194 | ],
195 | "@typescript-eslint/return-await": [
196 | "error"
197 | ],
198 | "no-trailing-spaces": [
199 | "error"
200 | ],
201 | "dot-notation": [
202 | "error"
203 | ],
204 | "no-bitwise": [
205 | "error"
206 | ],
207 | "@typescript-eslint/member-ordering": [
208 | "error",
209 | {
210 | "default": [
211 | "public-static-field",
212 | "public-static-method",
213 | "protected-static-field",
214 | "protected-static-method",
215 | "private-static-field",
216 | "private-static-method",
217 | "field",
218 | "constructor",
219 | "method"
220 | ]
221 | }
222 | ]
223 | },
224 | "overrides": [
225 | {
226 | "files": [
227 | ".projenrc.ts"
228 | ],
229 | "rules": {
230 | "@typescript-eslint/no-require-imports": "off",
231 | "import/no-extraneous-dependencies": "off"
232 | }
233 | }
234 | ]
235 | }
236 |
--------------------------------------------------------------------------------
/.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/pull_request_template.md linguist-generated
8 | /.github/workflows/build.yml linguist-generated
9 | /.github/workflows/pull-request-lint.yml linguist-generated
10 | /.github/workflows/release.yml linguist-generated
11 | /.gitignore linguist-generated
12 | /.mergify.yml linguist-generated
13 | /.npmignore linguist-generated
14 | /.projen/** linguist-generated
15 | /.projen/deps.json linguist-generated
16 | /.projen/files.json linguist-generated
17 | /.projen/tasks.json linguist-generated
18 | /API.md linguist-generated
19 | /LICENSE linguist-generated
20 | /package.json linguist-generated
21 | /tsconfig.dev.json linguist-generated
22 | /yarn.lock linguist-generated
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [mbonig]
4 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Fixes #
--------------------------------------------------------------------------------
/.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@v4
19 | with:
20 | ref: ${{ github.event.pull_request.head.ref }}
21 | repository: ${{ github.event.pull_request.head.repo.full_name }}
22 | - name: Setup Node.js
23 | uses: actions/setup-node@v4
24 | with:
25 | node-version: lts/*
26 | - name: Install dependencies
27 | run: yarn install --check-files
28 | - name: build
29 | run: npx projen build
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 | working-directory: ./
36 | - name: Upload patch
37 | if: steps.self_mutation.outputs.self_mutation_happened
38 | uses: actions/upload-artifact@v4.3.6
39 | with:
40 | name: repo.patch
41 | path: repo.patch
42 | overwrite: true
43 | - name: Fail build on mutation
44 | if: steps.self_mutation.outputs.self_mutation_happened
45 | run: |-
46 | echo "::error::Files were changed during build (see build log). If this was triggered from a fork, you will need to update your branch."
47 | cat repo.patch
48 | exit 1
49 | - name: Backup artifact permissions
50 | run: cd dist && getfacl -R . > permissions-backup.acl
51 | continue-on-error: true
52 | - name: Upload artifact
53 | uses: actions/upload-artifact@v4.3.6
54 | with:
55 | name: build-artifact
56 | path: dist
57 | overwrite: true
58 | self-mutation:
59 | needs: build
60 | runs-on: ubuntu-latest
61 | permissions:
62 | contents: write
63 | if: always() && needs.build.outputs.self_mutation_happened && !(github.event.pull_request.head.repo.full_name != github.repository)
64 | steps:
65 | - name: Checkout
66 | uses: actions/checkout@v4
67 | with:
68 | token: ${{ secrets.PROJEN_GITHUB_TOKEN }}
69 | ref: ${{ github.event.pull_request.head.ref }}
70 | repository: ${{ github.event.pull_request.head.repo.full_name }}
71 | - name: Download patch
72 | uses: actions/download-artifact@v4
73 | with:
74 | name: repo.patch
75 | path: ${{ runner.temp }}
76 | - name: Apply patch
77 | run: '[ -s ${{ runner.temp }}/repo.patch ] && git apply ${{ runner.temp }}/repo.patch || echo "Empty patch. Skipping."'
78 | - name: Set git identity
79 | run: |-
80 | git config user.name "github-actions"
81 | git config user.email "github-actions@github.com"
82 | - name: Push changes
83 | env:
84 | PULL_REQUEST_REF: ${{ github.event.pull_request.head.ref }}
85 | run: |-
86 | git add .
87 | git commit -s -m "chore: self mutation"
88 | git push origin HEAD:$PULL_REQUEST_REF
89 | package-js:
90 | needs: build
91 | runs-on: ubuntu-latest
92 | permissions:
93 | contents: read
94 | if: ${{ !needs.build.outputs.self_mutation_happened }}
95 | steps:
96 | - uses: actions/setup-node@v4
97 | with:
98 | node-version: lts/*
99 | - name: Download build artifacts
100 | uses: actions/download-artifact@v4
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@v4
109 | with:
110 | ref: ${{ github.event.pull_request.head.ref }}
111 | repository: ${{ github.event.pull_request.head.repo.full_name }}
112 | path: .repo
113 | - name: Install Dependencies
114 | run: cd .repo && yarn install --check-files --frozen-lockfile
115 | - name: Extract build artifact
116 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo
117 | - name: Move build artifact out of the way
118 | run: mv dist dist.old
119 | - name: Create js artifact
120 | run: cd .repo && npx projen package:js
121 | - name: Collect js artifact
122 | run: mv .repo/dist dist
123 | package-python:
124 | needs: build
125 | runs-on: ubuntu-latest
126 | permissions:
127 | contents: read
128 | if: ${{ !needs.build.outputs.self_mutation_happened }}
129 | steps:
130 | - uses: actions/setup-node@v4
131 | with:
132 | node-version: lts/*
133 | - uses: actions/setup-python@v5
134 | with:
135 | python-version: 3.x
136 | - name: Download build artifacts
137 | uses: actions/download-artifact@v4
138 | with:
139 | name: build-artifact
140 | path: dist
141 | - name: Restore build artifact permissions
142 | run: cd dist && setfacl --restore=permissions-backup.acl
143 | continue-on-error: true
144 | - name: Checkout
145 | uses: actions/checkout@v4
146 | with:
147 | ref: ${{ github.event.pull_request.head.ref }}
148 | repository: ${{ github.event.pull_request.head.repo.full_name }}
149 | path: .repo
150 | - name: Install Dependencies
151 | run: cd .repo && yarn install --check-files --frozen-lockfile
152 | - name: Extract build artifact
153 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo
154 | - name: Move build artifact out of the way
155 | run: mv dist dist.old
156 | - name: Create python artifact
157 | run: cd .repo && npx projen package:python
158 | - name: Collect python artifact
159 | run: mv .repo/dist dist
160 |
--------------------------------------------------------------------------------
/.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 | jobs:
14 | validate:
15 | name: Validate PR title
16 | runs-on: ubuntu-latest
17 | permissions:
18 | pull-requests: write
19 | steps:
20 | - uses: amannn/action-semantic-pull-request@v5.4.0
21 | env:
22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23 | with:
24 | types: |-
25 | feat
26 | fix
27 | chore
28 | requireScope: false
29 |
--------------------------------------------------------------------------------
/.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 | workflow_dispatch: {}
9 | concurrency:
10 | group: ${{ github.workflow }}
11 | cancel-in-progress: false
12 | jobs:
13 | release:
14 | runs-on: ubuntu-latest
15 | permissions:
16 | contents: write
17 | outputs:
18 | latest_commit: ${{ steps.git_remote.outputs.latest_commit }}
19 | tag_exists: ${{ steps.check_tag_exists.outputs.exists }}
20 | env:
21 | CI: "true"
22 | steps:
23 | - name: Checkout
24 | uses: actions/checkout@v4
25 | with:
26 | fetch-depth: 0
27 | - name: Set git identity
28 | run: |-
29 | git config user.name "github-actions"
30 | git config user.email "github-actions@github.com"
31 | - name: Setup Node.js
32 | uses: actions/setup-node@v4
33 | with:
34 | node-version: lts/*
35 | - name: Install dependencies
36 | run: yarn install --check-files --frozen-lockfile
37 | - name: release
38 | run: npx projen release
39 | - name: Check if version has already been tagged
40 | id: check_tag_exists
41 | run: |-
42 | TAG=$(cat dist/releasetag.txt)
43 | ([ ! -z "$TAG" ] && git ls-remote -q --exit-code --tags origin $TAG && (echo "exists=true" >> $GITHUB_OUTPUT)) || (echo "exists=false" >> $GITHUB_OUTPUT)
44 | cat $GITHUB_OUTPUT
45 | - name: Check for new commits
46 | id: git_remote
47 | run: |-
48 | echo "latest_commit=$(git ls-remote origin -h ${{ github.ref }} | cut -f1)" >> $GITHUB_OUTPUT
49 | cat $GITHUB_OUTPUT
50 | - name: Backup artifact permissions
51 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }}
52 | run: cd dist && getfacl -R . > permissions-backup.acl
53 | continue-on-error: true
54 | - name: Upload artifact
55 | if: ${{ steps.git_remote.outputs.latest_commit == github.sha }}
56 | uses: actions/upload-artifact@v4.3.6
57 | with:
58 | name: build-artifact
59 | path: dist
60 | overwrite: true
61 | release_github:
62 | name: Publish to GitHub Releases
63 | needs:
64 | - release
65 | - release_npm
66 | - release_pypi
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@v4
73 | with:
74 | node-version: lts/*
75 | - name: Download build artifacts
76 | uses: actions/download-artifact@v4
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 | GITHUB_REPOSITORY: ${{ github.repository }}
87 | GITHUB_REF: ${{ github.sha }}
88 | run: errout=$(mktemp); gh release create $(cat dist/releasetag.txt) -R $GITHUB_REPOSITORY -F dist/changelog.md -t $(cat dist/releasetag.txt) --target $GITHUB_REF 2> $errout && true; exitcode=$?; if [ $exitcode -ne 0 ] && ! grep -q "Release.tag_name already exists" $errout; then cat $errout; exit $exitcode; fi
89 | release_npm:
90 | name: Publish to npm
91 | needs: release
92 | runs-on: ubuntu-latest
93 | permissions:
94 | id-token: write
95 | contents: read
96 | if: needs.release.outputs.tag_exists != 'true' && needs.release.outputs.latest_commit == github.sha
97 | steps:
98 | - uses: actions/setup-node@v4
99 | with:
100 | node-version: lts/*
101 | - name: Download build artifacts
102 | uses: actions/download-artifact@v4
103 | with:
104 | name: build-artifact
105 | path: dist
106 | - name: Restore build artifact permissions
107 | run: cd dist && setfacl --restore=permissions-backup.acl
108 | continue-on-error: true
109 | - name: Checkout
110 | uses: actions/checkout@v4
111 | with:
112 | path: .repo
113 | - name: Install Dependencies
114 | run: cd .repo && yarn install --check-files --frozen-lockfile
115 | - name: Extract build artifact
116 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo
117 | - name: Move build artifact out of the way
118 | run: mv dist dist.old
119 | - name: Create js artifact
120 | run: cd .repo && npx projen package:js
121 | - name: Collect js artifact
122 | run: mv .repo/dist dist
123 | - name: Release
124 | env:
125 | NPM_DIST_TAG: latest
126 | NPM_REGISTRY: registry.npmjs.org
127 | NPM_CONFIG_PROVENANCE: "true"
128 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
129 | run: npx -p publib@latest publib-npm
130 | release_pypi:
131 | name: Publish to PyPI
132 | needs: release
133 | runs-on: ubuntu-latest
134 | permissions:
135 | contents: read
136 | if: needs.release.outputs.tag_exists != 'true' && needs.release.outputs.latest_commit == github.sha
137 | steps:
138 | - uses: actions/setup-node@v4
139 | with:
140 | node-version: lts/*
141 | - uses: actions/setup-python@v5
142 | with:
143 | python-version: 3.x
144 | - name: Download build artifacts
145 | uses: actions/download-artifact@v4
146 | with:
147 | name: build-artifact
148 | path: dist
149 | - name: Restore build artifact permissions
150 | run: cd dist && setfacl --restore=permissions-backup.acl
151 | continue-on-error: true
152 | - name: Checkout
153 | uses: actions/checkout@v4
154 | with:
155 | path: .repo
156 | - name: Install Dependencies
157 | run: cd .repo && yarn install --check-files --frozen-lockfile
158 | - name: Extract build artifact
159 | run: tar --strip-components=1 -xzvf dist/js/*.tgz -C .repo
160 | - name: Move build artifact out of the way
161 | run: mv dist dist.old
162 | - name: Create python artifact
163 | run: cd .repo && npx projen package:python
164 | - name: Collect python artifact
165 | run: mv .repo/dist dist
166 | - name: Release
167 | env:
168 | TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
169 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
170 | run: npx -p publib@latest publib-pypi
171 |
--------------------------------------------------------------------------------
/.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 | !/LICENSE
9 | !/.npmignore
10 | logs
11 | *.log
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 | lerna-debug.log*
16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
17 | pids
18 | *.pid
19 | *.seed
20 | *.pid.lock
21 | lib-cov
22 | coverage
23 | *.lcov
24 | .nyc_output
25 | build/Release
26 | node_modules/
27 | jspm_packages/
28 | *.tsbuildinfo
29 | .eslintcache
30 | *.tgz
31 | .yarn-integrity
32 | .cache
33 | .idea/
34 | /test-reports/
35 | junit.xml
36 | /coverage/
37 | !/.github/workflows/build.yml
38 | /dist/changelog.md
39 | /dist/version.txt
40 | !/.github/workflows/release.yml
41 | !/.mergify.yml
42 | !/.github/pull_request_template.md
43 | !/test/
44 | !/tsconfig.dev.json
45 | !/src/
46 | /lib
47 | /dist/
48 | !/.eslintrc.json
49 | .jsii
50 | tsconfig.json
51 | !/API.md
52 | !/.projenrc.ts
53 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/state-machine.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 |
3 | queue_rules:
4 | - name: default
5 | update_method: merge
6 | conditions:
7 | - "#approved-reviews-by>=1"
8 | - -label~=(do-not-merge)
9 | - status-success=build
10 | - status-success=package-js
11 | - status-success=package-python
12 | pull_request_rules:
13 | - name: Automatic merge on approval and successful build
14 | actions:
15 | delete_head_branch: {}
16 | queue:
17 | method: squash
18 | name: default
19 | commit_message_template: |-
20 | {{ title }} (#{{ number }})
21 |
22 | {{ body }}
23 | conditions:
24 | - "#approved-reviews-by>=1"
25 | - -label~=(do-not-merge)
26 | - status-success=build
27 | - status-success=package-js
28 | - status-success=package-python
29 |
--------------------------------------------------------------------------------
/.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 | /.mergify.yml
10 | /test/
11 | /tsconfig.dev.json
12 | /src/
13 | !/lib/
14 | !/lib/**/*.js
15 | !/lib/**/*.d.ts
16 | dist
17 | /tsconfig.json
18 | /.github/
19 | /.vscode/
20 | /.idea/
21 | /.projenrc.js
22 | tsconfig.tsbuildinfo
23 | /.eslintrc.json
24 | !.jsii
25 | /.gitattributes
26 | /.projenrc.ts
27 | /projenrc
28 |
--------------------------------------------------------------------------------
/.projen/deps.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": [
3 | {
4 | "name": "@matthewbonig/cdk-construct-library",
5 | "version": "0.0.14",
6 | "type": "build"
7 | },
8 | {
9 | "name": "@types/jest",
10 | "version": "28",
11 | "type": "build"
12 | },
13 | {
14 | "name": "@types/js-yaml",
15 | "type": "build"
16 | },
17 | {
18 | "name": "@types/node",
19 | "type": "build"
20 | },
21 | {
22 | "name": "@typescript-eslint/eslint-plugin",
23 | "version": "^7",
24 | "type": "build"
25 | },
26 | {
27 | "name": "@typescript-eslint/parser",
28 | "version": "^7",
29 | "type": "build"
30 | },
31 | {
32 | "name": "commit-and-tag-version",
33 | "version": "^12",
34 | "type": "build"
35 | },
36 | {
37 | "name": "eslint-import-resolver-typescript",
38 | "type": "build"
39 | },
40 | {
41 | "name": "eslint-plugin-import",
42 | "type": "build"
43 | },
44 | {
45 | "name": "eslint",
46 | "version": "^8",
47 | "type": "build"
48 | },
49 | {
50 | "name": "jest-junit",
51 | "version": "^15",
52 | "type": "build"
53 | },
54 | {
55 | "name": "jest",
56 | "version": "28",
57 | "type": "build"
58 | },
59 | {
60 | "name": "jsii-diff",
61 | "type": "build"
62 | },
63 | {
64 | "name": "jsii-docgen",
65 | "version": "^10.5.0",
66 | "type": "build"
67 | },
68 | {
69 | "name": "jsii-pacmak",
70 | "type": "build"
71 | },
72 | {
73 | "name": "jsii-rosetta",
74 | "version": "~5.5.0",
75 | "type": "build"
76 | },
77 | {
78 | "name": "jsii",
79 | "version": "~5.5.0",
80 | "type": "build"
81 | },
82 | {
83 | "name": "projen",
84 | "version": "~0.88.2",
85 | "type": "build"
86 | },
87 | {
88 | "name": "ts-jest",
89 | "version": "28",
90 | "type": "build"
91 | },
92 | {
93 | "name": "ts-node",
94 | "type": "build"
95 | },
96 | {
97 | "name": "typescript",
98 | "type": "build"
99 | },
100 | {
101 | "name": "case",
102 | "type": "bundled"
103 | },
104 | {
105 | "name": "js-yaml",
106 | "type": "bundled"
107 | },
108 | {
109 | "name": "lodash.merge",
110 | "type": "bundled"
111 | },
112 | {
113 | "name": "aws-cdk-lib",
114 | "version": "^2.85.0",
115 | "type": "peer"
116 | },
117 | {
118 | "name": "constructs",
119 | "version": "^10.3.0",
120 | "type": "peer"
121 | },
122 | {
123 | "name": "projen",
124 | "version": "^0.88.2",
125 | "type": "peer"
126 | },
127 | {
128 | "name": "case",
129 | "type": "runtime"
130 | },
131 | {
132 | "name": "js-yaml",
133 | "type": "runtime"
134 | },
135 | {
136 | "name": "lodash.merge",
137 | "type": "runtime"
138 | },
139 | {
140 | "name": "projen",
141 | "version": "^0.88.2",
142 | "type": "runtime"
143 | }
144 | ],
145 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
146 | }
147 |
--------------------------------------------------------------------------------
/.projen/files.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | ".eslintrc.json",
4 | ".gitattributes",
5 | ".github/pull_request_template.md",
6 | ".github/workflows/build.yml",
7 | ".github/workflows/pull-request-lint.yml",
8 | ".github/workflows/release.yml",
9 | ".gitignore",
10 | ".mergify.yml",
11 | ".projen/deps.json",
12 | ".projen/files.json",
13 | ".projen/tasks.json",
14 | "LICENSE",
15 | "tsconfig.dev.json"
16 | ],
17 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
18 | }
19 |
--------------------------------------------------------------------------------
/.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 | "docgen": {
105 | "name": "docgen",
106 | "description": "Generate API.md from .jsii manifest",
107 | "steps": [
108 | {
109 | "exec": "jsii-docgen -o API.md"
110 | }
111 | ]
112 | },
113 | "eject": {
114 | "name": "eject",
115 | "description": "Remove projen from the project",
116 | "env": {
117 | "PROJEN_EJECTING": "true"
118 | },
119 | "steps": [
120 | {
121 | "spawn": "default"
122 | }
123 | ]
124 | },
125 | "eslint": {
126 | "name": "eslint",
127 | "description": "Runs eslint against the codebase",
128 | "steps": [
129 | {
130 | "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern $@ src test build-tools projenrc .projenrc.ts",
131 | "receiveArgs": true
132 | }
133 | ]
134 | },
135 | "install": {
136 | "name": "install",
137 | "description": "Install project dependencies and update lockfile (non-frozen)",
138 | "steps": [
139 | {
140 | "exec": "yarn install --check-files"
141 | }
142 | ]
143 | },
144 | "install:ci": {
145 | "name": "install:ci",
146 | "description": "Install project dependencies using frozen lockfile",
147 | "steps": [
148 | {
149 | "exec": "yarn install --check-files --frozen-lockfile"
150 | }
151 | ]
152 | },
153 | "package": {
154 | "name": "package",
155 | "description": "Creates the distribution package",
156 | "steps": [
157 | {
158 | "spawn": "package:js",
159 | "condition": "node -e \"if (!process.env.CI) process.exit(1)\""
160 | },
161 | {
162 | "spawn": "package-all",
163 | "condition": "node -e \"if (process.env.CI) process.exit(1)\""
164 | }
165 | ]
166 | },
167 | "package-all": {
168 | "name": "package-all",
169 | "description": "Packages artifacts for all target languages",
170 | "steps": [
171 | {
172 | "spawn": "package:js"
173 | },
174 | {
175 | "spawn": "package:python"
176 | }
177 | ]
178 | },
179 | "package:js": {
180 | "name": "package:js",
181 | "description": "Create js language bindings",
182 | "steps": [
183 | {
184 | "exec": "jsii-pacmak -v --target js"
185 | }
186 | ]
187 | },
188 | "package:python": {
189 | "name": "package:python",
190 | "description": "Create python language bindings",
191 | "steps": [
192 | {
193 | "exec": "jsii-pacmak -v --target python"
194 | }
195 | ]
196 | },
197 | "post-compile": {
198 | "name": "post-compile",
199 | "description": "Runs after successful compilation",
200 | "steps": [
201 | {
202 | "spawn": "docgen"
203 | }
204 | ]
205 | },
206 | "pre-compile": {
207 | "name": "pre-compile",
208 | "description": "Prepare the project for compilation"
209 | },
210 | "release": {
211 | "name": "release",
212 | "description": "Prepare a release from \"main\" branch",
213 | "env": {
214 | "RELEASE": "true"
215 | },
216 | "steps": [
217 | {
218 | "exec": "rm -fr dist"
219 | },
220 | {
221 | "spawn": "bump"
222 | },
223 | {
224 | "spawn": "build"
225 | },
226 | {
227 | "spawn": "unbump"
228 | },
229 | {
230 | "exec": "git diff --ignore-space-at-eol --exit-code"
231 | }
232 | ]
233 | },
234 | "test": {
235 | "name": "test",
236 | "description": "Run tests",
237 | "steps": [
238 | {
239 | "exec": "jest --passWithNoTests --updateSnapshot",
240 | "receiveArgs": true
241 | },
242 | {
243 | "spawn": "eslint"
244 | }
245 | ]
246 | },
247 | "test:watch": {
248 | "name": "test:watch",
249 | "description": "Run jest in watch mode",
250 | "steps": [
251 | {
252 | "exec": "jest --watch"
253 | }
254 | ]
255 | },
256 | "unbump": {
257 | "name": "unbump",
258 | "description": "Restores version to 0.0.0",
259 | "env": {
260 | "OUTFILE": "package.json",
261 | "CHANGELOG": "dist/changelog.md",
262 | "BUMPFILE": "dist/version.txt",
263 | "RELEASETAG": "dist/releasetag.txt",
264 | "RELEASE_TAG_PREFIX": "",
265 | "BUMP_PACKAGE": "commit-and-tag-version@^12"
266 | },
267 | "steps": [
268 | {
269 | "builtin": "release/reset-version"
270 | }
271 | ]
272 | },
273 | "watch": {
274 | "name": "watch",
275 | "description": "Watch & compile in the background",
276 | "steps": [
277 | {
278 | "exec": "jsii -w --silence-warnings=reserved-word"
279 | }
280 | ]
281 | }
282 | },
283 | "env": {
284 | "PATH": "$(npx -c \"node --print process.env.PATH\")"
285 | },
286 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
287 | }
288 |
--------------------------------------------------------------------------------
/.projenrc.ts:
--------------------------------------------------------------------------------
1 | import { CdkConstruct } from '@matthewbonig/cdk-construct-library';
2 |
3 | const lodash = 'lodash.merge';
4 | const projenDep = 'projen@^0.88.2';
5 | const project = new CdkConstruct({
6 | description: 'A Step Function state machine construct focused on working well with the Workflow Studio',
7 | cdkVersion: '2.85.0',
8 | name: 'state-machine',
9 | constructsVersion: '10.3.0',
10 | deps: [
11 | projenDep,
12 | lodash,
13 | 'case',
14 | 'js-yaml',
15 | ],
16 | peerDeps: [
17 | projenDep,
18 | 'constructs@10.3.0',
19 | ],
20 | devDeps: [
21 | projenDep,
22 | '@types/js-yaml',
23 | '@matthewbonig/cdk-construct-library@0.0.14',
24 | ],
25 | bundledDeps: [lodash, 'case', 'js-yaml'],
26 | keywords: ['awscdk', 'cdk', 'AWS Step Functions'],
27 | disablePublishToGo: true,
28 | disablePublishToMaven: true,
29 | disablePublishToNuGet: true,
30 |
31 | });
32 | project.github!.actions.set('actions/upload-artifact', 'actions/upload-artifact@v4.3.6');
33 |
34 | project.synth();
35 |
--------------------------------------------------------------------------------
/API.md:
--------------------------------------------------------------------------------
1 | # API Reference
2 |
3 | ## Constructs
4 |
5 | ### StateMachine
6 |
7 | #### Initializers
8 |
9 | ```typescript
10 | import { StateMachine } from '@matthewbonig/state-machine'
11 |
12 | new StateMachine(scope: Construct, id: string, props: StateMachineProps)
13 | ```
14 |
15 | | **Name** | **Type** | **Description** |
16 | | --- | --- | --- |
17 | | scope
| constructs.Construct
| *No description.* |
18 | | id
| string
| *No description.* |
19 | | props
| StateMachineProps
| *No description.* |
20 |
21 | ---
22 |
23 | ##### `scope`Required
24 |
25 | - *Type:* constructs.Construct
26 |
27 | ---
28 |
29 | ##### `id`Required
30 |
31 | - *Type:* string
32 |
33 | ---
34 |
35 | ##### `props`Required
36 |
37 | - *Type:* StateMachineProps
38 |
39 | ---
40 |
41 | #### Methods
42 |
43 | | **Name** | **Description** |
44 | | --- | --- |
45 | | toString
| Returns a string representation of this construct. |
46 | | applyRemovalPolicy
| Apply the given removal policy to this resource. |
47 | | addToRolePolicy
| Add the given statement to the role's policy. |
48 | | grant
| Grant the given identity custom permissions. |
49 | | grantExecution
| Grant the given identity permissions on all executions of the state machine. |
50 | | grantRead
| Grant the given identity permissions to read results from state machine. |
51 | | grantStartExecution
| Grant the given identity permissions to start an execution of this state machine. |
52 | | grantStartSyncExecution
| Grant the given identity permissions to start a synchronous execution of this state machine. |
53 | | grantTaskResponse
| Grant the given identity task response permissions on a state machine. |
54 | | metric
| Return the given named metric for this State Machine's executions. |
55 | | metricAborted
| Metric for the number of executions that were aborted. |
56 | | metricFailed
| Metric for the number of executions that failed. |
57 | | metricStarted
| Metric for the number of executions that were started. |
58 | | metricSucceeded
| Metric for the number of executions that succeeded. |
59 | | metricThrottled
| Metric for the number of executions that were throttled. |
60 | | metricTime
| Metric for the interval, in milliseconds, between the time the execution starts and the time it closes. |
61 | | metricTimedOut
| Metric for the number of executions that timed out. |
62 |
63 | ---
64 |
65 | ##### `toString`
66 |
67 | ```typescript
68 | public toString(): string
69 | ```
70 |
71 | Returns a string representation of this construct.
72 |
73 | ##### `applyRemovalPolicy`
74 |
75 | ```typescript
76 | public applyRemovalPolicy(policy: RemovalPolicy): void
77 | ```
78 |
79 | Apply the given removal policy to this resource.
80 |
81 | The Removal Policy controls what happens to this resource when it stops
82 | being managed by CloudFormation, either because you've removed it from the
83 | CDK application or because you've made a change that requires the resource
84 | to be replaced.
85 |
86 | The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS
87 | account for data recovery and cleanup later (`RemovalPolicy.RETAIN`).
88 |
89 | ###### `policy`Required
90 |
91 | - *Type:* aws-cdk-lib.RemovalPolicy
92 |
93 | ---
94 |
95 | ##### `addToRolePolicy`
96 |
97 | ```typescript
98 | public addToRolePolicy(statement: PolicyStatement): void
99 | ```
100 |
101 | Add the given statement to the role's policy.
102 |
103 | ###### `statement`Required
104 |
105 | - *Type:* aws-cdk-lib.aws_iam.PolicyStatement
106 |
107 | ---
108 |
109 | ##### `grant`
110 |
111 | ```typescript
112 | public grant(identity: IGrantable, actions: ...string[]): Grant
113 | ```
114 |
115 | Grant the given identity custom permissions.
116 |
117 | ###### `identity`Required
118 |
119 | - *Type:* aws-cdk-lib.aws_iam.IGrantable
120 |
121 | ---
122 |
123 | ###### `actions`Required
124 |
125 | - *Type:* ...string[]
126 |
127 | ---
128 |
129 | ##### `grantExecution`
130 |
131 | ```typescript
132 | public grantExecution(identity: IGrantable, actions: ...string[]): Grant
133 | ```
134 |
135 | Grant the given identity permissions on all executions of the state machine.
136 |
137 | ###### `identity`Required
138 |
139 | - *Type:* aws-cdk-lib.aws_iam.IGrantable
140 |
141 | ---
142 |
143 | ###### `actions`Required
144 |
145 | - *Type:* ...string[]
146 |
147 | ---
148 |
149 | ##### `grantRead`
150 |
151 | ```typescript
152 | public grantRead(identity: IGrantable): Grant
153 | ```
154 |
155 | Grant the given identity permissions to read results from state machine.
156 |
157 | ###### `identity`Required
158 |
159 | - *Type:* aws-cdk-lib.aws_iam.IGrantable
160 |
161 | ---
162 |
163 | ##### `grantStartExecution`
164 |
165 | ```typescript
166 | public grantStartExecution(identity: IGrantable): Grant
167 | ```
168 |
169 | Grant the given identity permissions to start an execution of this state machine.
170 |
171 | ###### `identity`Required
172 |
173 | - *Type:* aws-cdk-lib.aws_iam.IGrantable
174 |
175 | ---
176 |
177 | ##### `grantStartSyncExecution`
178 |
179 | ```typescript
180 | public grantStartSyncExecution(identity: IGrantable): Grant
181 | ```
182 |
183 | Grant the given identity permissions to start a synchronous execution of this state machine.
184 |
185 | ###### `identity`Required
186 |
187 | - *Type:* aws-cdk-lib.aws_iam.IGrantable
188 |
189 | ---
190 |
191 | ##### `grantTaskResponse`
192 |
193 | ```typescript
194 | public grantTaskResponse(identity: IGrantable): Grant
195 | ```
196 |
197 | Grant the given identity task response permissions on a state machine.
198 |
199 | ###### `identity`Required
200 |
201 | - *Type:* aws-cdk-lib.aws_iam.IGrantable
202 |
203 | ---
204 |
205 | ##### `metric`
206 |
207 | ```typescript
208 | public metric(metricName: string, props?: MetricOptions): Metric
209 | ```
210 |
211 | Return the given named metric for this State Machine's executions.
212 |
213 | ###### `metricName`Required
214 |
215 | - *Type:* string
216 |
217 | ---
218 |
219 | ###### `props`Optional
220 |
221 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
222 |
223 | ---
224 |
225 | ##### `metricAborted`
226 |
227 | ```typescript
228 | public metricAborted(props?: MetricOptions): Metric
229 | ```
230 |
231 | Metric for the number of executions that were aborted.
232 |
233 | ###### `props`Optional
234 |
235 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
236 |
237 | ---
238 |
239 | ##### `metricFailed`
240 |
241 | ```typescript
242 | public metricFailed(props?: MetricOptions): Metric
243 | ```
244 |
245 | Metric for the number of executions that failed.
246 |
247 | ###### `props`Optional
248 |
249 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
250 |
251 | ---
252 |
253 | ##### `metricStarted`
254 |
255 | ```typescript
256 | public metricStarted(props?: MetricOptions): Metric
257 | ```
258 |
259 | Metric for the number of executions that were started.
260 |
261 | ###### `props`Optional
262 |
263 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
264 |
265 | ---
266 |
267 | ##### `metricSucceeded`
268 |
269 | ```typescript
270 | public metricSucceeded(props?: MetricOptions): Metric
271 | ```
272 |
273 | Metric for the number of executions that succeeded.
274 |
275 | ###### `props`Optional
276 |
277 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
278 |
279 | ---
280 |
281 | ##### `metricThrottled`
282 |
283 | ```typescript
284 | public metricThrottled(props?: MetricOptions): Metric
285 | ```
286 |
287 | Metric for the number of executions that were throttled.
288 |
289 | ###### `props`Optional
290 |
291 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
292 |
293 | ---
294 |
295 | ##### `metricTime`
296 |
297 | ```typescript
298 | public metricTime(props?: MetricOptions): Metric
299 | ```
300 |
301 | Metric for the interval, in milliseconds, between the time the execution starts and the time it closes.
302 |
303 | ###### `props`Optional
304 |
305 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
306 |
307 | ---
308 |
309 | ##### `metricTimedOut`
310 |
311 | ```typescript
312 | public metricTimedOut(props?: MetricOptions): Metric
313 | ```
314 |
315 | Metric for the number of executions that timed out.
316 |
317 | ###### `props`Optional
318 |
319 | - *Type:* aws-cdk-lib.aws_cloudwatch.MetricOptions
320 |
321 | ---
322 |
323 | #### Static Functions
324 |
325 | | **Name** | **Description** |
326 | | --- | --- |
327 | | isConstruct
| Checks if `x` is a construct. |
328 | | isOwnedResource
| Returns true if the construct was created by CDK, and false otherwise. |
329 | | isResource
| Check whether the given construct is a Resource. |
330 | | fromStateMachineArn
| Import a state machine. |
331 | | fromStateMachineName
| Import a state machine via resource name. |
332 |
333 | ---
334 |
335 | ##### `isConstruct`
336 |
337 | ```typescript
338 | import { StateMachine } from '@matthewbonig/state-machine'
339 |
340 | StateMachine.isConstruct(x: any)
341 | ```
342 |
343 | Checks if `x` is a construct.
344 |
345 | Use this method instead of `instanceof` to properly detect `Construct`
346 | instances, even when the construct library is symlinked.
347 |
348 | Explanation: in JavaScript, multiple copies of the `constructs` library on
349 | disk are seen as independent, completely different libraries. As a
350 | consequence, the class `Construct` in each copy of the `constructs` library
351 | is seen as a different class, and an instance of one class will not test as
352 | `instanceof` the other class. `npm install` will not create installations
353 | like this, but users may manually symlink construct libraries together or
354 | use a monorepo tool: in those cases, multiple copies of the `constructs`
355 | library can be accidentally installed, and `instanceof` will behave
356 | unpredictably. It is safest to avoid using `instanceof`, and using
357 | this type-testing method instead.
358 |
359 | ###### `x`Required
360 |
361 | - *Type:* any
362 |
363 | Any object.
364 |
365 | ---
366 |
367 | ##### `isOwnedResource`
368 |
369 | ```typescript
370 | import { StateMachine } from '@matthewbonig/state-machine'
371 |
372 | StateMachine.isOwnedResource(construct: IConstruct)
373 | ```
374 |
375 | Returns true if the construct was created by CDK, and false otherwise.
376 |
377 | ###### `construct`Required
378 |
379 | - *Type:* constructs.IConstruct
380 |
381 | ---
382 |
383 | ##### `isResource`
384 |
385 | ```typescript
386 | import { StateMachine } from '@matthewbonig/state-machine'
387 |
388 | StateMachine.isResource(construct: IConstruct)
389 | ```
390 |
391 | Check whether the given construct is a Resource.
392 |
393 | ###### `construct`Required
394 |
395 | - *Type:* constructs.IConstruct
396 |
397 | ---
398 |
399 | ##### `fromStateMachineArn`
400 |
401 | ```typescript
402 | import { StateMachine } from '@matthewbonig/state-machine'
403 |
404 | StateMachine.fromStateMachineArn(scope: Construct, id: string, stateMachineArn: string)
405 | ```
406 |
407 | Import a state machine.
408 |
409 | ###### `scope`Required
410 |
411 | - *Type:* constructs.Construct
412 |
413 | ---
414 |
415 | ###### `id`Required
416 |
417 | - *Type:* string
418 |
419 | ---
420 |
421 | ###### `stateMachineArn`Required
422 |
423 | - *Type:* string
424 |
425 | ---
426 |
427 | ##### `fromStateMachineName`
428 |
429 | ```typescript
430 | import { StateMachine } from '@matthewbonig/state-machine'
431 |
432 | StateMachine.fromStateMachineName(scope: Construct, id: string, stateMachineName: string)
433 | ```
434 |
435 | Import a state machine via resource name.
436 |
437 | ###### `scope`Required
438 |
439 | - *Type:* constructs.Construct
440 |
441 | ---
442 |
443 | ###### `id`Required
444 |
445 | - *Type:* string
446 |
447 | ---
448 |
449 | ###### `stateMachineName`Required
450 |
451 | - *Type:* string
452 |
453 | ---
454 |
455 | #### Properties
456 |
457 | | **Name** | **Type** | **Description** |
458 | | --- | --- | --- |
459 | | node
| constructs.Node
| The tree node. |
460 | | env
| aws-cdk-lib.ResourceEnvironment
| The environment this resource belongs to. |
461 | | stack
| aws-cdk-lib.Stack
| The stack in which this resource is defined. |
462 | | grantPrincipal
| aws-cdk-lib.aws_iam.IPrincipal
| The principal this state machine is running as. |
463 | | role
| aws-cdk-lib.aws_iam.IRole
| Execution role of this state machine. |
464 | | stateMachineArn
| string
| The ARN of the state machine. |
465 | | stateMachineName
| string
| The name of the state machine. |
466 | | stateMachineType
| aws-cdk-lib.aws_stepfunctions.StateMachineType
| Type of the state machine. |
467 |
468 | ---
469 |
470 | ##### `node`Required
471 |
472 | ```typescript
473 | public readonly node: Node;
474 | ```
475 |
476 | - *Type:* constructs.Node
477 |
478 | The tree node.
479 |
480 | ---
481 |
482 | ##### `env`Required
483 |
484 | ```typescript
485 | public readonly env: ResourceEnvironment;
486 | ```
487 |
488 | - *Type:* aws-cdk-lib.ResourceEnvironment
489 |
490 | The environment this resource belongs to.
491 |
492 | For resources that are created and managed by the CDK
493 | (generally, those created by creating new class instances like Role, Bucket, etc.),
494 | this is always the same as the environment of the stack they belong to;
495 | however, for imported resources
496 | (those obtained from static methods like fromRoleArn, fromBucketName, etc.),
497 | that might be different than the stack they were imported into.
498 |
499 | ---
500 |
501 | ##### `stack`Required
502 |
503 | ```typescript
504 | public readonly stack: Stack;
505 | ```
506 |
507 | - *Type:* aws-cdk-lib.Stack
508 |
509 | The stack in which this resource is defined.
510 |
511 | ---
512 |
513 | ##### `grantPrincipal`Required
514 |
515 | ```typescript
516 | public readonly grantPrincipal: IPrincipal;
517 | ```
518 |
519 | - *Type:* aws-cdk-lib.aws_iam.IPrincipal
520 |
521 | The principal this state machine is running as.
522 |
523 | ---
524 |
525 | ##### `role`Required
526 |
527 | ```typescript
528 | public readonly role: IRole;
529 | ```
530 |
531 | - *Type:* aws-cdk-lib.aws_iam.IRole
532 |
533 | Execution role of this state machine.
534 |
535 | ---
536 |
537 | ##### `stateMachineArn`Required
538 |
539 | ```typescript
540 | public readonly stateMachineArn: string;
541 | ```
542 |
543 | - *Type:* string
544 |
545 | The ARN of the state machine.
546 |
547 | ---
548 |
549 | ##### `stateMachineName`Required
550 |
551 | ```typescript
552 | public readonly stateMachineName: string;
553 | ```
554 |
555 | - *Type:* string
556 |
557 | The name of the state machine.
558 |
559 | ---
560 |
561 | ##### `stateMachineType`Required
562 |
563 | ```typescript
564 | public readonly stateMachineType: StateMachineType;
565 | ```
566 |
567 | - *Type:* aws-cdk-lib.aws_stepfunctions.StateMachineType
568 |
569 | Type of the state machine.
570 |
571 | ---
572 |
573 |
574 | ### StepFunctionsAutoDiscover
575 |
576 | A projen component for discovering AWS Step Function state machine workflow ASL files and generating a strongly typed interface and construct to use it.
577 |
578 | Simply add a new instance and hand it your AwsCdkTypeScriptApp projen class:
579 | ```
580 | const project = new AwsCdkTypeScriptApp({ ... });
581 | new StepFunctionsAutoDiscover(project);
582 | ```
583 |
584 | And any *.workflow.json file will cause the generation of a new strongly-typed StateMachine-derived class you can use.
585 | Note that these constructs are NOT jsii-compatible. If you need that,
586 | please open an [issue](https://github.com/mbonig/state-machine/issues/new)
587 |
588 | #### Initializers
589 |
590 | ```typescript
591 | import { StepFunctionsAutoDiscover } from '@matthewbonig/state-machine'
592 |
593 | new StepFunctionsAutoDiscover(project: AwsCdkTypeScriptApp, _options?: StepFunctionsAutoDiscoverOptions)
594 | ```
595 |
596 | | **Name** | **Type** | **Description** |
597 | | --- | --- | --- |
598 | | project
| projen.awscdk.AwsCdkTypeScriptApp
| *No description.* |
599 | | _options
| StepFunctionsAutoDiscoverOptions
| *No description.* |
600 |
601 | ---
602 |
603 | ##### `project`Required
604 |
605 | - *Type:* projen.awscdk.AwsCdkTypeScriptApp
606 |
607 | ---
608 |
609 | ##### `_options`Optional
610 |
611 | - *Type:* StepFunctionsAutoDiscoverOptions
612 |
613 | ---
614 |
615 | #### Methods
616 |
617 | | **Name** | **Description** |
618 | | --- | --- |
619 | | toString
| Returns a string representation of this construct. |
620 | | postSynthesize
| Called after synthesis. |
621 | | preSynthesize
| Called before synthesis. |
622 | | synthesize
| Synthesizes files to the project output directory. |
623 |
624 | ---
625 |
626 | ##### `toString`
627 |
628 | ```typescript
629 | public toString(): string
630 | ```
631 |
632 | Returns a string representation of this construct.
633 |
634 | ##### `postSynthesize`
635 |
636 | ```typescript
637 | public postSynthesize(): void
638 | ```
639 |
640 | Called after synthesis.
641 |
642 | Order is *not* guaranteed.
643 |
644 | ##### `preSynthesize`
645 |
646 | ```typescript
647 | public preSynthesize(): void
648 | ```
649 |
650 | Called before synthesis.
651 |
652 | ##### `synthesize`
653 |
654 | ```typescript
655 | public synthesize(): void
656 | ```
657 |
658 | Synthesizes files to the project output directory.
659 |
660 | #### Static Functions
661 |
662 | | **Name** | **Description** |
663 | | --- | --- |
664 | | isConstruct
| Checks if `x` is a construct. |
665 | | isComponent
| Test whether the given construct is a component. |
666 |
667 | ---
668 |
669 | ##### `isConstruct`
670 |
671 | ```typescript
672 | import { StepFunctionsAutoDiscover } from '@matthewbonig/state-machine'
673 |
674 | StepFunctionsAutoDiscover.isConstruct(x: any)
675 | ```
676 |
677 | Checks if `x` is a construct.
678 |
679 | Use this method instead of `instanceof` to properly detect `Construct`
680 | instances, even when the construct library is symlinked.
681 |
682 | Explanation: in JavaScript, multiple copies of the `constructs` library on
683 | disk are seen as independent, completely different libraries. As a
684 | consequence, the class `Construct` in each copy of the `constructs` library
685 | is seen as a different class, and an instance of one class will not test as
686 | `instanceof` the other class. `npm install` will not create installations
687 | like this, but users may manually symlink construct libraries together or
688 | use a monorepo tool: in those cases, multiple copies of the `constructs`
689 | library can be accidentally installed, and `instanceof` will behave
690 | unpredictably. It is safest to avoid using `instanceof`, and using
691 | this type-testing method instead.
692 |
693 | ###### `x`Required
694 |
695 | - *Type:* any
696 |
697 | Any object.
698 |
699 | ---
700 |
701 | ##### `isComponent`
702 |
703 | ```typescript
704 | import { StepFunctionsAutoDiscover } from '@matthewbonig/state-machine'
705 |
706 | StepFunctionsAutoDiscover.isComponent(x: any)
707 | ```
708 |
709 | Test whether the given construct is a component.
710 |
711 | ###### `x`Required
712 |
713 | - *Type:* any
714 |
715 | ---
716 |
717 | #### Properties
718 |
719 | | **Name** | **Type** | **Description** |
720 | | --- | --- | --- |
721 | | node
| constructs.Node
| The tree node. |
722 | | project
| projen.Project
| *No description.* |
723 | | entrypoints
| string[]
| Auto-discovered entry points with paths relative to the project directory. |
724 |
725 | ---
726 |
727 | ##### `node`Required
728 |
729 | ```typescript
730 | public readonly node: Node;
731 | ```
732 |
733 | - *Type:* constructs.Node
734 |
735 | The tree node.
736 |
737 | ---
738 |
739 | ##### `project`Required
740 |
741 | ```typescript
742 | public readonly project: Project;
743 | ```
744 |
745 | - *Type:* projen.Project
746 |
747 | ---
748 |
749 | ##### `entrypoints`Required
750 |
751 | ```typescript
752 | public readonly entrypoints: string[];
753 | ```
754 |
755 | - *Type:* string[]
756 |
757 | Auto-discovered entry points with paths relative to the project directory.
758 |
759 | ---
760 |
761 |
762 | ## Structs
763 |
764 | ### StateMachineProps
765 |
766 | #### Initializer
767 |
768 | ```typescript
769 | import { StateMachineProps } from '@matthewbonig/state-machine'
770 |
771 | const stateMachineProps: StateMachineProps = { ... }
772 | ```
773 |
774 | #### Properties
775 |
776 | | **Name** | **Type** | **Description** |
777 | | --- | --- | --- |
778 | | definition
| any
| An object that can be serialized into an ASL. |
779 | | aslYaml
| boolean
| Should the ASL definition be written as YAML. |
780 | | logs
| aws-cdk-lib.aws_stepfunctions.LogOptions
| Defines what execution history events are logged and where they are logged. |
781 | | overrides
| any
| An object that matches the schema/shape of the ASL .States map with overridden values. |
782 | | role
| aws-cdk-lib.aws_iam.IRole
| The execution role for the state machine service. |
783 | | stateMachineName
| string
| A name for the state machine. |
784 | | stateMachineType
| aws-cdk-lib.aws_stepfunctions.StateMachineType
| Type of the state machine. |
785 | | timeout
| aws-cdk-lib.Duration
| Maximum run time for this state machine. |
786 | | tracingEnabled
| boolean
| Specifies whether Amazon X-Ray tracing is enabled for this state machine. |
787 |
788 | ---
789 |
790 | ##### `definition`Required
791 |
792 | ```typescript
793 | public readonly definition: any;
794 | ```
795 |
796 | - *Type:* any
797 |
798 | An object that can be serialized into an ASL.
799 |
800 | ---
801 |
802 | ##### `aslYaml`Optional
803 |
804 | ```typescript
805 | public readonly aslYaml: boolean;
806 | ```
807 |
808 | - *Type:* boolean
809 | - *Default:* false
810 |
811 | Should the ASL definition be written as YAML.
812 |
813 | ---
814 |
815 | ##### `logs`Optional
816 |
817 | ```typescript
818 | public readonly logs: LogOptions;
819 | ```
820 |
821 | - *Type:* aws-cdk-lib.aws_stepfunctions.LogOptions
822 | - *Default:* No logging
823 |
824 | Defines what execution history events are logged and where they are logged.
825 |
826 | ---
827 |
828 | ##### `overrides`Optional
829 |
830 | ```typescript
831 | public readonly overrides: any;
832 | ```
833 |
834 | - *Type:* any
835 |
836 | An object that matches the schema/shape of the ASL .States map with overridden values.
837 |
838 | ---
839 |
840 | *Example*
841 |
842 | ```typescript
843 | {'My First State': { Parameters: { FunctionName: 'aLambdaFunctionArn' } } }
844 | ```
845 |
846 |
847 | ##### `role`Optional
848 |
849 | ```typescript
850 | public readonly role: IRole;
851 | ```
852 |
853 | - *Type:* aws-cdk-lib.aws_iam.IRole
854 | - *Default:* A role is automatically created
855 |
856 | The execution role for the state machine service.
857 |
858 | ---
859 |
860 | ##### `stateMachineName`Optional
861 |
862 | ```typescript
863 | public readonly stateMachineName: string;
864 | ```
865 |
866 | - *Type:* string
867 | - *Default:* A name is automatically generated
868 |
869 | A name for the state machine.
870 |
871 | ---
872 |
873 | ##### `stateMachineType`Optional
874 |
875 | ```typescript
876 | public readonly stateMachineType: StateMachineType;
877 | ```
878 |
879 | - *Type:* aws-cdk-lib.aws_stepfunctions.StateMachineType
880 | - *Default:* StateMachineType.STANDARD
881 |
882 | Type of the state machine.
883 |
884 | ---
885 |
886 | ##### `timeout`Optional
887 |
888 | ```typescript
889 | public readonly timeout: Duration;
890 | ```
891 |
892 | - *Type:* aws-cdk-lib.Duration
893 | - *Default:* No timeout
894 |
895 | Maximum run time for this state machine.
896 |
897 | ---
898 |
899 | ##### `tracingEnabled`Optional
900 |
901 | ```typescript
902 | public readonly tracingEnabled: boolean;
903 | ```
904 |
905 | - *Type:* boolean
906 | - *Default:* false
907 |
908 | Specifies whether Amazon X-Ray tracing is enabled for this state machine.
909 |
910 | ---
911 |
912 | ### StepFunctionsAutoDiscoverOptions
913 |
914 | #### Initializer
915 |
916 | ```typescript
917 | import { StepFunctionsAutoDiscoverOptions } from '@matthewbonig/state-machine'
918 |
919 | const stepFunctionsAutoDiscoverOptions: StepFunctionsAutoDiscoverOptions = { ... }
920 | ```
921 |
922 | #### Properties
923 |
924 | | **Name** | **Type** | **Description** |
925 | | --- | --- | --- |
926 | | extension
| string
| An optional extension to use for discovering state machine files. |
927 |
928 | ---
929 |
930 | ##### `extension`Optional
931 |
932 | ```typescript
933 | public readonly extension: string;
934 | ```
935 |
936 | - *Type:* string
937 | - *Default:* '.workflow.json' (JSON_STEPFUNCTION_EXT)
938 |
939 | An optional extension to use for discovering state machine files.
940 |
941 | ---
942 |
943 |
944 |
945 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024 Matthew Bonig
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Workflow Studio compatible State Machine
2 |
3 | [](https://constructs.dev/packages/@matthewbonig/state-machine)
4 |
5 | This is a Workflow Studio compatible AWS Step Function state machine construct.
6 |
7 | The goal of this construct is to make it easy to build and maintain your state machines using the Workflow Studio but still
8 | leverage the AWS CDK as the source of truth for the state machine.
9 |
10 | Read more about it [here](https://matthewbonig.com/2022/02/19/step-functions-and-the-cdk/).
11 |
12 | ## How to Use This Construct
13 |
14 | Start by designing your initial state machine using the Workflow Studio.
15 | When done with your first draft, copy and paste the ASL definition to a local file.
16 |
17 | Create a new instance of this construct, handing it a fully parsed version of the ASL.
18 | Then add overridden values.
19 | The fields in the `overrides` field should match the `States` field of the ASL.
20 |
21 | ## Version Usage
22 |
23 | The AWS CDK `StateMachine` construct introduced a change in version [**2.85.0**](https://github.com/aws/aws-cdk/pull/25932) that deprecated an earlier usage of 'definition'
24 | by this construct. This construct has been updated to use the new 'definitionBody' field.
25 |
26 | If you are using a version of the CDK before version **2.85.0**, you should use version **0.0.28** of this construct.
27 |
28 | If you are using a version fo the CDK great or equal to **2.85.0**, you should use version **0.0.29+** of this construct.
29 |
30 | ### Projen component
31 |
32 | There is a projen component included in this library which will help you in using the construct. It works similar
33 | to the [auto-discovery feature](https://projen.io/docs/integrations/aws/#aws-lambda-functions). To use it, first add the component
34 | to your projen project:
35 |
36 | ```js
37 | // ...
38 | const { StepFunctionsAutoDiscover } = require('@matthewbonig/state-machine');
39 |
40 | const project = new awscdk.AwsCdkTypeScriptApp({
41 | // ...,
42 | deps: [
43 | // ...,
44 | '@matthewbonig/state-machine',
45 | ]
46 | });
47 |
48 | new StepFunctionsAutoDiscover(project);
49 | ```
50 |
51 | Now projen will look for any files with a suffix `.workflow.json` and generate new files beside the .json:
52 | * A typed `overrides` interface which is based on your workflow.
53 | * A construct derived from `StateMachine` that uses this override.
54 |
55 | Instead of using the `StateMachine` construct directly you can now use the generated one:
56 |
57 | ```text
58 | .
59 | ├── MyFancyThing.workflow.json
60 | └── MyFancyThing-statemachine.ts
61 | ```
62 |
63 | ```ts
64 | export class SomeStack extends Stack {
65 | constructor(scope: Construct, id: string, props: StackProps) {
66 | super(scope, id, props);
67 | const handler = new NodejsFunction(this, 'MyHandler');
68 | new SomeFancyThingStateMachine(this, 'MyFancyWorkflow', {
69 | overrides: {
70 | 'My First State': {
71 | Parameters: {
72 | FunctionName: handler.functionName
73 | }
74 | }
75 | }
76 | })
77 | }
78 | }
79 | ```
80 |
81 | > :warning: **The interfaces and constructs generated here are NOT jsii compliant (they use Partials and Omits) and cannot be
82 | compiled by jsii into other languages. If you plan to distribute any libraries you cannot use this.**
83 |
84 | ### Alternative Extensions
85 |
86 | There is an optional parameter, `extension` that you can pass to have it search for alternative extensions.
87 | AWS recommends that ASL definition files have a `.asl.json` extension, which will be picked up by some IDE
88 | tools. This extension was recommended after initial development of this component. Therefore, the default is
89 | to use the original extension. But, you can override this by passing a different extension to the
90 | AutoDiscover's constructor options. There are two constants defined, `JSON_STEPFUNCTION_EXT` and `AWS_RECOMMENDED_JSON_EXT` that you can use.
91 |
92 | ```js
93 | // ...
94 | const { StepFunctionsAutoDiscover, AWS_RECOMMENDED_JSON_EXT } = require('@matthewbonig/state-machine');
95 |
96 | const project = new awscdk.AwsCdkTypeScriptApp({
97 | // ...,
98 | deps: [
99 | // ...,
100 | '@matthewbonig/state-machine',
101 | ]
102 | });
103 |
104 | new StepFunctionsAutoDiscover(project, { extension: AWS_RECOMMENDED_JSON_EXT });
105 | ```
106 |
107 | ### Yaml files
108 |
109 | Yaml files are supported as well. You can provide an extension to the AutoDiscover component to have it search for yaml files. If the file has 'yaml' or 'yml' anywhere in the name it will be parsed as yaml. If not, it will be parsed as json.
110 |
111 | ```js
112 | // ...
113 | const { StepFunctionsAutoDiscover } = require('@matthewbonig/state-machine');
114 |
115 | const project = new awscdk.AwsCdkTypeScriptApp({
116 | // ...,
117 | deps: [
118 | // ...,
119 | '@matthewbonig/state-machine',
120 | ]
121 | });
122 |
123 | new StepFunctionsAutoDiscover(project, { extension: '.yaml.asl' });
124 | ```
125 |
126 | ### Examples
127 |
128 | ```ts
129 | const secret = new Secret(stack, 'Secret', {});
130 | new StateMachine(stack, 'Test', {
131 | stateMachineName: 'A nice state machine',
132 | definition: JSON.parse(fs.readFileSync(path.join(__dirname, 'sample.json'), 'utf8').toString()),
133 | overrides: {
134 | 'Read database credentials secret': {
135 | Parameters: {
136 | SecretId: secret.secretArn,
137 | },
138 | },
139 | },
140 | });
141 | ```
142 |
143 | You can also override nested states in arrays, for example:
144 |
145 | ```ts
146 | new StateMachine(stack, 'Test', {
147 | stateMachineName: 'A-nice-state-machine',
148 | overrides: {
149 | Branches: [{
150 | // pass an empty object too offset overrides
151 | }, {
152 | StartAt: 'StartInstances',
153 | States: {
154 | StartInstances: {
155 | Parameters: {
156 | InstanceIds: ['INSTANCE_ID'],
157 | },
158 | },
159 | },
160 | }],
161 | },
162 | stateMachineType: StateMachineType.STANDARD,
163 | definition: {
164 | States: {
165 | Branches: [
166 | {
167 | StartAt: 'ResumeCluster',
168 | States: {
169 | 'Redshift Pass': {
170 | Type: 'Pass',
171 | End: true,
172 | },
173 | },
174 | },
175 | {
176 | StartAt: 'StartInstances',
177 | States: {
178 | 'StartInstances': {
179 | Type: 'Task',
180 | Parameters: {
181 | InstanceIds: [
182 | 'MyData',
183 | ],
184 | },
185 | Resource: 'arn:aws:states:::aws-sdk:ec2:startInstances',
186 | Next: 'DescribeInstanceStatus',
187 | },
188 | 'DescribeInstanceStatus': {
189 | Type: 'Task',
190 | Next: 'EC2 Pass',
191 | Parameters: {
192 | InstanceIds: [
193 | 'MyData',
194 | ],
195 | },
196 | Resource: 'arn:aws:states:::aws-sdk:ec2:describeInstanceStatus',
197 | },
198 | 'EC2 Pass': {
199 | Type: 'Pass',
200 | End: true,
201 | },
202 | },
203 | },
204 | ],
205 | },
206 | },
207 | });
208 | ```
209 |
210 | For Python, be sure to use a context manager when opening your JSON file.
211 | - You do not need to `str()` the dictionary object you supply as your `definition` prop.
212 | - Elements of your override path **do** need to be strings.
213 |
214 | ```python
215 | secret = Secret(stack, 'Secret')
216 |
217 | with open('sample.json', 'r+', encoding='utf-8') as sample:
218 | sample_dict = json.load(sample)
219 |
220 | state_machine = StateMachine(
221 | self,
222 | 'Test',
223 | definition = sample_dict,
224 | overrides = {
225 | "Read database credentials secret": {
226 | "Parameters": {
227 | "SecretId": secret.secret_arn,
228 | },
229 | },
230 | })
231 | ```
232 |
233 | In this example, the ASL has a state called 'Read database credentials secret' and the SecretId parameter is overridden with a
234 | CDK generated value.
235 | Future changes can be done by editing, debugging, and testing the state machine directly in the Workflow Studio.
236 | Once everything is working properly, copy and paste the ASL back to your local file.
237 |
238 | ## Issues
239 |
240 | Please open any issues you have on [Github](https://github.com/mbonig/state-machine/issues).
241 |
242 | ## Contributing
243 |
244 | Please submit PRs from forked repositories if you'd like to contribute.
245 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@matthewbonig/state-machine",
3 | "description": "A Step Function state machine construct focused on working well with the Workflow Studio",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/mbonig/state-machine.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 | "docgen": "npx projen docgen",
16 | "eject": "npx projen eject",
17 | "eslint": "npx projen eslint",
18 | "package": "npx projen package",
19 | "package-all": "npx projen package-all",
20 | "package:js": "npx projen package:js",
21 | "package:python": "npx projen package:python",
22 | "post-compile": "npx projen post-compile",
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 | "watch": "npx projen watch",
29 | "projen": "npx projen"
30 | },
31 | "author": {
32 | "name": "Matthew Bonig",
33 | "email": "matthew.bonig@gmail.com",
34 | "organization": false
35 | },
36 | "devDependencies": {
37 | "@matthewbonig/cdk-construct-library": "0.0.14",
38 | "@types/jest": "28",
39 | "@types/js-yaml": "^4.0.5",
40 | "@types/node": "^18",
41 | "@typescript-eslint/eslint-plugin": "^7",
42 | "@typescript-eslint/parser": "^7",
43 | "aws-cdk-lib": "2.85.0",
44 | "commit-and-tag-version": "^12",
45 | "constructs": "10.3.0",
46 | "eslint": "^8",
47 | "eslint-import-resolver-typescript": "^3.6.3",
48 | "eslint-plugin-import": "^2.31.0",
49 | "jest": "28",
50 | "jest-junit": "^15",
51 | "jsii": "~5.5.0",
52 | "jsii-diff": "^1.55.1",
53 | "jsii-docgen": "^10.5.0",
54 | "jsii-pacmak": "^1.101.0",
55 | "jsii-rosetta": "~5.5.0",
56 | "projen": "0.88.2",
57 | "ts-jest": "28",
58 | "ts-node": "^10.9.1",
59 | "typescript": "^4.9.4"
60 | },
61 | "peerDependencies": {
62 | "aws-cdk-lib": "^2.85.0",
63 | "constructs": "^10.3.0",
64 | "projen": "^0.88.2"
65 | },
66 | "dependencies": {
67 | "case": "^1.6.3",
68 | "js-yaml": "^4.1.0",
69 | "lodash.merge": "^4.6.2",
70 | "projen": "^0.88.2"
71 | },
72 | "bundledDependencies": [
73 | "case",
74 | "js-yaml",
75 | "lodash.merge"
76 | ],
77 | "keywords": [
78 | "AWS Step Functions",
79 | "awscdk",
80 | "cdk"
81 | ],
82 | "main": "lib/index.js",
83 | "license": "MIT",
84 | "publishConfig": {
85 | "access": "public"
86 | },
87 | "version": "0.0.0",
88 | "jest": {
89 | "coverageProvider": "v8",
90 | "testMatch": [
91 | "/@(src|test)/**/*(*.)@(spec|test).ts?(x)",
92 | "/@(src|test)/**/__tests__/**/*.ts?(x)",
93 | "/@(projenrc)/**/*(*.)@(spec|test).ts?(x)",
94 | "/@(projenrc)/**/__tests__/**/*.ts?(x)"
95 | ],
96 | "clearMocks": true,
97 | "collectCoverage": true,
98 | "coverageReporters": [
99 | "json",
100 | "lcov",
101 | "clover",
102 | "cobertura",
103 | "text"
104 | ],
105 | "coverageDirectory": "coverage",
106 | "coveragePathIgnorePatterns": [
107 | "/node_modules/"
108 | ],
109 | "testPathIgnorePatterns": [
110 | "/node_modules/"
111 | ],
112 | "watchPathIgnorePatterns": [
113 | "/node_modules/"
114 | ],
115 | "reporters": [
116 | "default",
117 | [
118 | "jest-junit",
119 | {
120 | "outputDirectory": "test-reports"
121 | }
122 | ]
123 | ],
124 | "preset": "ts-jest",
125 | "globals": {
126 | "ts-jest": {
127 | "tsconfig": "tsconfig.dev.json"
128 | }
129 | }
130 | },
131 | "types": "lib/index.d.ts",
132 | "stability": "stable",
133 | "jsii": {
134 | "outdir": "dist",
135 | "targets": {
136 | "python": {
137 | "distName": "mbonig.state-machine",
138 | "module": "mbonig_state_machine"
139 | }
140 | },
141 | "tsc": {
142 | "outDir": "lib",
143 | "rootDir": "src"
144 | }
145 | },
146 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
147 | }
148 |
--------------------------------------------------------------------------------
/src/BuildStateType.ts:
--------------------------------------------------------------------------------
1 | export function buildStateType(stateDef: any, indent = 2) {
2 | let stateType = 'Partial<{\n';
3 | const indentTabs = ' '.repeat(indent);
4 | const closeIndents = ' '.repeat(indent - 1);
5 | if (stateDef === null) {
6 | // we're going to return an any here because while it's null now, maybe it'll be an any later.
7 | return 'any';
8 | }
9 | if (typeof stateDef === 'string') {
10 | return 'string';
11 | }
12 | if (Number.isInteger(stateDef)) {
13 | return 'number';
14 | }
15 | for (const prop of Object.keys(stateDef)) {
16 | const propValue = stateDef[prop];
17 | const safeProp = prop.replace(/'/g, '\\\'');
18 | if (typeof propValue === 'string') {
19 | stateType += `${indentTabs}'${safeProp}': string;\n`;
20 | } else if (Array.isArray(propValue)) {
21 | const arrayPropTypes = propValue.map(pv => buildStateType(pv, indent + 1));
22 | stateType += `${indentTabs}'${safeProp}': Partial<[${arrayPropTypes.join(', ')}]>;\n`;
23 | } else {
24 | stateType += `${indentTabs}'${safeProp}': ${buildStateType(propValue, indent + 1)};\n`;
25 | }
26 | }
27 | stateType += `${closeIndents}}>`;
28 | return stateType;
29 | }
30 |
--------------------------------------------------------------------------------
/src/StateMachine.ts:
--------------------------------------------------------------------------------
1 | import { Duration } from 'aws-cdk-lib';
2 | import * as iam from 'aws-cdk-lib/aws-iam';
3 | import * as aws_stepfunctions from 'aws-cdk-lib/aws-stepfunctions';
4 | import { DefinitionBody, LogOptions, StateMachineType } from 'aws-cdk-lib/aws-stepfunctions';
5 | import { Construct } from 'constructs';
6 | import * as yaml from 'js-yaml';
7 |
8 | // eslint-disable-next-line @typescript-eslint/no-require-imports
9 | const merge = require('lodash.merge');
10 |
11 | export interface StateMachineProps {
12 |
13 | /**
14 | * An object that matches the schema/shape of the ASL .States map with overridden values.
15 | *
16 | * @example {'My First State': { Parameters: { FunctionName: 'aLambdaFunctionArn' } } }
17 | */
18 | readonly overrides?: any;
19 |
20 | /**
21 | * An object that can be serialized into an ASL.
22 | */
23 | readonly definition: any;
24 |
25 | /**
26 | * A name for the state machine
27 | *
28 | * @default A name is automatically generated
29 | */
30 | readonly stateMachineName?: string;
31 |
32 | /**
33 | * The execution role for the state machine service
34 | *
35 | * @default A role is automatically created
36 | */
37 | readonly role?: iam.IRole;
38 |
39 | /**
40 | * Maximum run time for this state machine
41 | *
42 | * @default No timeout
43 | */
44 | readonly timeout?: Duration;
45 |
46 | /**
47 | * Type of the state machine
48 | *
49 | * @default StateMachineType.STANDARD
50 | */
51 | readonly stateMachineType?: StateMachineType;
52 |
53 | /**
54 | * Defines what execution history events are logged and where they are logged.
55 | *
56 | * @default No logging
57 | */
58 | readonly logs?: LogOptions;
59 |
60 | /**
61 | * Specifies whether Amazon X-Ray tracing is enabled for this state machine.
62 | *
63 | * @default false
64 | */
65 | readonly tracingEnabled?: boolean;
66 |
67 | /**
68 | * Should the ASL definition be written as YAML
69 | *
70 | * @default false
71 | */
72 | readonly aslYaml?: boolean;
73 |
74 | }
75 |
76 | export class StateMachine extends aws_stepfunctions.StateMachine {
77 |
78 | constructor(scope: Construct, id: string, props: StateMachineProps) {
79 | const mergedDefinition = merge(props.definition, { States: props.overrides });
80 | let definitionString: string;
81 | if (props.aslYaml) {
82 | definitionString = yaml.dump(mergedDefinition);
83 | } else {
84 | definitionString = JSON.stringify(mergedDefinition);
85 | }
86 | const propsMinusDefinition = { ...props, definition: undefined };
87 | delete propsMinusDefinition.definition;
88 | super(scope, id, {
89 | ...propsMinusDefinition,
90 | definitionBody: DefinitionBody.fromString(definitionString),
91 | });
92 | }
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/src/StepFunctionsAutoDiscover.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import * as path from 'path';
3 | import { basename, dirname, extname, join } from 'path';
4 | import { pascal } from 'case';
5 | import * as yaml from 'js-yaml';
6 | import { Component, Project, SourceCode } from 'projen';
7 | import { AwsCdkTypeScriptApp } from 'projen/lib/awscdk';
8 | import { AwsCdkDeps } from 'projen/lib/awscdk/awscdk-deps';
9 | import { AutoDiscoverBase } from 'projen/lib/cdk';
10 | import { buildStateType } from './BuildStateType';
11 |
12 | /**
13 | * The original extension used to search for ASL files.
14 | */
15 | export const JSON_STEPFUNCTION_EXT = '.workflow.json';
16 |
17 | /**
18 | * The AWS-recommended extension for ASL files.
19 | */
20 | export const AWS_RECOMMENDED_JSON_EXT = '.json.asl';
21 |
22 | /**
23 | * The AWS-recommended extension for YAML ASL files.
24 | */
25 | export const AWS_RECOMMENDED_YAML_EXT = '.yaml.asl';
26 |
27 | export interface StepFunctionsAutoDiscoverOptions {
28 | /**
29 | * An optional extension to use for discovering state machine files.
30 | *
31 | * @default '.workflow.json' (JSON_STEPFUNCTION_EXT)
32 | */
33 | readonly extension?: string;
34 | }
35 |
36 | /**
37 | * A projen component for discovering AWS Step Function state machine workflow ASL files
38 | * and generating a strongly typed interface and construct to use it.
39 | *
40 | * Simply add a new instance and hand it your AwsCdkTypeScriptApp projen class:
41 | * ```
42 | * const project = new AwsCdkTypeScriptApp({ ... });
43 | * new StepFunctionsAutoDiscover(project);
44 | * ```
45 | *
46 | * And any *.workflow.json file will cause the generation of a new strongly-typed StateMachine-derived class you can use.
47 | * Note that these constructs are NOT jsii-compatible. If you need that,
48 | * please open an [issue](https://github.com/mbonig/state-machine/issues/new)
49 | */
50 | export class StepFunctionsAutoDiscover extends AutoDiscoverBase {
51 | constructor(project: AwsCdkTypeScriptApp, _options?: StepFunctionsAutoDiscoverOptions) {
52 | if (_options?.extension) {
53 | if (!_options.extension.startsWith('.')) {
54 | throw new Error('extension must start with a .');
55 | }
56 | }
57 | let extension = _options?.extension || JSON_STEPFUNCTION_EXT;
58 | super(project, {
59 | extension: extension,
60 | projectdir: project.srcdir,
61 | });
62 | for (const entrypoint of this.entrypoints) {
63 | new StepFunctionsStateMachine(this.project, {
64 | workflowAsl: entrypoint,
65 | cdkDeps: project.cdkDeps,
66 | extension,
67 | });
68 | }
69 | }
70 | }
71 |
72 | export interface StepFunctionsStateMachineOptions {
73 | readonly extension: string;
74 | readonly constructFile?: string;
75 | readonly workflowAsl: string;
76 | readonly constructName?: string;
77 | readonly cdkDeps: AwsCdkDeps;
78 | }
79 |
80 | /**
81 | * Don't use this class directly.
82 | */
83 | export class StepFunctionsStateMachine extends Component {
84 | constructor(project: Project, options: StepFunctionsStateMachineOptions) {
85 | super(project);
86 |
87 | const extension = options.extension ?? JSON_STEPFUNCTION_EXT;
88 | const workflowAsl = options.workflowAsl;
89 |
90 | if (
91 | !workflowAsl.endsWith(extension)
92 | ) {
93 | throw new Error(
94 | `${workflowAsl} must have a ${extension} extension`,
95 | );
96 | }
97 | const basePath = join(
98 | dirname(workflowAsl),
99 | basename(
100 | workflowAsl,
101 | extension,
102 | ),
103 | );
104 | const constructFile = options.constructFile ?? `${basePath}-statemachine.ts`;
105 |
106 | if (extname(constructFile) !== '.ts') {
107 | throw new Error(
108 | `Construct file name "${constructFile}" must have a .ts extension`,
109 | );
110 | }
111 |
112 | // type names
113 | const constructName =
114 | options.constructName ?? pascal(basename(basePath)) + 'StateMachine';
115 |
116 | const src = new SourceCode(project, constructFile);
117 | if (src.marker) {
118 | src.line(`// ${src.marker}`);
119 | }
120 | src.line('import fs from \'fs\';');
121 | src.line('import path from \'path\';');
122 | src.line('import { StateMachine, StateMachineProps } from \'@matthewbonig/state-machine\';');
123 | src.line('import { Construct } from \'constructs\';');
124 |
125 | let isYaml = /(yaml|yml)/.test(extension);
126 | if (isYaml) {
127 | src.line('import * as yaml from \'js-yaml\';');
128 | }
129 |
130 | src.open(`export interface ${constructName}Overrides {`);
131 |
132 | let workflowDefinition: any;
133 | if (isYaml) {
134 | workflowDefinition = yaml.load(fs.readFileSync(join(project.outdir, workflowAsl)).toString());
135 | } else {
136 | workflowDefinition = JSON.parse(fs.readFileSync(join(project.outdir, workflowAsl)).toString());
137 |
138 | }
139 | if (!workflowDefinition.States) {
140 | throw new Error(`The workflow file ${workflowAsl} doesn't appear to be a valid ASL file, it doesn't contain a 'States' field`);
141 | }
142 | for (const [stateName, stateDef] of Object.entries(workflowDefinition.States)) {
143 | const stateType = buildStateType(stateDef);
144 | src.line(`readonly '${stateName}': ${stateType};`);
145 | }
146 | src.close('}');
147 |
148 | src.open(`export interface ${constructName}Props extends Omit {`);
149 | src.line(`readonly overrides: Partial<${constructName}Overrides>;`);
150 | src.close('}');
151 |
152 |
153 | src.open(`export class ${constructName} extends StateMachine {`);
154 | src.open(`constructor(scope: Construct, id: string, props: ${constructName}Props) {`);
155 | src.open('super(scope, id, {');
156 | src.line('...props,');
157 | const relativeFile = path.basename(workflowAsl);
158 | if (isYaml) {
159 | src.line(`definition: yaml.load(fs.readFileSync(path.join(__dirname, '${relativeFile}')).toString()),`);
160 | src.line('aslYaml: true,');
161 | } else {
162 | src.line(`definition: JSON.parse(fs.readFileSync(path.join(__dirname, '${relativeFile}')).toString()),`);
163 |
164 | }
165 | src.close('});');
166 | src.close('}');
167 | src.close('}');
168 |
169 | this.project.logger.verbose(
170 | `${basePath}: construct "${constructName}" generated under "${constructFile}"`,
171 | );
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './StateMachine';
2 | export { StepFunctionsAutoDiscover, StepFunctionsAutoDiscoverOptions } from './StepFunctionsAutoDiscover';
3 |
--------------------------------------------------------------------------------
/test/StateMachine.test.ts:
--------------------------------------------------------------------------------
1 | import { App, Stack } from 'aws-cdk-lib';
2 | import { Template } from 'aws-cdk-lib/assertions';
3 | import { StateMachineType } from 'aws-cdk-lib/aws-stepfunctions';
4 | import { StateMachine } from '../src';
5 |
6 | test('simple snapshot', () => {
7 | const stack = new Stack(new App(), 'TestingStack', {});
8 | new StateMachine(stack, 'Test', {
9 | stateMachineName: 'A-nice-state-machine',
10 | overrides: { one: { Parameters: { thingOne: 'test passed' } } },
11 | stateMachineType: StateMachineType.STANDARD,
12 | definition: { States: { one: { Parameters: { thingOne: 'test failed' } } } },
13 | });
14 | const assert = Template.fromStack(stack);
15 | expect(assert.toJSON()).toMatchSnapshot();
16 | });
17 |
18 | test('handles arrays', () => {
19 | const stack = new Stack(new App(), 'TestingStack', {});
20 | let firstBranch = {
21 | StartAt: 'ResumeCluster',
22 | States: {
23 | 'ResumeCluster': {
24 | Type: 'Task',
25 | Parameters: {
26 | ClusterIdentifier: 'MyData',
27 | },
28 | Resource: 'arn:aws:states:::aws-sdk:redshift:resumeCluster',
29 | Next: 'DescribeClusters',
30 | },
31 | 'DescribeClusters': {
32 | Type: 'Task',
33 | Parameters: {
34 | ClusterIdentifier: '',
35 | },
36 | Resource: 'arn:aws:states:::aws-sdk:redshift:describeClusters',
37 | Next: 'Evaluate Cluster Status',
38 | },
39 | 'Evaluate Cluster Status': {
40 | Type: 'Choice',
41 | Choices: [
42 | {
43 | Variable: '$.Clusters[0].ClusterStatus',
44 | StringEquals: 'available',
45 | Next: 'Redshift Pass',
46 | },
47 | ],
48 | Default: 'Redshift Wait',
49 | },
50 | 'Redshift Pass': {
51 | Type: 'Pass',
52 | End: true,
53 | },
54 | 'Redshift Wait': {
55 | Type: 'Wait',
56 | Seconds: 5,
57 | Next: 'DescribeClusters',
58 | },
59 | },
60 | };
61 | new StateMachine(stack, 'Test', {
62 | stateMachineName: 'A-nice-state-machine',
63 | overrides: {
64 | Branches: [{}, {
65 | StartAt: 'StartInstances',
66 | States: {
67 | StartInstances: {
68 | Parameters: {
69 | InstanceIds: ['INSTANCE_ID'],
70 | },
71 | },
72 | DescribeInstanceStatus: {
73 | Parameters: {
74 | InstanceIds: ['INSTANCE_ID'],
75 | },
76 | },
77 | },
78 | }],
79 | },
80 | stateMachineType: StateMachineType.STANDARD,
81 | definition: {
82 | States: {
83 | Branches: [
84 | firstBranch,
85 | {
86 | StartAt: 'StartInstances',
87 | States: {
88 | 'StartInstances': {
89 | Type: 'Task',
90 | Parameters: {
91 | InstanceIds: [
92 | 'MyData',
93 | ],
94 | },
95 | Resource: 'arn:aws:states:::aws-sdk:ec2:startInstances',
96 | Next: 'DescribeInstanceStatus',
97 | },
98 | 'DescribeInstanceStatus': {
99 | Type: 'Task',
100 | Next: 'Evaluate Instance Status',
101 | Parameters: {
102 | InstanceIds: [
103 | 'MyData',
104 | ],
105 | },
106 | Resource: 'arn:aws:states:::aws-sdk:ec2:describeInstanceStatus',
107 | },
108 | 'Evaluate Instance Status': {
109 | Type: 'Choice',
110 | Choices: [
111 | {
112 | And: [
113 | {
114 | Variable: '$.InstanceStatuses[0].InstanceState.Name',
115 | StringEquals: 'running',
116 | },
117 | {
118 | Variable: '$.InstanceStatuses[0].SystemStatus.Details[0].Status',
119 | StringEquals: 'passed',
120 | },
121 | {
122 | Variable: '$.InstanceStatuses[0].InstanceStatus.Details[0].Status',
123 | StringEquals: 'passed',
124 | },
125 | ],
126 | Next: 'EC2 Pass',
127 | },
128 | ],
129 | Default: 'EC2 Wait',
130 | },
131 | 'EC2 Pass': {
132 | Type: 'Pass',
133 | End: true,
134 | },
135 | 'EC2 Wait': {
136 | Type: 'Wait',
137 | Seconds: 5,
138 | Next: 'DescribeInstanceStatus',
139 | },
140 | },
141 | },
142 | ],
143 | },
144 | },
145 | });
146 | const assert = Template.fromStack(stack);
147 | assert.hasResourceProperties('AWS::StepFunctions::StateMachine', {
148 | DefinitionString: JSON.stringify({
149 | States: {
150 | Branches: [
151 | firstBranch,
152 | {
153 | StartAt: 'StartInstances',
154 | States: {
155 | 'StartInstances': {
156 | Type: 'Task',
157 | Parameters: {
158 | InstanceIds: ['INSTANCE_ID'],
159 | },
160 | Resource: 'arn:aws:states:::aws-sdk:ec2:startInstances',
161 | Next: 'DescribeInstanceStatus',
162 | },
163 | 'DescribeInstanceStatus': {
164 | Type: 'Task',
165 | Next: 'Evaluate Instance Status',
166 | Parameters: {
167 | InstanceIds: ['INSTANCE_ID'],
168 | },
169 | Resource: 'arn:aws:states:::aws-sdk:ec2:describeInstanceStatus',
170 | },
171 | 'Evaluate Instance Status': {
172 | Type: 'Choice',
173 | Choices: [
174 | {
175 | And: [
176 | {
177 | Variable: '$.InstanceStatuses[0].InstanceState.Name',
178 | StringEquals: 'running',
179 | },
180 | {
181 | Variable: '$.InstanceStatuses[0].SystemStatus.Details[0].Status',
182 | StringEquals: 'passed',
183 | },
184 | {
185 | Variable: '$.InstanceStatuses[0].InstanceStatus.Details[0].Status',
186 | StringEquals: 'passed',
187 | },
188 | ],
189 | Next: 'EC2 Pass',
190 | },
191 | ],
192 | Default: 'EC2 Wait',
193 | },
194 | 'EC2 Pass': {
195 | Type: 'Pass',
196 | End: true,
197 | },
198 | 'EC2 Wait': {
199 | Type: 'Wait',
200 | Seconds: 5,
201 | Next: 'DescribeInstanceStatus',
202 | },
203 | },
204 | },
205 | ],
206 | },
207 | }),
208 | });
209 | });
210 |
--------------------------------------------------------------------------------
/test/StateMachineAutoDiscover.test.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import { mkdtempSync } from 'fs';
3 | import * as os from 'os';
4 | import * as path from 'path';
5 | import { AwsCdkTypeScriptApp } from 'projen/lib/awscdk';
6 | import { synthSnapshot } from 'projen/lib/util/synth';
7 | import { StepFunctionsAutoDiscover } from '../src';
8 | import { AWS_RECOMMENDED_JSON_EXT, AWS_RECOMMENDED_YAML_EXT, JSON_STEPFUNCTION_EXT } from '../src/StepFunctionsAutoDiscover';
9 |
10 |
11 | function setupTestProject(testFile: string, extension: string = JSON_STEPFUNCTION_EXT, srcFile: string = 'test.workflow.json') {
12 | const tempDir = mkdtempSync(path.join(os.tmpdir(), 'test2'));
13 | const project = new AwsCdkTypeScriptApp({
14 | name: 'test',
15 | defaultReleaseBranch: 'main',
16 | cdkVersion: '2.53.0',
17 | outdir: tempDir,
18 | });
19 |
20 | // add a test file...
21 | fs.mkdirSync(path.join(project.outdir, project.srcdir));
22 | fs.copyFileSync(
23 | path.join(__dirname, 'step-functions', testFile),
24 | path.join(project.outdir, project.srcdir, srcFile),
25 | );
26 | new StepFunctionsAutoDiscover(project, { extension: extension });
27 | return project;
28 | }
29 |
30 |
31 | describe('Json', () => {
32 | test('simple case', () => {
33 | const project = setupTestProject('test.workflow.json');
34 | const snap = synthSnapshot(project);
35 | expect(snap['src/test-statemachine.ts']).toMatchSnapshot();
36 | });
37 |
38 | test('more complex case', async () => {
39 | const project = setupTestProject('test2.workflow.json');
40 | const snap = synthSnapshot(project);
41 | expect(snap['src/test-statemachine.ts']).toMatchSnapshot();
42 | });
43 | });
44 |
45 | describe('yaml', () => {
46 | test('handles yaml file', async () => {
47 | const project = setupTestProject('test.yaml.asl', AWS_RECOMMENDED_YAML_EXT, 'test.yaml.asl' );
48 | const snap = synthSnapshot(project);
49 | expect(snap['src/test-statemachine.ts']).toMatchSnapshot();
50 | });
51 |
52 | test('handles yml file', async () => {
53 | const project = setupTestProject('test.yaml.asl', '.yml.asl', 'test.yml.asl' );
54 | const snap = synthSnapshot(project);
55 | expect(snap['src/test-statemachine.ts']).toMatchSnapshot();
56 | });
57 |
58 | });
59 |
60 | describe('Extension parameter', () => {
61 | test('takes another extension', async () => {
62 | const project = setupTestProject('test.json.asl', AWS_RECOMMENDED_JSON_EXT, 'test.json.asl');
63 | const snap = synthSnapshot(project);
64 | expect(snap['src/test-statemachine.ts']).toMatchSnapshot();
65 | });
66 |
67 | test('fails when extension does not start with a .', () => {
68 | expect(() => setupTestProject('test.json.asl', 'asdfasdf', 'test.json.asl')).toThrow('extension must start with a .');
69 | });
70 | });
71 |
72 |
--------------------------------------------------------------------------------
/test/__snapshots__/StateMachine.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`simple snapshot 1`] = `
4 | Object {
5 | "Mappings": Object {
6 | "ServiceprincipalMap": Object {
7 | "af-south-1": Object {
8 | "states": "states.af-south-1.amazonaws.com",
9 | },
10 | "ap-east-1": Object {
11 | "states": "states.ap-east-1.amazonaws.com",
12 | },
13 | "ap-northeast-1": Object {
14 | "states": "states.ap-northeast-1.amazonaws.com",
15 | },
16 | "ap-northeast-2": Object {
17 | "states": "states.ap-northeast-2.amazonaws.com",
18 | },
19 | "ap-northeast-3": Object {
20 | "states": "states.ap-northeast-3.amazonaws.com",
21 | },
22 | "ap-south-1": Object {
23 | "states": "states.ap-south-1.amazonaws.com",
24 | },
25 | "ap-south-2": Object {
26 | "states": "states.ap-south-2.amazonaws.com",
27 | },
28 | "ap-southeast-1": Object {
29 | "states": "states.ap-southeast-1.amazonaws.com",
30 | },
31 | "ap-southeast-2": Object {
32 | "states": "states.ap-southeast-2.amazonaws.com",
33 | },
34 | "ap-southeast-3": Object {
35 | "states": "states.ap-southeast-3.amazonaws.com",
36 | },
37 | "ca-central-1": Object {
38 | "states": "states.ca-central-1.amazonaws.com",
39 | },
40 | "cn-north-1": Object {
41 | "states": "states.cn-north-1.amazonaws.com",
42 | },
43 | "cn-northwest-1": Object {
44 | "states": "states.cn-northwest-1.amazonaws.com",
45 | },
46 | "eu-central-1": Object {
47 | "states": "states.eu-central-1.amazonaws.com",
48 | },
49 | "eu-central-2": Object {
50 | "states": "states.eu-central-2.amazonaws.com",
51 | },
52 | "eu-north-1": Object {
53 | "states": "states.eu-north-1.amazonaws.com",
54 | },
55 | "eu-south-1": Object {
56 | "states": "states.eu-south-1.amazonaws.com",
57 | },
58 | "eu-south-2": Object {
59 | "states": "states.eu-south-2.amazonaws.com",
60 | },
61 | "eu-west-1": Object {
62 | "states": "states.eu-west-1.amazonaws.com",
63 | },
64 | "eu-west-2": Object {
65 | "states": "states.eu-west-2.amazonaws.com",
66 | },
67 | "eu-west-3": Object {
68 | "states": "states.eu-west-3.amazonaws.com",
69 | },
70 | "me-central-1": Object {
71 | "states": "states.me-central-1.amazonaws.com",
72 | },
73 | "me-south-1": Object {
74 | "states": "states.me-south-1.amazonaws.com",
75 | },
76 | "sa-east-1": Object {
77 | "states": "states.sa-east-1.amazonaws.com",
78 | },
79 | "us-east-1": Object {
80 | "states": "states.us-east-1.amazonaws.com",
81 | },
82 | "us-east-2": Object {
83 | "states": "states.us-east-2.amazonaws.com",
84 | },
85 | "us-gov-east-1": Object {
86 | "states": "states.us-gov-east-1.amazonaws.com",
87 | },
88 | "us-gov-west-1": Object {
89 | "states": "states.us-gov-west-1.amazonaws.com",
90 | },
91 | "us-iso-east-1": Object {
92 | "states": "states.amazonaws.com",
93 | },
94 | "us-iso-west-1": Object {
95 | "states": "states.amazonaws.com",
96 | },
97 | "us-isob-east-1": Object {
98 | "states": "states.amazonaws.com",
99 | },
100 | "us-west-1": Object {
101 | "states": "states.us-west-1.amazonaws.com",
102 | },
103 | "us-west-2": Object {
104 | "states": "states.us-west-2.amazonaws.com",
105 | },
106 | },
107 | },
108 | "Parameters": Object {
109 | "BootstrapVersion": Object {
110 | "Default": "/cdk-bootstrap/hnb659fds/version",
111 | "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
112 | "Type": "AWS::SSM::Parameter::Value",
113 | },
114 | },
115 | "Resources": Object {
116 | "Test7BFAF513": Object {
117 | "DeletionPolicy": "Delete",
118 | "DependsOn": Array [
119 | "TestRole17AB2208",
120 | ],
121 | "Properties": Object {
122 | "DefinitionString": "{\\"States\\":{\\"one\\":{\\"Parameters\\":{\\"thingOne\\":\\"test passed\\"}}}}",
123 | "RoleArn": Object {
124 | "Fn::GetAtt": Array [
125 | "TestRole17AB2208",
126 | "Arn",
127 | ],
128 | },
129 | "StateMachineName": "A-nice-state-machine",
130 | "StateMachineType": "STANDARD",
131 | },
132 | "Type": "AWS::StepFunctions::StateMachine",
133 | "UpdateReplacePolicy": "Delete",
134 | },
135 | "TestRole17AB2208": Object {
136 | "Properties": Object {
137 | "AssumeRolePolicyDocument": Object {
138 | "Statement": Array [
139 | Object {
140 | "Action": "sts:AssumeRole",
141 | "Effect": "Allow",
142 | "Principal": Object {
143 | "Service": Object {
144 | "Fn::FindInMap": Array [
145 | "ServiceprincipalMap",
146 | Object {
147 | "Ref": "AWS::Region",
148 | },
149 | "states",
150 | ],
151 | },
152 | },
153 | },
154 | ],
155 | "Version": "2012-10-17",
156 | },
157 | },
158 | "Type": "AWS::IAM::Role",
159 | },
160 | },
161 | "Rules": Object {
162 | "CheckBootstrapVersion": Object {
163 | "Assertions": Array [
164 | Object {
165 | "Assert": Object {
166 | "Fn::Not": Array [
167 | Object {
168 | "Fn::Contains": Array [
169 | Array [
170 | "1",
171 | "2",
172 | "3",
173 | "4",
174 | "5",
175 | ],
176 | Object {
177 | "Ref": "BootstrapVersion",
178 | },
179 | ],
180 | },
181 | ],
182 | },
183 | "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
184 | },
185 | ],
186 | },
187 | },
188 | }
189 | `;
190 |
--------------------------------------------------------------------------------
/test/__snapshots__/StateMachineAutoDiscover.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Extension parameter takes another extension 1`] = `
4 | "// ~~ Generated by projen. To modify, edit .projenrc.js and run \\"npx projen\\".
5 | import fs from 'fs';
6 | import path from 'path';
7 | import { StateMachine, StateMachineProps } from '@matthewbonig/state-machine';
8 | import { Construct } from 'constructs';
9 | export interface TestStateMachineOverrides {
10 | readonly 'Which database?': Partial<{
11 | 'Type': string;
12 | 'Choices': Partial<[Partial<{
13 | 'Variable': string;
14 | 'StringMatches': string;
15 | 'Next': string;
16 | }>, Partial<{
17 | 'Variable': string;
18 | 'StringMatches': string;
19 | 'Next': string;
20 | }>, Partial<{
21 | 'Variable': string;
22 | 'StringMatches': string;
23 | 'Next': string;
24 | }>]>;
25 | }>;
26 | readonly 'Get belle secret': Partial<{
27 | 'Type': string;
28 | 'Next': string;
29 | 'Parameters': Partial<{
30 | 'SecretId': string;
31 | }>;
32 | 'Resource': string;
33 | 'ResultPath': string;
34 | }>;
35 | readonly 'Parse belle secret value': Partial<{
36 | 'Type': string;
37 | 'Parameters': Partial<{
38 | 'ParsedValue.$': string;
39 | }>;
40 | 'ResultPath': string;
41 | 'Next': string;
42 | }>;
43 | readonly 'Create new database username and password': Partial<{
44 | 'Type': string;
45 | 'Resource': string;
46 | 'Parameters': Partial<{
47 | 'Payload.$': string;
48 | 'FunctionName': string;
49 | }>;
50 | 'Retry': Partial<[Partial<{
51 | 'ErrorEquals': Partial<[string, string, string]>;
52 | 'IntervalSeconds': number;
53 | 'MaxAttempts': number;
54 | 'BackoffRate': number;
55 | }>]>;
56 | 'ResultPath': string;
57 | 'Comment': string;
58 | 'Next': string;
59 | 'ResultSelector': Partial<{
60 | 'username.$': string;
61 | 'password.$': string;
62 | 'otsUrl.$': string;
63 | }>;
64 | }>;
65 | readonly 'Create user on the database': Partial<{
66 | 'Type': string;
67 | 'Resource': string;
68 | 'Parameters': Partial<{
69 | 'FunctionName': string;
70 | 'Payload': Partial<{
71 | 'script.$': string;
72 | 'databaseName.$': string;
73 | }>;
74 | }>;
75 | 'Retry': Partial<[Partial<{
76 | 'ErrorEquals': Partial<[string, string, string]>;
77 | 'IntervalSeconds': number;
78 | 'MaxAttempts': number;
79 | 'BackoffRate': number;
80 | }>]>;
81 | 'ResultPath': string;
82 | 'Next': string;
83 | }>;
84 | readonly 'Send credentials to user': Partial<{
85 | 'Type': string;
86 | 'Parameters': Partial<{
87 | 'Destination': Partial<{
88 | 'ToAddresses.$': string;
89 | }>;
90 | 'Message': Partial<{
91 | 'Body': Partial<{
92 | 'Text': Partial<{
93 | 'Data.$': string;
94 | }>;
95 | }>;
96 | 'Subject': Partial<{
97 | 'Data': string;
98 | }>;
99 | }>;
100 | 'Source': string;
101 | }>;
102 | 'Resource': string;
103 | 'End': Partial<{
104 | }>;
105 | }>;
106 | readonly 'Get engines secret': Partial<{
107 | 'Type': string;
108 | 'Parameters': Partial<{
109 | 'SecretId': string;
110 | }>;
111 | 'Resource': string;
112 | 'ResultPath': string;
113 | 'Next': string;
114 | }>;
115 | readonly 'Parse engines secret value': Partial<{
116 | 'Type': string;
117 | 'Parameters': Partial<{
118 | 'ParsedValue.$': string;
119 | }>;
120 | 'ResultPath': string;
121 | 'Next': string;
122 | }>;
123 | readonly 'Create new database username and password for engines': Partial<{
124 | 'Type': string;
125 | 'Resource': string;
126 | 'Parameters': Partial<{
127 | 'Payload.$': string;
128 | 'FunctionName': string;
129 | }>;
130 | 'Retry': Partial<[Partial<{
131 | 'ErrorEquals': Partial<[string, string, string]>;
132 | 'IntervalSeconds': number;
133 | 'MaxAttempts': number;
134 | 'BackoffRate': number;
135 | }>]>;
136 | 'ResultPath': string;
137 | 'Comment': string;
138 | 'ResultSelector': Partial<{
139 | 'username.$': string;
140 | 'password.$': string;
141 | 'otsUrl.$': string;
142 | }>;
143 | 'Next': string;
144 | }>;
145 | readonly 'Create user on jasmine': Partial<{
146 | 'Type': string;
147 | 'Resource': string;
148 | 'Parameters': Partial<{
149 | 'FunctionName': string;
150 | 'Payload': Partial<{
151 | 'script.$': string;
152 | 'databaseName.$': string;
153 | }>;
154 | }>;
155 | 'Retry': Partial<[Partial<{
156 | 'ErrorEquals': Partial<[string, string, string]>;
157 | 'IntervalSeconds': number;
158 | 'MaxAttempts': number;
159 | 'BackoffRate': number;
160 | }>]>;
161 | 'ResultPath': string;
162 | 'Next': string;
163 | }>;
164 | readonly 'Send credentials to jasmine user': Partial<{
165 | 'Type': string;
166 | 'Parameters': Partial<{
167 | 'Destination': Partial<{
168 | 'ToAddresses.$': string;
169 | }>;
170 | 'Message': Partial<{
171 | 'Body': Partial<{
172 | 'Text': Partial<{
173 | 'Data.$': string;
174 | }>;
175 | }>;
176 | 'Subject': Partial<{
177 | 'Data': string;
178 | }>;
179 | }>;
180 | 'Source': string;
181 | }>;
182 | 'Resource': string;
183 | 'End': Partial<{
184 | }>;
185 | }>;
186 | readonly 'Get anna secret': Partial<{
187 | 'Type': string;
188 | 'Next': string;
189 | 'Parameters': Partial<{
190 | 'SecretId': string;
191 | }>;
192 | 'Resource': string;
193 | 'ResultPath': string;
194 | }>;
195 | readonly 'Parse anna secret value': Partial<{
196 | 'Type': string;
197 | 'Parameters': Partial<{
198 | 'ParsedValue.$': string;
199 | }>;
200 | 'ResultPath': string;
201 | 'Next': string;
202 | }>;
203 | readonly 'Create new database username and password for anna': Partial<{
204 | 'Type': string;
205 | 'Resource': string;
206 | 'Parameters': Partial<{
207 | 'Payload.$': string;
208 | 'FunctionName': string;
209 | }>;
210 | 'Retry': Partial<[Partial<{
211 | 'ErrorEquals': Partial<[string, string, string]>;
212 | 'IntervalSeconds': number;
213 | 'MaxAttempts': number;
214 | 'BackoffRate': number;
215 | }>]>;
216 | 'ResultPath': string;
217 | 'Comment': string;
218 | 'Next': string;
219 | 'ResultSelector': Partial<{
220 | 'username.$': string;
221 | 'password.$': string;
222 | 'otsUrl.$': string;
223 | }>;
224 | }>;
225 | readonly 'Create user on the anna database': Partial<{
226 | 'Type': string;
227 | 'Resource': string;
228 | 'Parameters': Partial<{
229 | 'FunctionName': string;
230 | 'Payload': Partial<{
231 | 'script.$': string;
232 | 'databaseName.$': string;
233 | }>;
234 | }>;
235 | 'Retry': Partial<[Partial<{
236 | 'ErrorEquals': Partial<[string, string, string]>;
237 | 'IntervalSeconds': number;
238 | 'MaxAttempts': number;
239 | 'BackoffRate': number;
240 | }>]>;
241 | 'ResultPath': string;
242 | 'Next': string;
243 | }>;
244 | readonly 'Send credentials to user for anna': Partial<{
245 | 'Type': string;
246 | 'Parameters': Partial<{
247 | 'Destination': Partial<{
248 | 'ToAddresses.$': string;
249 | }>;
250 | 'Message': Partial<{
251 | 'Body': Partial<{
252 | 'Text': Partial<{
253 | 'Data.$': string;
254 | }>;
255 | }>;
256 | 'Subject': Partial<{
257 | 'Data': string;
258 | }>;
259 | }>;
260 | 'Source': string;
261 | }>;
262 | 'Resource': string;
263 | 'End': Partial<{
264 | }>;
265 | }>;
266 | }
267 | export interface TestStateMachineProps extends Omit {
268 | readonly overrides: Partial;
269 | }
270 | export class TestStateMachine extends StateMachine {
271 | constructor(scope: Construct, id: string, props: TestStateMachineProps) {
272 | super(scope, id, {
273 | ...props,
274 | definition: JSON.parse(fs.readFileSync(path.join(__dirname, 'test.json.asl')).toString()),
275 | });
276 | }
277 | }"
278 | `;
279 |
280 | exports[`Json more complex case 1`] = `
281 | "// ~~ Generated by projen. To modify, edit .projenrc.js and run \\"npx projen\\".
282 | import fs from 'fs';
283 | import path from 'path';
284 | import { StateMachine, StateMachineProps } from '@matthewbonig/state-machine';
285 | import { Construct } from 'constructs';
286 | export interface TestStateMachineOverrides {
287 | readonly 'Get Pod To Execute On': Partial<{
288 | 'Type': string;
289 | 'Resource': string;
290 | 'Parameters': Partial<{
291 | 'FunctionName': string;
292 | 'Payload': Partial<{
293 | 'commands': Partial<[string, string, string, string]>;
294 | }>;
295 | }>;
296 | 'Retry': Partial<[Partial<{
297 | 'ErrorEquals': Partial<[string, string, string]>;
298 | 'IntervalSeconds': number;
299 | 'MaxAttempts': number;
300 | 'BackoffRate': number;
301 | }>]>;
302 | 'ResultSelector': Partial<{
303 | 'belle.$': string;
304 | }>;
305 | 'ResultPath': string;
306 | 'Next': string;
307 | 'Catch': Partial<[Partial<{
308 | 'ErrorEquals': Partial<[string]>;
309 | 'Next': string;
310 | 'ResultPath': string;
311 | }>]>;
312 | }>;
313 | readonly 'Generate Commands': Partial<{
314 | 'Type': string;
315 | 'Resource': string;
316 | 'Parameters': Partial<{
317 | 'Payload.$': string;
318 | 'FunctionName': string;
319 | }>;
320 | 'Retry': Partial<[Partial<{
321 | 'ErrorEquals': Partial<[string, string, string]>;
322 | 'IntervalSeconds': number;
323 | 'MaxAttempts': number;
324 | 'BackoffRate': number;
325 | }>]>;
326 | 'ResultSelector': Partial<{
327 | 'commands.$': string;
328 | }>;
329 | 'ResultPath': string;
330 | 'Next': string;
331 | 'Catch': Partial<[Partial<{
332 | 'ErrorEquals': Partial<[string]>;
333 | 'Next': string;
334 | 'ResultPath': string;
335 | }>]>;
336 | }>;
337 | readonly 'Run Command': Partial<{
338 | 'Type': string;
339 | 'Resource': string;
340 | 'Parameters': Partial<{
341 | 'Payload': Partial<{
342 | 'commands.$': string;
343 | }>;
344 | 'FunctionName': string;
345 | }>;
346 | 'Retry': Partial<[Partial<{
347 | 'ErrorEquals': Partial<[string, string, string]>;
348 | 'IntervalSeconds': number;
349 | 'MaxAttempts': number;
350 | 'BackoffRate': number;
351 | }>]>;
352 | 'ResultPath': string;
353 | 'Next': string;
354 | 'Catch': Partial<[Partial<{
355 | 'ErrorEquals': Partial<[string]>;
356 | 'Next': string;
357 | 'ResultPath': string;
358 | }>]>;
359 | }>;
360 | readonly 'Notify Slack': Partial<{
361 | 'Type': string;
362 | 'Resource': string;
363 | 'Parameters': Partial<{
364 | 'Payload.$': string;
365 | 'FunctionName': string;
366 | }>;
367 | 'Retry': Partial<[Partial<{
368 | 'ErrorEquals': Partial<[string, string, string]>;
369 | 'IntervalSeconds': number;
370 | 'MaxAttempts': number;
371 | 'BackoffRate': number;
372 | }>]>;
373 | 'ResultPath': any;
374 | 'End': Partial<{
375 | }>;
376 | 'Catch': Partial<[Partial<{
377 | 'ErrorEquals': Partial<[string]>;
378 | 'Next': string;
379 | 'ResultPath': string;
380 | }>]>;
381 | }>;
382 | readonly 'Notify Slack of Error': Partial<{
383 | 'Type': string;
384 | 'Resource': string;
385 | 'Parameters': Partial<{
386 | 'Payload.$': string;
387 | 'FunctionName': string;
388 | }>;
389 | 'Retry': Partial<[Partial<{
390 | 'ErrorEquals': Partial<[string, string, string]>;
391 | 'IntervalSeconds': number;
392 | 'MaxAttempts': number;
393 | 'BackoffRate': number;
394 | }>]>;
395 | 'End': Partial<{
396 | }>;
397 | 'ResultPath': any;
398 | }>;
399 | }
400 | export interface TestStateMachineProps extends Omit {
401 | readonly overrides: Partial;
402 | }
403 | export class TestStateMachine extends StateMachine {
404 | constructor(scope: Construct, id: string, props: TestStateMachineProps) {
405 | super(scope, id, {
406 | ...props,
407 | definition: JSON.parse(fs.readFileSync(path.join(__dirname, 'test.workflow.json')).toString()),
408 | });
409 | }
410 | }"
411 | `;
412 |
413 | exports[`Json simple case 1`] = `
414 | "// ~~ Generated by projen. To modify, edit .projenrc.js and run \\"npx projen\\".
415 | import fs from 'fs';
416 | import path from 'path';
417 | import { StateMachine, StateMachineProps } from '@matthewbonig/state-machine';
418 | import { Construct } from 'constructs';
419 | export interface TestStateMachineOverrides {
420 | readonly 'Which database?': Partial<{
421 | 'Type': string;
422 | 'Choices': Partial<[Partial<{
423 | 'Variable': string;
424 | 'StringMatches': string;
425 | 'Next': string;
426 | }>, Partial<{
427 | 'Variable': string;
428 | 'StringMatches': string;
429 | 'Next': string;
430 | }>, Partial<{
431 | 'Variable': string;
432 | 'StringMatches': string;
433 | 'Next': string;
434 | }>]>;
435 | }>;
436 | readonly 'Get belle secret': Partial<{
437 | 'Type': string;
438 | 'Next': string;
439 | 'Parameters': Partial<{
440 | 'SecretId': string;
441 | }>;
442 | 'Resource': string;
443 | 'ResultPath': string;
444 | }>;
445 | readonly 'Parse belle secret value': Partial<{
446 | 'Type': string;
447 | 'Parameters': Partial<{
448 | 'ParsedValue.$': string;
449 | }>;
450 | 'ResultPath': string;
451 | 'Next': string;
452 | }>;
453 | readonly 'Create new database username and password': Partial<{
454 | 'Type': string;
455 | 'Resource': string;
456 | 'Parameters': Partial<{
457 | 'Payload.$': string;
458 | 'FunctionName': string;
459 | }>;
460 | 'Retry': Partial<[Partial<{
461 | 'ErrorEquals': Partial<[string, string, string]>;
462 | 'IntervalSeconds': number;
463 | 'MaxAttempts': number;
464 | 'BackoffRate': number;
465 | }>]>;
466 | 'ResultPath': string;
467 | 'Comment': string;
468 | 'Next': string;
469 | 'ResultSelector': Partial<{
470 | 'username.$': string;
471 | 'password.$': string;
472 | 'otsUrl.$': string;
473 | }>;
474 | }>;
475 | readonly 'Create user on the database': Partial<{
476 | 'Type': string;
477 | 'Resource': string;
478 | 'Parameters': Partial<{
479 | 'FunctionName': string;
480 | 'Payload': Partial<{
481 | 'script.$': string;
482 | 'databaseName.$': string;
483 | }>;
484 | }>;
485 | 'Retry': Partial<[Partial<{
486 | 'ErrorEquals': Partial<[string, string, string]>;
487 | 'IntervalSeconds': number;
488 | 'MaxAttempts': number;
489 | 'BackoffRate': number;
490 | }>]>;
491 | 'ResultPath': string;
492 | 'Next': string;
493 | }>;
494 | readonly 'Send credentials to user': Partial<{
495 | 'Type': string;
496 | 'Parameters': Partial<{
497 | 'Destination': Partial<{
498 | 'ToAddresses.$': string;
499 | }>;
500 | 'Message': Partial<{
501 | 'Body': Partial<{
502 | 'Text': Partial<{
503 | 'Data.$': string;
504 | }>;
505 | }>;
506 | 'Subject': Partial<{
507 | 'Data': string;
508 | }>;
509 | }>;
510 | 'Source': string;
511 | }>;
512 | 'Resource': string;
513 | 'End': Partial<{
514 | }>;
515 | }>;
516 | readonly 'Get engines secret': Partial<{
517 | 'Type': string;
518 | 'Parameters': Partial<{
519 | 'SecretId': string;
520 | }>;
521 | 'Resource': string;
522 | 'ResultPath': string;
523 | 'Next': string;
524 | }>;
525 | readonly 'Parse engines secret value': Partial<{
526 | 'Type': string;
527 | 'Parameters': Partial<{
528 | 'ParsedValue.$': string;
529 | }>;
530 | 'ResultPath': string;
531 | 'Next': string;
532 | }>;
533 | readonly 'Create new database username and password for engines': Partial<{
534 | 'Type': string;
535 | 'Resource': string;
536 | 'Parameters': Partial<{
537 | 'Payload.$': string;
538 | 'FunctionName': string;
539 | }>;
540 | 'Retry': Partial<[Partial<{
541 | 'ErrorEquals': Partial<[string, string, string]>;
542 | 'IntervalSeconds': number;
543 | 'MaxAttempts': number;
544 | 'BackoffRate': number;
545 | }>]>;
546 | 'ResultPath': string;
547 | 'Comment': string;
548 | 'ResultSelector': Partial<{
549 | 'username.$': string;
550 | 'password.$': string;
551 | 'otsUrl.$': string;
552 | }>;
553 | 'Next': string;
554 | }>;
555 | readonly 'Create user on jasmine': Partial<{
556 | 'Type': string;
557 | 'Resource': string;
558 | 'Parameters': Partial<{
559 | 'FunctionName': string;
560 | 'Payload': Partial<{
561 | 'script.$': string;
562 | 'databaseName.$': string;
563 | }>;
564 | }>;
565 | 'Retry': Partial<[Partial<{
566 | 'ErrorEquals': Partial<[string, string, string]>;
567 | 'IntervalSeconds': number;
568 | 'MaxAttempts': number;
569 | 'BackoffRate': number;
570 | }>]>;
571 | 'ResultPath': string;
572 | 'Next': string;
573 | }>;
574 | readonly 'Send credentials to jasmine user': Partial<{
575 | 'Type': string;
576 | 'Parameters': Partial<{
577 | 'Destination': Partial<{
578 | 'ToAddresses.$': string;
579 | }>;
580 | 'Message': Partial<{
581 | 'Body': Partial<{
582 | 'Text': Partial<{
583 | 'Data.$': string;
584 | }>;
585 | }>;
586 | 'Subject': Partial<{
587 | 'Data': string;
588 | }>;
589 | }>;
590 | 'Source': string;
591 | }>;
592 | 'Resource': string;
593 | 'End': Partial<{
594 | }>;
595 | }>;
596 | readonly 'Get anna secret': Partial<{
597 | 'Type': string;
598 | 'Next': string;
599 | 'Parameters': Partial<{
600 | 'SecretId': string;
601 | }>;
602 | 'Resource': string;
603 | 'ResultPath': string;
604 | }>;
605 | readonly 'Parse anna secret value': Partial<{
606 | 'Type': string;
607 | 'Parameters': Partial<{
608 | 'ParsedValue.$': string;
609 | }>;
610 | 'ResultPath': string;
611 | 'Next': string;
612 | }>;
613 | readonly 'Create new database username and password for anna': Partial<{
614 | 'Type': string;
615 | 'Resource': string;
616 | 'Parameters': Partial<{
617 | 'Payload.$': string;
618 | 'FunctionName': string;
619 | }>;
620 | 'Retry': Partial<[Partial<{
621 | 'ErrorEquals': Partial<[string, string, string]>;
622 | 'IntervalSeconds': number;
623 | 'MaxAttempts': number;
624 | 'BackoffRate': number;
625 | }>]>;
626 | 'ResultPath': string;
627 | 'Comment': string;
628 | 'Next': string;
629 | 'ResultSelector': Partial<{
630 | 'username.$': string;
631 | 'password.$': string;
632 | 'otsUrl.$': string;
633 | }>;
634 | }>;
635 | readonly 'Create user on the anna database': Partial<{
636 | 'Type': string;
637 | 'Resource': string;
638 | 'Parameters': Partial<{
639 | 'FunctionName': string;
640 | 'Payload': Partial<{
641 | 'script.$': string;
642 | 'databaseName.$': string;
643 | }>;
644 | }>;
645 | 'Retry': Partial<[Partial<{
646 | 'ErrorEquals': Partial<[string, string, string]>;
647 | 'IntervalSeconds': number;
648 | 'MaxAttempts': number;
649 | 'BackoffRate': number;
650 | }>]>;
651 | 'ResultPath': string;
652 | 'Next': string;
653 | }>;
654 | readonly 'Send credentials to user for anna': Partial<{
655 | 'Type': string;
656 | 'Parameters': Partial<{
657 | 'Destination': Partial<{
658 | 'ToAddresses.$': string;
659 | }>;
660 | 'Message': Partial<{
661 | 'Body': Partial<{
662 | 'Text': Partial<{
663 | 'Data.$': string;
664 | }>;
665 | }>;
666 | 'Subject': Partial<{
667 | 'Data': string;
668 | }>;
669 | }>;
670 | 'Source': string;
671 | }>;
672 | 'Resource': string;
673 | 'End': Partial<{
674 | }>;
675 | }>;
676 | }
677 | export interface TestStateMachineProps extends Omit {
678 | readonly overrides: Partial;
679 | }
680 | export class TestStateMachine extends StateMachine {
681 | constructor(scope: Construct, id: string, props: TestStateMachineProps) {
682 | super(scope, id, {
683 | ...props,
684 | definition: JSON.parse(fs.readFileSync(path.join(__dirname, 'test.workflow.json')).toString()),
685 | });
686 | }
687 | }"
688 | `;
689 |
690 | exports[`yaml handles yaml file 1`] = `
691 | "// ~~ Generated by projen. To modify, edit .projenrc.js and run \\"npx projen\\".
692 | import fs from 'fs';
693 | import path from 'path';
694 | import { StateMachine, StateMachineProps } from '@matthewbonig/state-machine';
695 | import { Construct } from 'constructs';
696 | import * as yaml from 'js-yaml';
697 | export interface TestStateMachineOverrides {
698 | readonly 'Check Stock Price': Partial<{
699 | 'Type': string;
700 | 'Resource': string;
701 | 'Next': string;
702 | }>;
703 | readonly 'Generate Buy/Sell recommendation': Partial<{
704 | 'Type': string;
705 | 'Resource': string;
706 | 'ResultPath': string;
707 | 'Next': string;
708 | }>;
709 | readonly 'Request Human Approval': Partial<{
710 | 'Type': string;
711 | 'Resource': string;
712 | 'Parameters': Partial<{
713 | 'QueueUrl': string;
714 | 'MessageBody': Partial<{
715 | 'Input.$': string;
716 | 'TaskToken.$': string;
717 | }>;
718 | }>;
719 | 'ResultPath': any;
720 | 'Next': string;
721 | }>;
722 | readonly 'Buy or Sell?': Partial<{
723 | 'Type': string;
724 | 'Choices': Partial<[Partial<{
725 | 'Variable': string;
726 | 'StringEquals': string;
727 | 'Next': string;
728 | }>, Partial<{
729 | 'Variable': string;
730 | 'StringEquals': string;
731 | 'Next': string;
732 | }>]>;
733 | }>;
734 | readonly 'Buy Stock': Partial<{
735 | 'Type': string;
736 | 'Resource': string;
737 | 'Next': string;
738 | }>;
739 | readonly 'Sell Stock': Partial<{
740 | 'Type': string;
741 | 'Resource': string;
742 | 'Next': string;
743 | }>;
744 | readonly 'Report Result': Partial<{
745 | 'Type': string;
746 | 'Resource': string;
747 | 'Parameters': Partial<{
748 | 'TopicArn': string;
749 | 'Message': Partial<{
750 | 'Input.$': string;
751 | }>;
752 | }>;
753 | 'End': Partial<{
754 | }>;
755 | }>;
756 | }
757 | export interface TestStateMachineProps extends Omit {
758 | readonly overrides: Partial;
759 | }
760 | export class TestStateMachine extends StateMachine {
761 | constructor(scope: Construct, id: string, props: TestStateMachineProps) {
762 | super(scope, id, {
763 | ...props,
764 | definition: yaml.load(fs.readFileSync(path.join(__dirname, 'test.yaml.asl')).toString()),
765 | aslYaml: true,
766 | });
767 | }
768 | }"
769 | `;
770 |
771 | exports[`yaml handles yml file 1`] = `
772 | "// ~~ Generated by projen. To modify, edit .projenrc.js and run \\"npx projen\\".
773 | import fs from 'fs';
774 | import path from 'path';
775 | import { StateMachine, StateMachineProps } from '@matthewbonig/state-machine';
776 | import { Construct } from 'constructs';
777 | import * as yaml from 'js-yaml';
778 | export interface TestStateMachineOverrides {
779 | readonly 'Check Stock Price': Partial<{
780 | 'Type': string;
781 | 'Resource': string;
782 | 'Next': string;
783 | }>;
784 | readonly 'Generate Buy/Sell recommendation': Partial<{
785 | 'Type': string;
786 | 'Resource': string;
787 | 'ResultPath': string;
788 | 'Next': string;
789 | }>;
790 | readonly 'Request Human Approval': Partial<{
791 | 'Type': string;
792 | 'Resource': string;
793 | 'Parameters': Partial<{
794 | 'QueueUrl': string;
795 | 'MessageBody': Partial<{
796 | 'Input.$': string;
797 | 'TaskToken.$': string;
798 | }>;
799 | }>;
800 | 'ResultPath': any;
801 | 'Next': string;
802 | }>;
803 | readonly 'Buy or Sell?': Partial<{
804 | 'Type': string;
805 | 'Choices': Partial<[Partial<{
806 | 'Variable': string;
807 | 'StringEquals': string;
808 | 'Next': string;
809 | }>, Partial<{
810 | 'Variable': string;
811 | 'StringEquals': string;
812 | 'Next': string;
813 | }>]>;
814 | }>;
815 | readonly 'Buy Stock': Partial<{
816 | 'Type': string;
817 | 'Resource': string;
818 | 'Next': string;
819 | }>;
820 | readonly 'Sell Stock': Partial<{
821 | 'Type': string;
822 | 'Resource': string;
823 | 'Next': string;
824 | }>;
825 | readonly 'Report Result': Partial<{
826 | 'Type': string;
827 | 'Resource': string;
828 | 'Parameters': Partial<{
829 | 'TopicArn': string;
830 | 'Message': Partial<{
831 | 'Input.$': string;
832 | }>;
833 | }>;
834 | 'End': Partial<{
835 | }>;
836 | }>;
837 | }
838 | export interface TestStateMachineProps extends Omit {
839 | readonly overrides: Partial;
840 | }
841 | export class TestStateMachine extends StateMachine {
842 | constructor(scope: Construct, id: string, props: TestStateMachineProps) {
843 | super(scope, id, {
844 | ...props,
845 | definition: yaml.load(fs.readFileSync(path.join(__dirname, 'test.yml.asl')).toString()),
846 | aslYaml: true,
847 | });
848 | }
849 | }"
850 | `;
851 |
--------------------------------------------------------------------------------
/test/sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "Comment": "A description of my state machine",
3 | "StartAt": "Read database credentials secret",
4 | "States": {
5 | "Read database credentials secret": {
6 | "Type": "Task",
7 | "Parameters": {
8 | "SecretId": "DbSecret685A0FA5-GXCINaDfwzla"
9 | },
10 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
11 | "Next": "Parse SecretString",
12 | "ResultPath": "$.dbSecret"
13 | },
14 | "Parse SecretString": {
15 | "Type": "Pass",
16 | "Next": "Generate username and password",
17 | "InputPath": "$.dbSecret",
18 | "Parameters": {
19 | "Value.$": "States.StringToJson($.SecretString)"
20 | },
21 | "ResultPath": "$.dbSecret"
22 | },
23 | "Generate username and password": {
24 | "Type": "Task",
25 | "Resource": "arn:aws:states:::lambda:invoke",
26 | "Parameters": {
27 | "Payload.$": "$",
28 | "FunctionName": "arn:aws:lambda:us-east-1:536309290949:function:step-functions-with-the-c-GenerateUsernameAndPassw-OZ3vhotMEJPK"
29 | },
30 | "Retry": [
31 | {
32 | "ErrorEquals": [
33 | "Lambda.ServiceException",
34 | "Lambda.AWSLambdaException",
35 | "Lambda.SdkClientException"
36 | ],
37 | "IntervalSeconds": 2,
38 | "MaxAttempts": 6,
39 | "BackoffRate": 2
40 | }
41 | ],
42 | "Next": "Invoke SQL script against database",
43 | "ResultPath": "$.usernameAndPassword",
44 | "ResultSelector": {
45 | "Username.$": "$.Payload.username",
46 | "Password.$": "$.Payload.password"
47 | }
48 | },
49 | "Invoke SQL script against database": {
50 | "Type": "Task",
51 | "Resource": "arn:aws:states:::lambda:invoke",
52 | "Parameters": {
53 | "Payload.$": "$",
54 | "FunctionName": "arn:aws:lambda:us-east-1:536309290949:function:step-functions-with-the-cdk-ScriptProvider32E26F41-DBeWWSBNMARo"
55 | },
56 | "Retry": [
57 | {
58 | "ErrorEquals": [
59 | "Lambda.ServiceException",
60 | "Lambda.AWSLambdaException",
61 | "Lambda.SdkClientException"
62 | ],
63 | "IntervalSeconds": 2,
64 | "MaxAttempts": 6,
65 | "BackoffRate": 2
66 | }
67 | ],
68 | "Next": "Generate OTS",
69 | "ResultPath": "$.invokeOutput"
70 | },
71 | "Generate OTS": {
72 | "Type": "Task",
73 | "Resource": "arn:aws:states:::lambda:invoke",
74 | "Parameters": {
75 | "Payload.$": "$",
76 | "FunctionName": "arn:aws:lambda:us-east-1:536309290949:function:step-functions-with-the-cdk-GenerateOtsBE7C09B0-nTIEu0OxGURq"
77 | },
78 | "Retry": [
79 | {
80 | "ErrorEquals": [
81 | "Lambda.ServiceException",
82 | "Lambda.AWSLambdaException",
83 | "Lambda.SdkClientException"
84 | ],
85 | "IntervalSeconds": 2,
86 | "MaxAttempts": 6,
87 | "BackoffRate": 2
88 | }
89 | ],
90 | "Next": "Send email",
91 | "ResultPath": "$.ots",
92 | "ResultSelector": {
93 | "OtsUrl.$": "$.Payload.otsUrl"
94 | }
95 | },
96 | "Send email": {
97 | "Type": "Task",
98 | "End": true,
99 | "Parameters": {
100 | "FromEmailAddress": "matthew.bonig@gmail.com",
101 | "Content": {
102 | "Simple": {
103 | "Body": {
104 | "Html": {
105 | "Data": "You're getting new creds!"
106 | },
107 | "Text": {
108 | "Data": "You're getting new creds!"
109 | }
110 | },
111 | "Subject": {
112 | "Data": "You're getting new creds!"
113 | }
114 | }
115 | },
116 | "Destination": {
117 | "ToAddresses.$": "States.Array($.email)"
118 | }
119 | },
120 | "Resource": "arn:aws:states:::aws-sdk:sesv2:sendEmail"
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/test/step-functions/test.json.asl:
--------------------------------------------------------------------------------
1 | {
2 | "StartAt": "Which database?",
3 | "States": {
4 | "Which database?": {
5 | "Type": "Choice",
6 | "Choices": [
7 | {
8 | "Variable": "$.databaseName",
9 | "StringMatches": "belle*",
10 | "Next": "Get belle secret"
11 | },
12 | {
13 | "Variable": "$.databaseName",
14 | "StringMatches": "jasmine*",
15 | "Next": "Get engines secret"
16 | },
17 | {
18 | "Variable": "$.databaseName",
19 | "StringMatches": "anna*",
20 | "Next": "Get anna secret"
21 | }
22 | ]
23 | },
24 | "Get belle secret": {
25 | "Type": "Task",
26 | "Next": "Parse belle secret value",
27 | "Parameters": {
28 | "SecretId": "qa2/belle-sql-secrets"
29 | },
30 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
31 | "ResultPath": "$.databaseSecret"
32 | },
33 | "Parse belle secret value": {
34 | "Type": "Pass",
35 | "Parameters": {
36 | "ParsedValue.$": "States.StringToJson($.databaseSecret.SecretString)"
37 | },
38 | "ResultPath": "$.databaseSecret",
39 | "Next": "Create new database username and password"
40 | },
41 | "Create new database username and password": {
42 | "Type": "Task",
43 | "Resource": "arn:aws:states:::lambda:invoke",
44 | "Parameters": {
45 | "Payload.$": "$",
46 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-UserDatabaseCreatorPersonalUsernameGe-dgk0cAkQs0VW"
47 | },
48 | "Retry": [
49 | {
50 | "ErrorEquals": [
51 | "Lambda.ServiceException",
52 | "Lambda.AWSLambdaException",
53 | "Lambda.SdkClientException"
54 | ],
55 | "IntervalSeconds": 2,
56 | "MaxAttempts": 6,
57 | "BackoffRate": 2
58 | }
59 | ],
60 | "ResultPath": "$.newCreds",
61 | "Comment": "returns back {username,password}",
62 | "Next": "Create user on the database",
63 | "ResultSelector": {
64 | "username.$": "$.Payload.username",
65 | "password.$": "$.Payload.password",
66 | "otsUrl.$": "$.Payload.otsUrl"
67 | }
68 | },
69 | "Create user on the database": {
70 | "Type": "Task",
71 | "Resource": "arn:aws:states:::lambda:invoke",
72 | "Parameters": {
73 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-Databaseadhocsingl2E02F587-yZxuEpPiDCUc",
74 | "Payload": {
75 | "script.$": "States.Format('CREATE ROLE {} LOGIN PASSWORD \\'{}\\'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to {}; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to {}; GRANT {} to {};', $.newCreds.username, $.newCreds.password, $.newCreds.username, $.newCreds.username, $.databaseSecret.ParsedValue.SQL_USER,$.newCreds.username)",
76 | "databaseName.$": "$.databaseSecret.ParsedValue.SQL_DATABASE"
77 | }
78 | },
79 | "Retry": [
80 | {
81 | "ErrorEquals": [
82 | "Lambda.ServiceException",
83 | "Lambda.AWSLambdaException",
84 | "Lambda.SdkClientException"
85 | ],
86 | "IntervalSeconds": 2,
87 | "MaxAttempts": 6,
88 | "BackoffRate": 2
89 | }
90 | ],
91 | "ResultPath": "$.databaseResults",
92 | "Next": "Send credentials to user"
93 | },
94 | "Send credentials to user": {
95 | "Type": "Task",
96 | "Parameters": {
97 | "Destination": {
98 | "ToAddresses.$": "States.Array($.email)"
99 | },
100 | "Message": {
101 | "Body": {
102 | "Text": {
103 | "Data.$": "States.Format('New credentials were generated for you: \n\ndatabase: {}\nusername: {}\npassword: {} \nhost: {}', $.databaseSecret.ParsedValue.SQL_DATABASE, $.newCreds.username, $.newCreds.otsUrl, $.databaseSecret.ParsedValue.SQL_HOST)"
104 | }
105 | },
106 | "Subject": {
107 | "Data": "New database access credentials have been created for you!"
108 | }
109 | },
110 | "Source": "devops@momnt.com"
111 | },
112 | "Resource": "arn:aws:states:::aws-sdk:ses:sendEmail",
113 | "End": true
114 | },
115 | "Get engines secret": {
116 | "Type": "Task",
117 | "Parameters": {
118 | "SecretId": "qa2/engines-secrets"
119 | },
120 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
121 | "ResultPath": "$.databaseSecret",
122 | "Next": "Parse engines secret value"
123 | },
124 | "Parse engines secret value": {
125 | "Type": "Pass",
126 | "Parameters": {
127 | "ParsedValue.$": "States.StringToJson($.databaseSecret.SecretString)"
128 | },
129 | "ResultPath": "$.databaseSecret",
130 | "Next": "Create new database username and password for engines"
131 | },
132 | "Create new database username and password for engines": {
133 | "Type": "Task",
134 | "Resource": "arn:aws:states:::lambda:invoke",
135 | "Parameters": {
136 | "Payload.$": "$",
137 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Database-UserDatabaseCreatorPersonalUsernameGe-dmIs8HXvJAYc"
138 | },
139 | "Retry": [
140 | {
141 | "ErrorEquals": [
142 | "Lambda.ServiceException",
143 | "Lambda.AWSLambdaException",
144 | "Lambda.SdkClientException"
145 | ],
146 | "IntervalSeconds": 2,
147 | "MaxAttempts": 6,
148 | "BackoffRate": 2
149 | }
150 | ],
151 | "ResultPath": "$.newCreds",
152 | "Comment": "returns back {username,password}",
153 | "ResultSelector": {
154 | "username.$": "$.Payload.username",
155 | "password.$": "$.Payload.password",
156 | "otsUrl.$": "$.Payload.otsUrl"
157 | },
158 | "Next": "Create user on jasmine"
159 | },
160 | "Create user on jasmine": {
161 | "Type": "Task",
162 | "Resource": "arn:aws:states:::lambda:invoke",
163 | "Parameters": {
164 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-Databaseadhocsingl2E02F587-yZxuEpPiDCUc",
165 | "Payload": {
166 | "script.$": "States.Format('CREATE ROLE {} LOGIN PASSWORD \\'{}\\'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA engine_rules to {}; GRANT ALL PRIVILEGES ON SCHEMA engine_rules to {}; GRANT {} to {};', $.newCreds.username, $.newCreds.password, $.newCreds.username, $.newCreds.username, $.databaseSecret.ParsedValue.PGUSER, $.newCreds.username)",
167 | "databaseName.$": "$.databaseSecret.ParsedValue.PGDATABASE"
168 | }
169 | },
170 | "Retry": [
171 | {
172 | "ErrorEquals": [
173 | "Lambda.ServiceException",
174 | "Lambda.AWSLambdaException",
175 | "Lambda.SdkClientException"
176 | ],
177 | "IntervalSeconds": 2,
178 | "MaxAttempts": 6,
179 | "BackoffRate": 2
180 | }
181 | ],
182 | "ResultPath": "$.databaseResults",
183 | "Next": "Send credentials to jasmine user"
184 | },
185 | "Send credentials to jasmine user": {
186 | "Type": "Task",
187 | "Parameters": {
188 | "Destination": {
189 | "ToAddresses.$": "States.Array($.email)"
190 | },
191 | "Message": {
192 | "Body": {
193 | "Text": {
194 | "Data.$": "States.Format('New credentials were generated for you: \n\ndatabase: {}\nusername: {}\npassword: {} \nhost: {}', $.databaseSecret.ParsedValue.PGDATABASE, $.newCreds.username, $.newCreds.otsUrl, $.databaseSecret.ParsedValue.PGHOST)"
195 | }
196 | },
197 | "Subject": {
198 | "Data": "New database access credentials have been created for you!"
199 | }
200 | },
201 | "Source": "devops@momnt.com"
202 | },
203 | "Resource": "arn:aws:states:::aws-sdk:ses:sendEmail",
204 | "End": true
205 | },
206 |
207 | "Get anna secret": {
208 | "Type": "Task",
209 | "Next": "Parse anna secret value",
210 | "Parameters": {
211 | "SecretId": "qa2/anna-sql-secrets"
212 | },
213 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
214 | "ResultPath": "$.databaseSecret"
215 | },
216 | "Parse anna secret value": {
217 | "Type": "Pass",
218 | "Parameters": {
219 | "ParsedValue.$": "States.StringToJson($.databaseSecret.SecretString)"
220 | },
221 | "ResultPath": "$.databaseSecret",
222 | "Next": "Create new database username and password for anna"
223 | },
224 | "Create new database username and password for anna": {
225 | "Type": "Task",
226 | "Resource": "arn:aws:states:::lambda:invoke",
227 | "Parameters": {
228 | "Payload.$": "$",
229 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-UserDatabaseCreatorPersonalUsernameGe-dgk0cAkQs0VW"
230 | },
231 | "Retry": [
232 | {
233 | "ErrorEquals": [
234 | "Lambda.ServiceException",
235 | "Lambda.AWSLambdaException",
236 | "Lambda.SdkClientException"
237 | ],
238 | "IntervalSeconds": 2,
239 | "MaxAttempts": 6,
240 | "BackoffRate": 2
241 | }
242 | ],
243 | "ResultPath": "$.newCreds",
244 | "Comment": "returns back {username,password}",
245 | "Next": "Create user on the anna database",
246 | "ResultSelector": {
247 | "username.$": "$.Payload.username",
248 | "password.$": "$.Payload.password",
249 | "otsUrl.$": "$.Payload.otsUrl"
250 | }
251 | },
252 | "Create user on the anna database": {
253 | "Type": "Task",
254 | "Resource": "arn:aws:states:::lambda:invoke",
255 | "Parameters": {
256 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-Databaseadhocsingl2E02F587-yZxuEpPiDCUc",
257 | "Payload": {
258 | "script.$": "States.Format('CREATE ROLE {} LOGIN PASSWORD \\'{}\\'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to {}; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to {}; GRANT {} to {};', $.newCreds.username, $.newCreds.password, $.newCreds.username, $.newCreds.username, $.databaseSecret.ParsedValue.PGUSER, $.newCreds.username)",
259 | "databaseName.$": "$.databaseSecret.ParsedValue.PGDATABASE"
260 | }
261 | },
262 | "Retry": [
263 | {
264 | "ErrorEquals": [
265 | "Lambda.ServiceException",
266 | "Lambda.AWSLambdaException",
267 | "Lambda.SdkClientException"
268 | ],
269 | "IntervalSeconds": 2,
270 | "MaxAttempts": 6,
271 | "BackoffRate": 2
272 | }
273 | ],
274 | "ResultPath": "$.databaseResults",
275 | "Next": "Send credentials to user for anna"
276 | },
277 | "Send credentials to user for anna": {
278 | "Type": "Task",
279 | "Parameters": {
280 | "Destination": {
281 | "ToAddresses.$": "States.Array($.email)"
282 | },
283 | "Message": {
284 | "Body": {
285 | "Text": {
286 | "Data.$": "States.Format('New credentials were generated for you: \n\ndatabase: {}\nusername: {}\npassword: {} \nhost: {}', $.databaseSecret.ParsedValue.PGDATABASE, $.newCreds.username, $.newCreds.otsUrl, $.databaseSecret.ParsedValue.PGHOST)"
287 | }
288 | },
289 | "Subject": {
290 | "Data": "New database access credentials have been created for you!"
291 | }
292 | },
293 | "Source": "devops@momnt.com"
294 | },
295 | "Resource": "arn:aws:states:::aws-sdk:ses:sendEmail",
296 | "End": true
297 | }
298 | },
299 | "Comment": "must provide:\nusername (will be prefix)\ndatabaseName (jasmine or belle, don't have to have full name, but should be able to?)\nemail (the email address to send results to)"
300 | }
301 |
--------------------------------------------------------------------------------
/test/step-functions/test.workflow.json:
--------------------------------------------------------------------------------
1 | {
2 | "StartAt": "Which database?",
3 | "States": {
4 | "Which database?": {
5 | "Type": "Choice",
6 | "Choices": [
7 | {
8 | "Variable": "$.databaseName",
9 | "StringMatches": "belle*",
10 | "Next": "Get belle secret"
11 | },
12 | {
13 | "Variable": "$.databaseName",
14 | "StringMatches": "jasmine*",
15 | "Next": "Get engines secret"
16 | },
17 | {
18 | "Variable": "$.databaseName",
19 | "StringMatches": "anna*",
20 | "Next": "Get anna secret"
21 | }
22 | ]
23 | },
24 | "Get belle secret": {
25 | "Type": "Task",
26 | "Next": "Parse belle secret value",
27 | "Parameters": {
28 | "SecretId": "qa2/belle-sql-secrets"
29 | },
30 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
31 | "ResultPath": "$.databaseSecret"
32 | },
33 | "Parse belle secret value": {
34 | "Type": "Pass",
35 | "Parameters": {
36 | "ParsedValue.$": "States.StringToJson($.databaseSecret.SecretString)"
37 | },
38 | "ResultPath": "$.databaseSecret",
39 | "Next": "Create new database username and password"
40 | },
41 | "Create new database username and password": {
42 | "Type": "Task",
43 | "Resource": "arn:aws:states:::lambda:invoke",
44 | "Parameters": {
45 | "Payload.$": "$",
46 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-UserDatabaseCreatorPersonalUsernameGe-dgk0cAkQs0VW"
47 | },
48 | "Retry": [
49 | {
50 | "ErrorEquals": [
51 | "Lambda.ServiceException",
52 | "Lambda.AWSLambdaException",
53 | "Lambda.SdkClientException"
54 | ],
55 | "IntervalSeconds": 2,
56 | "MaxAttempts": 6,
57 | "BackoffRate": 2
58 | }
59 | ],
60 | "ResultPath": "$.newCreds",
61 | "Comment": "returns back {username,password}",
62 | "Next": "Create user on the database",
63 | "ResultSelector": {
64 | "username.$": "$.Payload.username",
65 | "password.$": "$.Payload.password",
66 | "otsUrl.$": "$.Payload.otsUrl"
67 | }
68 | },
69 | "Create user on the database": {
70 | "Type": "Task",
71 | "Resource": "arn:aws:states:::lambda:invoke",
72 | "Parameters": {
73 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-Databaseadhocsingl2E02F587-yZxuEpPiDCUc",
74 | "Payload": {
75 | "script.$": "States.Format('CREATE ROLE {} LOGIN PASSWORD \\'{}\\'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to {}; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to {}; GRANT {} to {};', $.newCreds.username, $.newCreds.password, $.newCreds.username, $.newCreds.username, $.databaseSecret.ParsedValue.SQL_USER,$.newCreds.username)",
76 | "databaseName.$": "$.databaseSecret.ParsedValue.SQL_DATABASE"
77 | }
78 | },
79 | "Retry": [
80 | {
81 | "ErrorEquals": [
82 | "Lambda.ServiceException",
83 | "Lambda.AWSLambdaException",
84 | "Lambda.SdkClientException"
85 | ],
86 | "IntervalSeconds": 2,
87 | "MaxAttempts": 6,
88 | "BackoffRate": 2
89 | }
90 | ],
91 | "ResultPath": "$.databaseResults",
92 | "Next": "Send credentials to user"
93 | },
94 | "Send credentials to user": {
95 | "Type": "Task",
96 | "Parameters": {
97 | "Destination": {
98 | "ToAddresses.$": "States.Array($.email)"
99 | },
100 | "Message": {
101 | "Body": {
102 | "Text": {
103 | "Data.$": "States.Format('New credentials were generated for you: \n\ndatabase: {}\nusername: {}\npassword: {} \nhost: {}', $.databaseSecret.ParsedValue.SQL_DATABASE, $.newCreds.username, $.newCreds.otsUrl, $.databaseSecret.ParsedValue.SQL_HOST)"
104 | }
105 | },
106 | "Subject": {
107 | "Data": "New database access credentials have been created for you!"
108 | }
109 | },
110 | "Source": "devops@momnt.com"
111 | },
112 | "Resource": "arn:aws:states:::aws-sdk:ses:sendEmail",
113 | "End": true
114 | },
115 | "Get engines secret": {
116 | "Type": "Task",
117 | "Parameters": {
118 | "SecretId": "qa2/engines-secrets"
119 | },
120 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
121 | "ResultPath": "$.databaseSecret",
122 | "Next": "Parse engines secret value"
123 | },
124 | "Parse engines secret value": {
125 | "Type": "Pass",
126 | "Parameters": {
127 | "ParsedValue.$": "States.StringToJson($.databaseSecret.SecretString)"
128 | },
129 | "ResultPath": "$.databaseSecret",
130 | "Next": "Create new database username and password for engines"
131 | },
132 | "Create new database username and password for engines": {
133 | "Type": "Task",
134 | "Resource": "arn:aws:states:::lambda:invoke",
135 | "Parameters": {
136 | "Payload.$": "$",
137 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Database-UserDatabaseCreatorPersonalUsernameGe-dmIs8HXvJAYc"
138 | },
139 | "Retry": [
140 | {
141 | "ErrorEquals": [
142 | "Lambda.ServiceException",
143 | "Lambda.AWSLambdaException",
144 | "Lambda.SdkClientException"
145 | ],
146 | "IntervalSeconds": 2,
147 | "MaxAttempts": 6,
148 | "BackoffRate": 2
149 | }
150 | ],
151 | "ResultPath": "$.newCreds",
152 | "Comment": "returns back {username,password}",
153 | "ResultSelector": {
154 | "username.$": "$.Payload.username",
155 | "password.$": "$.Payload.password",
156 | "otsUrl.$": "$.Payload.otsUrl"
157 | },
158 | "Next": "Create user on jasmine"
159 | },
160 | "Create user on jasmine": {
161 | "Type": "Task",
162 | "Resource": "arn:aws:states:::lambda:invoke",
163 | "Parameters": {
164 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-Databaseadhocsingl2E02F587-yZxuEpPiDCUc",
165 | "Payload": {
166 | "script.$": "States.Format('CREATE ROLE {} LOGIN PASSWORD \\'{}\\'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA engine_rules to {}; GRANT ALL PRIVILEGES ON SCHEMA engine_rules to {}; GRANT {} to {};', $.newCreds.username, $.newCreds.password, $.newCreds.username, $.newCreds.username, $.databaseSecret.ParsedValue.PGUSER, $.newCreds.username)",
167 | "databaseName.$": "$.databaseSecret.ParsedValue.PGDATABASE"
168 | }
169 | },
170 | "Retry": [
171 | {
172 | "ErrorEquals": [
173 | "Lambda.ServiceException",
174 | "Lambda.AWSLambdaException",
175 | "Lambda.SdkClientException"
176 | ],
177 | "IntervalSeconds": 2,
178 | "MaxAttempts": 6,
179 | "BackoffRate": 2
180 | }
181 | ],
182 | "ResultPath": "$.databaseResults",
183 | "Next": "Send credentials to jasmine user"
184 | },
185 | "Send credentials to jasmine user": {
186 | "Type": "Task",
187 | "Parameters": {
188 | "Destination": {
189 | "ToAddresses.$": "States.Array($.email)"
190 | },
191 | "Message": {
192 | "Body": {
193 | "Text": {
194 | "Data.$": "States.Format('New credentials were generated for you: \n\ndatabase: {}\nusername: {}\npassword: {} \nhost: {}', $.databaseSecret.ParsedValue.PGDATABASE, $.newCreds.username, $.newCreds.otsUrl, $.databaseSecret.ParsedValue.PGHOST)"
195 | }
196 | },
197 | "Subject": {
198 | "Data": "New database access credentials have been created for you!"
199 | }
200 | },
201 | "Source": "devops@momnt.com"
202 | },
203 | "Resource": "arn:aws:states:::aws-sdk:ses:sendEmail",
204 | "End": true
205 | },
206 |
207 | "Get anna secret": {
208 | "Type": "Task",
209 | "Next": "Parse anna secret value",
210 | "Parameters": {
211 | "SecretId": "qa2/anna-sql-secrets"
212 | },
213 | "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
214 | "ResultPath": "$.databaseSecret"
215 | },
216 | "Parse anna secret value": {
217 | "Type": "Pass",
218 | "Parameters": {
219 | "ParsedValue.$": "States.StringToJson($.databaseSecret.SecretString)"
220 | },
221 | "ResultPath": "$.databaseSecret",
222 | "Next": "Create new database username and password for anna"
223 | },
224 | "Create new database username and password for anna": {
225 | "Type": "Task",
226 | "Resource": "arn:aws:states:::lambda:invoke",
227 | "Parameters": {
228 | "Payload.$": "$",
229 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-UserDatabaseCreatorPersonalUsernameGe-dgk0cAkQs0VW"
230 | },
231 | "Retry": [
232 | {
233 | "ErrorEquals": [
234 | "Lambda.ServiceException",
235 | "Lambda.AWSLambdaException",
236 | "Lambda.SdkClientException"
237 | ],
238 | "IntervalSeconds": 2,
239 | "MaxAttempts": 6,
240 | "BackoffRate": 2
241 | }
242 | ],
243 | "ResultPath": "$.newCreds",
244 | "Comment": "returns back {username,password}",
245 | "Next": "Create user on the anna database",
246 | "ResultSelector": {
247 | "username.$": "$.Payload.username",
248 | "password.$": "$.Payload.password",
249 | "otsUrl.$": "$.Payload.otsUrl"
250 | }
251 | },
252 | "Create user on the anna database": {
253 | "Type": "Task",
254 | "Resource": "arn:aws:states:::lambda:invoke",
255 | "Parameters": {
256 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa2-Database-Databaseadhocsingl2E02F587-yZxuEpPiDCUc",
257 | "Payload": {
258 | "script.$": "States.Format('CREATE ROLE {} LOGIN PASSWORD \\'{}\\'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to {}; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to {}; GRANT {} to {};', $.newCreds.username, $.newCreds.password, $.newCreds.username, $.newCreds.username, $.databaseSecret.ParsedValue.PGUSER, $.newCreds.username)",
259 | "databaseName.$": "$.databaseSecret.ParsedValue.PGDATABASE"
260 | }
261 | },
262 | "Retry": [
263 | {
264 | "ErrorEquals": [
265 | "Lambda.ServiceException",
266 | "Lambda.AWSLambdaException",
267 | "Lambda.SdkClientException"
268 | ],
269 | "IntervalSeconds": 2,
270 | "MaxAttempts": 6,
271 | "BackoffRate": 2
272 | }
273 | ],
274 | "ResultPath": "$.databaseResults",
275 | "Next": "Send credentials to user for anna"
276 | },
277 | "Send credentials to user for anna": {
278 | "Type": "Task",
279 | "Parameters": {
280 | "Destination": {
281 | "ToAddresses.$": "States.Array($.email)"
282 | },
283 | "Message": {
284 | "Body": {
285 | "Text": {
286 | "Data.$": "States.Format('New credentials were generated for you: \n\ndatabase: {}\nusername: {}\npassword: {} \nhost: {}', $.databaseSecret.ParsedValue.PGDATABASE, $.newCreds.username, $.newCreds.otsUrl, $.databaseSecret.ParsedValue.PGHOST)"
287 | }
288 | },
289 | "Subject": {
290 | "Data": "New database access credentials have been created for you!"
291 | }
292 | },
293 | "Source": "devops@momnt.com"
294 | },
295 | "Resource": "arn:aws:states:::aws-sdk:ses:sendEmail",
296 | "End": true
297 | }
298 | },
299 | "Comment": "must provide:\nusername (will be prefix)\ndatabaseName (jasmine or belle, don't have to have full name, but should be able to?)\nemail (the email address to send results to)"
300 | }
301 |
--------------------------------------------------------------------------------
/test/step-functions/test.yaml.asl:
--------------------------------------------------------------------------------
1 | StartAt: Check Stock Price
2 | States:
3 | Check Stock Price:
4 | Type: Task
5 | Resource: >-
6 | arn:aws:lambda:us-east-1:843153345658:function:StepFunctionsSample-HelloLam-CheckStockPriceLambda-9Ql8L0vFGNyX
7 | Next: Generate Buy/Sell recommendation
8 | Generate Buy/Sell recommendation:
9 | Type: Task
10 | Resource: >-
11 | arn:aws:lambda:us-east-1:843153345658:function:StepFunctionsSample-Hello-GenerateBuySellRecommend-RV43mVlWrlRp
12 | ResultPath: $.recommended_type
13 | Next: Request Human Approval
14 | Request Human Approval:
15 | Type: Task
16 | Resource: arn:aws:states:::sqs:sendMessage.waitForTaskToken
17 | Parameters:
18 | QueueUrl: >-
19 | https://sqs.us-east-1.amazonaws.com/843153345658/StepFunctionsSample-HelloLambda1cfd9e64-a1b-RequestHumanApprovalSqs-1ctyDMjtCfTL
20 | MessageBody:
21 | Input.$: $
22 | TaskToken.$: $$.Task.Token
23 | ResultPath: null
24 | Next: Buy or Sell?
25 | Buy or Sell?:
26 | Type: Choice
27 | Choices:
28 | - Variable: $.recommended_type
29 | StringEquals: buy
30 | Next: Buy Stock
31 | - Variable: $.recommended_type
32 | StringEquals: sell
33 | Next: Sell Stock
34 | Buy Stock:
35 | Type: Task
36 | Resource: >-
37 | arn:aws:lambda:us-east-1:843153345658:function:StepFunctionsSample-HelloLambda1cfd-BuyStockLambda-ggejR4EeAftC
38 | Next: Report Result
39 | Sell Stock:
40 | Type: Task
41 | Resource: >-
42 | arn:aws:lambda:us-east-1:843153345658:function:StepFunctionsSample-HelloLambda1cf-SellStockLambda-HY85TtYKY9xk
43 | Next: Report Result
44 | Report Result:
45 | Type: Task
46 | Resource: arn:aws:states:::sns:publish
47 | Parameters:
48 | TopicArn: >-
49 | arn:aws:sns:us-east-1:843153345658:StepFunctionsSample-HelloLambda1cfd9e64-a1bb-45f1-b2b0-7e258d8ba55f-ReportResultSnsTopic-GABSbYyOACQR
50 | Message:
51 | Input.$: $
52 | End: true
53 |
--------------------------------------------------------------------------------
/test/step-functions/test2.workflow.json:
--------------------------------------------------------------------------------
1 | {
2 | "Comment": "A description of my state machine",
3 | "StartAt": "Get Pod To Execute On",
4 | "States": {
5 | "Get Pod To Execute On": {
6 | "Type": "Task",
7 | "Resource": "arn:aws:states:::lambda:invoke",
8 | "Parameters": {
9 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Cluster-KubectlProviderAD5CE4B2-MASGyPp0MUAp",
10 | "Payload": {
11 | "commands": [
12 | "get",
13 | "pods",
14 | "--selector=app=belle",
15 | "-ojson"
16 | ]
17 | }
18 | },
19 | "Retry": [
20 | {
21 | "ErrorEquals": [
22 | "Lambda.ServiceException",
23 | "Lambda.AWSLambdaException",
24 | "Lambda.SdkClientException"
25 | ],
26 | "IntervalSeconds": 2,
27 | "MaxAttempts": 6,
28 | "BackoffRate": 2
29 | }
30 | ],
31 | "ResultSelector": {
32 | "belle.$": "$.Payload"
33 | },
34 | "ResultPath": "$.pods",
35 | "Next": "Generate Commands",
36 | "Catch": [
37 | {
38 | "ErrorEquals": [
39 | "States.ALL"
40 | ],
41 | "Next": "Notify Slack of Error",
42 | "ResultPath": "$.error"
43 | }
44 | ]
45 | },
46 | "Generate Commands": {
47 | "Type": "Task",
48 | "Resource": "arn:aws:states:::lambda:invoke",
49 | "Parameters": {
50 | "Payload.$": "$",
51 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Cluster-GetConfigGetCommands036E8CAC-bfIUgcupKlMI"
52 | },
53 | "Retry": [
54 | {
55 | "ErrorEquals": [
56 | "Lambda.ServiceException",
57 | "Lambda.AWSLambdaException",
58 | "Lambda.SdkClientException"
59 | ],
60 | "IntervalSeconds": 2,
61 | "MaxAttempts": 6,
62 | "BackoffRate": 2
63 | }
64 | ],
65 | "ResultSelector": {
66 | "commands.$": "$.Payload.commands"
67 | },
68 | "ResultPath": "$.commands",
69 | "Next": "Run Command",
70 | "Catch": [
71 | {
72 | "ErrorEquals": [
73 | "States.ALL"
74 | ],
75 | "Next": "Notify Slack of Error",
76 | "ResultPath": "$.error"
77 | }
78 | ]
79 | },
80 | "Run Command": {
81 | "Type": "Task",
82 | "Resource": "arn:aws:states:::lambda:invoke",
83 | "Parameters": {
84 | "Payload": {
85 | "commands.$": "$.commands.commands"
86 | },
87 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Cluster-KubectlProviderAD5CE4B2-MASGyPp0MUAp"
88 | },
89 | "Retry": [
90 | {
91 | "ErrorEquals": [
92 | "Lambda.ServiceException",
93 | "Lambda.AWSLambdaException",
94 | "Lambda.SdkClientException"
95 | ],
96 | "IntervalSeconds": 2,
97 | "MaxAttempts": 6,
98 | "BackoffRate": 2
99 | }
100 | ],
101 | "ResultPath": "$.commandResults",
102 | "Next": "Notify Slack",
103 | "Catch": [
104 | {
105 | "ErrorEquals": [
106 | "States.ALL"
107 | ],
108 | "Next": "Notify Slack of Error",
109 | "ResultPath": "$.error"
110 | }
111 | ]
112 | },
113 | "Notify Slack": {
114 | "Type": "Task",
115 | "Resource": "arn:aws:states:::lambda:invoke",
116 | "Parameters": {
117 | "Payload.$": "$",
118 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Cluster-GetConfigNotifySlackHandlerCF56DE5E-flBCIqABv0mk"
119 | },
120 | "Retry": [
121 | {
122 | "ErrorEquals": [
123 | "Lambda.ServiceException",
124 | "Lambda.AWSLambdaException",
125 | "Lambda.SdkClientException"
126 | ],
127 | "IntervalSeconds": 2,
128 | "MaxAttempts": 6,
129 | "BackoffRate": 2
130 | }
131 | ],
132 | "ResultPath": null,
133 | "End": true,
134 | "Catch": [
135 | {
136 | "ErrorEquals": [
137 | "States.ALL"
138 | ],
139 | "Next": "Notify Slack of Error",
140 | "ResultPath": "$.error"
141 | }
142 | ]
143 | },
144 | "Notify Slack of Error": {
145 | "Type": "Task",
146 | "Resource": "arn:aws:states:::lambda:invoke",
147 | "Parameters": {
148 | "Payload.$": "$",
149 | "FunctionName": "arn:aws:lambda:us-east-1:754664436462:function:qa1-Cluster-GetConfigNotifySlackErrorHandlerA0AA40-JVUiGyKvwHRm"
150 | },
151 | "Retry": [
152 | {
153 | "ErrorEquals": [
154 | "Lambda.ServiceException",
155 | "Lambda.AWSLambdaException",
156 | "Lambda.SdkClientException"
157 | ],
158 | "IntervalSeconds": 2,
159 | "MaxAttempts": 6,
160 | "BackoffRate": 2
161 | }
162 | ],
163 | "End": true,
164 | "ResultPath": null
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/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 | "es2019"
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": "ES2019"
27 | },
28 | "include": [
29 | "src/**/*.ts",
30 | "test/**/*.ts",
31 | ".projenrc.ts",
32 | "projenrc/**/*.ts"
33 | ],
34 | "exclude": [
35 | "node_modules"
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------