From 80a9e89b521ffe4291ca778ce0e55871638a23b6 Mon Sep 17 00:00:00 2001 From: Markus Bergkvist Date: Wed, 6 Mar 2024 06:26:54 +0100 Subject: [PATCH] Add tests for aws-cn support The github, runner-provided and stage-options tests are duplicated and modified for using the aws-cn partition for the pipeline. The difference between the snapshots for the test suites looks correct when reviewing. --- test/__snapshots__/github.cn.test.ts.snap | 1087 +++++++++++++++++ .../runner-provided.cn.test.ts.snap | 74 ++ .../stage-options.cn.test.ts.snap | 934 ++++++++++++++ test/github.cn.test.ts | 513 ++++++++ test/runner-provided.cn.test.ts | 45 + test/stage-options.cn.test.ts | 580 +++++++++ 6 files changed, 3233 insertions(+) create mode 100644 test/__snapshots__/github.cn.test.ts.snap create mode 100644 test/__snapshots__/runner-provided.cn.test.ts.snap create mode 100644 test/__snapshots__/stage-options.cn.test.ts.snap create mode 100644 test/github.cn.test.ts create mode 100644 test/runner-provided.cn.test.ts create mode 100644 test/stage-options.cn.test.ts diff --git a/test/__snapshots__/github.cn.test.ts.snap b/test/__snapshots__/github.cn.test.ts.snap new file mode 100644 index 00000000..27e4422d --- /dev/null +++ b/test/__snapshots__/github.cn.test.ts.snap @@ -0,0 +1,1087 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`example app 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + container: + image: alpine + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: \\"16\\" + - name: Build + run: echo \\"nothing to do (cdk.out is committed)\\" + - run: echo post-build + Assets-DockerAsset1: + name: Publish Assets Assets-DockerAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - uses: docker/login-action@v2 + with: + registry: 000000000000.dkr.ecr.us-east-1.amazonaws.com + - id: Publish + name: Publish Assets-DockerAsset1 + run: /bin/bash ./cdk.out/assembly-StageA/publish-Assets-DockerAsset1-step.sh + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-StageA/publish-Assets-FileAsset1-step.sh + Assets-FileAsset2: + name: Publish Assets Assets-FileAsset2 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset2 + run: /bin/bash ./cdk.out/assembly-StageA/publish-Assets-FileAsset2-step.sh + Assets-FileAsset3: + name: Publish Assets Assets-FileAsset3 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset3 + run: /bin/bash ./cdk.out/assembly-StageA/publish-Assets-FileAsset3-step.sh + Assets-FileAsset4: + name: Publish Assets Assets-FileAsset4 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset4 + run: /bin/bash ./cdk.out/assembly-StageA/publish-Assets-FileAsset4-step.sh + Assets-FileAsset5: + name: Publish Assets Assets-FileAsset5 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset5 + run: /bin/bash ./cdk.out/assembly-StageB/publish-Assets-FileAsset5-step.sh + Assets-FileAsset6: + name: Publish Assets Assets-FileAsset6 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset6 + run: /bin/bash ./cdk.out/assembly-StageB/publish-Assets-FileAsset6-step.sh + StageA-Pre: + name: Pre + permissions: + contents: read + runs-on: ubuntu-latest + needs: + - Build-Build + env: {} + steps: + - run: echo hello + StageA-BucketStack-Deploy: + name: Deploy StageABucketStackEAC67DBE + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - Assets-FileAsset2 + - StageA-Pre + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: StageA-BucketStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + StageA-FunctionStack-Deploy: + name: Deploy StageAFunctionStackD42C27B8 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset3 + - Assets-FileAsset4 + - Assets-DockerAsset1 + - StageA-BucketStack-Deploy + - StageA-Pre + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: StageA-FunctionStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset3.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + outputs: + myout: \${{ steps.Deploy.outputs.myout }} + StageA-Post: + name: Post + permissions: + contents: read + runs-on: ubuntu-latest + needs: + - StageA-FunctionStack-Deploy + - StageA-BucketStack-Deploy + - StageA-FunctionStack-Deploy + - Build-Build + env: + FN_NAME: \${{ needs.StageA-FunctionStack-Deploy.outputs.myout }} + steps: + - run: \\"echo FN_NAME equals: $FN_NAME\\" + StageB-BucketStack-Deploy: + name: Deploy StageBBucketStackDF3FFF07 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset5 + - Assets-FileAsset2 + - StageA-BucketStack-Deploy + - StageA-FunctionStack-Deploy + - StageA-Pre + - StageA-Post + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-northwest-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::222222222222:role/cdk-hnb659fds-deploy-role-222222222222-cn-northwest-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: StageB-BucketStack + template: https://cdk-hnb659fds-assets-222222222222-cn-northwest-1.s3.cn-northwest-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset5.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::222222222222:role/cdk-hnb659fds-cfn-exec-role-222222222222-cn-northwest-1 + StageB-FunctionStack-Deploy: + name: Deploy StageBFunctionStack18098DCD + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset6 + - Assets-FileAsset4 + - Assets-DockerAsset1 + - StageB-BucketStack-Deploy + - StageA-BucketStack-Deploy + - StageA-FunctionStack-Deploy + - StageA-Pre + - StageA-Post + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-northwest-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::222222222222:role/cdk-hnb659fds-deploy-role-222222222222-cn-northwest-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: StageB-FunctionStack + template: https://cdk-hnb659fds-assets-222222222222-cn-northwest-1.s3.cn-northwest-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset6.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::222222222222:role/cdk-hnb659fds-cfn-exec-role-222222222222-cn-northwest-1 +" +`; + +exports[`pipeline publish asset scripts are in stage assembly directory 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build + run: \\"\\" + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ap-southeast-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStage/publish-Assets-FileAsset1-step.sh + Assets-FileAsset2: + name: Publish Assets Assets-FileAsset2 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ap-southeast-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset2 + run: /bin/bash ./cdk.out/assembly-MyStage/publish-Assets-FileAsset2-step.sh + MyStage-MyStack-Deploy: + name: Deploy MyStageMyStackD5720EA1 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - Assets-FileAsset2 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStage-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`pipeline with GitHub hosted runner override 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: windows-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out +" +`; + +exports[`pipeline with job settings 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + if: github.repository == 'account/repo' + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build + run: \\"\\" + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + if: github.repository == 'account/repo' + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + Assets-FileAsset2: + name: Publish Assets Assets-FileAsset2 + if: github.repository == 'account/repo' + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset2 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset2-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + if: github.repository == 'account/repo' + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - Assets-FileAsset2 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`pipeline with oidc authentication 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: write + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: write + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via OIDC Role + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + role-to-assume: arn:aws:iam::000000000000:role/GitHubActionRole + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + Assets-FileAsset2: + name: Publish Assets Assets-FileAsset2 + needs: + - Build-Build + permissions: + contents: read + id-token: write + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via OIDC Role + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + role-to-assume: arn:aws:iam::000000000000:role/GitHubActionRole + - id: Publish + name: Publish Assets-FileAsset2 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset2-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + permissions: + contents: read + id-token: write + needs: + - Build-Build + - Assets-FileAsset1 + - Assets-FileAsset2 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via OIDC Role + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + role-to-assume: arn:aws:iam::000000000000:role/GitHubActionRole + - name: Assume CDK Deploy Role + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ env.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ env.AWS_SECRET_ACCESS_KEY }} + aws-session-token: \${{ env.AWS_SESSION_TOKEN }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`pipeline with only a synth step 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out +" +`; + +exports[`pipeline with publish asset region override 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build + run: \\"\\" + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ap-southeast-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + Assets-FileAsset2: + name: Publish Assets Assets-FileAsset2 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ap-southeast-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset2 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset2-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - Assets-FileAsset2 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`pipeline with self-hosted runner override 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: + - self-hosted + - label1 + - label2 + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out +" +`; + +exports[`single wave/stage/stack 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build + run: \\"\\" + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + Assets-FileAsset2: + name: Publish Assets Assets-FileAsset2 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: github.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset2 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset2-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - Assets-FileAsset2 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; diff --git a/test/__snapshots__/runner-provided.cn.test.ts.snap b/test/__snapshots__/runner-provided.cn.test.ts.snap new file mode 100644 index 00000000..473977d2 --- /dev/null +++ b/test/__snapshots__/runner-provided.cn.test.ts.snap @@ -0,0 +1,74 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`pipeline without aws credentials 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: runner-provided.cn.out + - name: Install + run: npm install --no-save cdk-assets + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; diff --git a/test/__snapshots__/stage-options.cn.test.ts.snap b/test/__snapshots__/stage-options.cn.test.ts.snap new file mode 100644 index 00000000..2c4b63da --- /dev/null +++ b/test/__snapshots__/stage-options.cn.test.ts.snap @@ -0,0 +1,934 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`can set pre/post github action job step 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Synth: + name: Synthesize + if: contains(fromJson('[\\"push\\", \\"pull_request\\"]'), github.event_name) + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + if: contains(fromJson('[\\"push\\", \\"pull_request\\"]'), github.event_name) + needs: + - Build-Synth + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash + ./cdk.out/assembly-MyPrePostStack/publish-Assets-FileAsset1-step.sh + MyPrePostStack-PreDeployAction: + name: PreDeployAction + if: contains(fromJson('[\\"push\\", \\"pull_request\\"]'), github.event_name) + permissions: + contents: write + runs-on: ubuntu-latest + needs: + - Build-Synth + env: {} + steps: + - name: pre deploy action + uses: my-pre-deploy-action@1.0.0 + with: + app-id: 1234 + secrets: my-secrets + MyPrePostStack-MyStack-Deploy: + name: Deploy MyPrePostStackMyStack8AD5AF9E + if: success() && contains(github.event.issue.labels.*.name, 'deploy') + permissions: + contents: read + id-token: none + needs: + - Build-Synth + - Assets-FileAsset1 + - MyPrePostStack-PreDeployAction + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyPrePostStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + MyPrePostStack-PostDeployAction: + name: PostDeployAction + if: contains(fromJson('[\\"push\\", \\"pull_request\\"]'), github.event_name) + permissions: + contents: write + runs-on: ubuntu-latest + needs: + - MyPrePostStack-MyStack-Deploy + - Build-Synth + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: post deploy action + uses: my-post-deploy-action@1.0.0 + with: + app-id: 4321 + secrets: secrets +" +`; + +exports[`cloudformation stack capabilities can specify multiple capabilities 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`cloudformation stack capabilities can specify stack capabilities 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + capabilities: CAPABILITY_NAMED_IAM + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`github environment can specify multiple github environments 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStage1/publish-Assets-FileAsset1-step.sh + MyStage1-MyStack-Deploy: + name: Deploy MyStage1MyStack61AF4CC5 + permissions: + contents: read + id-token: none + environment: test + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStage1-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + MyStage2-MyStack-Deploy: + name: Deploy MyStage2MyStack9B82AF96 + permissions: + contents: read + id-token: none + environment: prod + needs: + - Build-Build + - Assets-FileAsset1 + - MyStage1-MyStack-Deploy + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-northwest-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::222222222222:role/cdk-hnb659fds-deploy-role-222222222222-cn-northwest-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStage2-MyStack + template: https://cdk-hnb659fds-assets-222222222222-cn-northwest-1.s3.cn-northwest-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::222222222222:role/cdk-hnb659fds-cfn-exec-role-222222222222-cn-northwest-1 +" +`; + +exports[`github stages in waves works 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + if: contains(github.event.issue.labels.*.name, 'deployToA') || + contains(github.event.issue.labels.*.name, 'deployToB') + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + if: contains(github.event.issue.labels.*.name, 'deployToA') || + contains(github.event.issue.labels.*.name, 'deployToB') + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStageA/publish-Assets-FileAsset1-step.sh + MyWave-PreWaveAction: + name: PreWaveAction + if: contains(github.event.issue.labels.*.name, 'deployToA') || + contains(github.event.issue.labels.*.name, 'deployToB') + permissions: + contents: write + runs-on: ubuntu-latest + needs: + - Build-Build + env: {} + steps: + - name: pre wave action + uses: my-pre-wave-action@1.0.0 + with: + app-id: 1234 + secrets: my-secrets + MyWave-MyStageA-MyStackA-Deploy: + name: Deploy MyStageAMyStackA0F0BE321 + if: success() && contains(github.event.issue.labels.*.name, 'deployToA') + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - MyWave-PreWaveAction + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStageA-MyStackA + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + MyWave-MyStageB-MyStackB-Deploy: + name: Deploy MyStageBMyStackBFE4B1ADE + if: success() && contains(github.event.issue.labels.*.name, 'deployToB') + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - MyWave-PreWaveAction + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::12345678901:role/cdk-hnb659fds-deploy-role-12345678901-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStageB-MyStackB + template: https://cdk-hnb659fds-assets-12345678901-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::12345678901:role/cdk-hnb659fds-cfn-exec-role-12345678901-cn-north-1 + MyWave-PostWaveAction: + name: PostWaveAction + if: contains(github.event.issue.labels.*.name, 'deployToA') || + contains(github.event.issue.labels.*.name, 'deployToB') + permissions: + contents: write + runs-on: ubuntu-latest + needs: + - MyWave-MyStageA-MyStackA-Deploy + - MyWave-MyStageB-MyStackB-Deploy + - Build-Build + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: post wave action + uses: my-post-wave-action@1.0.0 + with: + app-id: 4321 + secrets: secrets +" +`; + +exports[`job settings can specify job settings at stage level 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStack/publish-Assets-FileAsset1-step.sh + MyStack-MyStack-Deploy: + name: Deploy MyStack098574E7 + if: github.repository == 'github/repo' + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStack-MyStack + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 +" +`; + +exports[`stages in github waves works 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStageA/publish-Assets-FileAsset1-step.sh + MyWave-MyStageA-MyStackA-Deploy: + name: Deploy MyStageAMyStackA0F0BE321 + if: success() && contains(github.event.issue.labels.*.name, 'deployToA') + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStageA-MyStackA + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + MyWave-MyStageB-MyStackB-Deploy: + name: Deploy MyStageBMyStackBFE4B1ADE + if: success() && contains(github.event.issue.labels.*.name, 'deployToB') + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::12345678901:role/cdk-hnb659fds-deploy-role-12345678901-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStageB-MyStackB + template: https://cdk-hnb659fds-assets-12345678901-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::12345678901:role/cdk-hnb659fds-cfn-exec-role-12345678901-cn-north-1 +" +`; + +exports[`stages in pipeline works with \`if\` 1`] = ` +"# AUTOMATICALLY GENERATED FILE, DO NOT EDIT MANUALLY. +# Generated by AWS CDK and [cdk-pipelines-github](https://github.com/cdklabs/cdk-pipelines-github) + +name: deploy +on: + push: + branches: + - main + workflow_dispatch: {} +jobs: + Build-Build: + name: Synthesize + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + needs: [] + env: {} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install + run: yarn + - name: Build + run: yarn build + - name: Upload cdk.out + uses: actions/upload-artifact@v4 + with: + name: cdk.out + path: cdk.out + Assets-FileAsset1: + name: Publish Assets Assets-FileAsset1 + needs: + - Build-Build + permissions: + contents: read + id-token: none + runs-on: ubuntu-latest + outputs: + asset-hash: \${{ steps.Publish.outputs.asset-hash }} + steps: + - name: Download cdk.out + uses: actions/download-artifact@v4 + with: + name: cdk.out + path: stage.cn.out + - name: Install + run: npm install --no-save cdk-assets + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + - id: Publish + name: Publish Assets-FileAsset1 + run: /bin/bash ./cdk.out/assembly-MyStageA/publish-Assets-FileAsset1-step.sh + MyStageA-MyStackA-Deploy: + name: Deploy MyStageAMyStackA0F0BE321 + if: success() && contains(github.event.issue.labels.*.name, 'deployToA') + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStageA-MyStackA + template: https://cdk-hnb659fds-assets-111111111111-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::111111111111:role/cdk-hnb659fds-cfn-exec-role-111111111111-cn-north-1 + MyStageB-MyStackB-Deploy: + name: Deploy MyStageBMyStackBFE4B1ADE + if: success() && contains(github.event.issue.labels.*.name, 'deployToB') + permissions: + contents: read + id-token: none + needs: + - Build-Build + - Assets-FileAsset1 + - MyStageA-MyStackA-Deploy + runs-on: ubuntu-latest + steps: + - name: Authenticate Via GitHub Secrets + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: cn-north-1 + role-duration-seconds: 1800 + role-skip-session-tagging: true + aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws-cn:iam::12345678901:role/cdk-hnb659fds-deploy-role-12345678901-cn-north-1 + role-external-id: Pipeline + - id: Deploy + uses: aws-actions/aws-cloudformation-github-deploy@v1 + with: + name: MyStageB-MyStackB + template: https://cdk-hnb659fds-assets-12345678901-cn-north-1.s3.cn-north-1.amazonaws.com.cn/\${{ + needs.Assets-FileAsset1.outputs.asset-hash }}.json + no-fail-on-empty-changeset: \\"1\\" + role-arn: arn:aws-cn:iam::12345678901:role/cdk-hnb659fds-cfn-exec-role-12345678901-cn-north-1 +" +`; diff --git a/test/github.cn.test.ts b/test/github.cn.test.ts new file mode 100644 index 00000000..7d8f3a71 --- /dev/null +++ b/test/github.cn.test.ts @@ -0,0 +1,513 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { Stack, Stage } from 'aws-cdk-lib'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { ShellStep } from 'aws-cdk-lib/pipelines'; +import { GitHubExampleApp } from './example-app'; +import { withTemporaryDirectory, TestApp } from './testutil'; +import { GitHubWorkflow, JsonPatch, Runner, AwsCredentials } from '../src'; + +const fixtures = join(__dirname, 'fixtures'); + +beforeAll(() => { process.env.CDK_AWS_PARTITION = 'aws-cn'; }); +afterAll(() => { process.env.CDK_AWS_PARTITION = undefined; }); + +let app: TestApp; +beforeEach(() => { + const tempOutDir = 'github.cn.out'; + app = new TestApp({ + outdir: tempOutDir, + }); +}); + +afterEach(() => { + app.cleanup(); +}); + +test('pipeline with only a synth step', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + app.synth(); + + expect(readFileSync(github.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('pipeline with aws credentials', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + awsCredentials: { + accessKeyId: 'MY_ACCESS_KEY_ID', + secretAccessKey: 'MY_SECRET_ACCESS_KEY', + sessionToken: 'MY_SESSION_TOKEN', + }, + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + github.addStage(stage); + + app.synth(); + + const file = readFileSync(github.workflowPath, 'utf-8'); + expect(file).toContain('aws-access-key-id: \${{ secrets.MY_ACCESS_KEY_ID }}\n'); + expect(file).toContain('aws-secret-access-key: \${{ secrets.MY_SECRET_ACCESS_KEY }}\n'); + expect(file).toContain('aws-session-token: \${{ secrets.MY_SESSION_TOKEN }}\n'); + }); +}); + +test('pipeline with aws credentials using awsCreds', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + awsCreds: AwsCredentials.fromGitHubSecrets(), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + github.addStage(stage); + + app.synth(); + + const file = readFileSync(github.workflowPath, 'utf-8'); + expect(file).toContain('aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }}\n'); + expect(file).toContain('aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }}\n'); + }); +}); + +test('pipeline with aws credentials using OIDC and role-session-name', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + awsCreds: AwsCredentials.fromOpenIdConnect({ + roleSessionName: 'my-github-actions-session', + gitHubActionRoleArn: + 'arn:aws:iam::111111111111:role/my-github-actions-role', + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + github.addStage(stage); + + app.synth(); + + const file = readFileSync(github.workflowPath, 'utf-8'); + expect(file).toContain('role-session-name: my-github-actions-session\n'); + expect(file).toContain('role-to-assume: arn:aws:iam::111111111111:role/my-github-actions-role\n'); + }); +}); + +test('pipeline with aws credentials in custom secrets', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + awsCreds: AwsCredentials.fromGitHubSecrets({ + accessKeyId: 'MY_ACCESS_KEY_ID', + secretAccessKey: 'MY_SECRET_ACCESS_KEY', + sessionToken: 'MY_SESSION_TOKEN', + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + github.addStage(stage); + + app.synth(); + + const file = readFileSync(github.workflowPath, 'utf-8'); + expect(file).toContain('aws-access-key-id: \${{ secrets.MY_ACCESS_KEY_ID }}\n'); + expect(file).toContain('aws-secret-access-key: \${{ secrets.MY_SECRET_ACCESS_KEY }}\n'); + expect(file).toContain('aws-session-token: \${{ secrets.MY_SESSION_TOKEN }}\n'); + }); +}); + +test('pipeline with GitHub hosted runner override', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + runner: Runner.WINDOWS_LATEST, + }); + + app.synth(); + + expect(readFileSync(github.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('pipeline with self-hosted runner override', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + runner: Runner.selfHosted(['label1', 'label2']), + }); + + app.synth(); + + expect(readFileSync(github.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('pipeline with publish asset region override', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + commands: [], + }), + publishAssetsAuthRegion: 'ap-southeast-2', + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + const stack = new Stack(stage, 'MyStack'); + + new lambda.Function(stack, 'Function', { + code: lambda.Code.fromAsset(fixtures), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + }); + + pipeline.addStage(stage); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('pipeline publish asset scripts are in stage assembly directory', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + commands: [], + }), + publishAssetsAuthRegion: 'ap-southeast-2', + }); + + const stage = new Stage(app, 'MyStage', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + const stack = new Stack(stage, 'MyStack'); + + new lambda.Function(stack, 'Function', { + code: lambda.Code.fromAsset(fixtures), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + }); + + pipeline.addStage(stage); + + app.synth(); + + const file = readFileSync(pipeline.workflowPath, 'utf-8'); + expect(file).toContain('./cdk.out/assembly-MyStage/publish-Assets'); + expect(file).toMatchSnapshot(); + }); +}); + +test('pipeline with job settings', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + commands: [], + }), + jobSettings: { + if: 'github.repository == \'account/repo\'', + }, + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + const stack = new Stack(stage, 'MyStack'); + + new lambda.Function(stack, 'Function', { + code: lambda.Code.fromAsset(fixtures), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + }); + + pipeline.addStage(stage); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('single wave/stage/stack', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + commands: [], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + const stack = new Stack(stage, 'MyStack'); + + new lambda.Function(stack, 'Function', { + code: lambda.Code.fromAsset(fixtures), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + }); + + pipeline.addStage(stage); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('pipeline with oidc authentication', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + gitHubActionRoleArn: 'arn:aws:iam::000000000000:role/GitHubActionRole', + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + const stack = new Stack(stage, 'MyStack'); + + new lambda.Function(stack, 'Function', { + code: lambda.Code.fromAsset(fixtures), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + }); + + pipeline.addStage(stage); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); + +test('example app', () => { + withTemporaryDirectory((dir) => { + const repoDir = dir; + const githubApp = new GitHubExampleApp({ + repoDir: repoDir, + envA: 'aws://111111111111/cn-north-1', + envB: 'aws://222222222222/cn-northwest-1', + }); + githubApp.synth(); + expect(readFileSync(join(repoDir, '.github/workflows/deploy.yml'), 'utf-8')).toMatchSnapshot(); + }); +}); + +describe('workflow path', () => { + test('invalid workflow path fails', () => { + expect(() => { + new GitHubWorkflow(app, 'Pipeline', { + workflowPath: 'deploy.yml', + synth: new ShellStep('Build', { + commands: [], + }), + }); + }).toThrowError("workflow files must be stored in the '.github/workflows' directory of your repository"); + }); + + test('workflow path must be a yaml file', () => { + expect(() => { + new GitHubWorkflow(app, 'Pipeline', { + workflowPath: '.github/workflows/deploy.json', + synth: new ShellStep('Build', { + commands: [], + }), + }); + }).toThrowError('workflow file is expected to be a yaml file'); + }); +}); + +describe('diff protection when GITHUB_WORKFLOW set', () => { + test('synth fails with diff', () => { + // set GITHUB_WORKFLOW env variable to simulate GitHub environment + wrapEnv('GITHUB_WORKFLOW', 'deploy', () => withTemporaryDirectory((dir) => { + const repoDir = dir; + const githubApp = new GitHubExampleApp({ + repoDir: repoDir, + envA: 'aws://111111111111/cn-north-1', + envB: 'aws://222222222222/cn-northwest-1', + }); + expect(() => githubApp.synth()).toThrowError(/Please commit the updated workflow file/); + })); + }); + + test('synth succeeds with no diff', () => { + withTemporaryDirectory((dir) => { + const repoDir = dir; + const githubApp = new GitHubExampleApp({ + repoDir: repoDir, + envA: 'aws://111111111111/cn-north-1', + envB: 'aws://222222222222/cn-northwest-1', + }); + + // synth to write the deploy.yml the first time + githubApp.synth(); + + // simulate GitHub environment with the same deploy.yml + wrapEnv('GITHUB_WORKFLOW', 'deploy', () => githubApp.synth()); + }); + }); + + test('synth succeeds with no diff and escape hatches', () => { + withTemporaryDirectory((dir) => { + const repoDir = dir; + const githubApp = new GitHubExampleApp({ + repoDir: repoDir, + envA: 'aws://111111111111/cn-north-1', + envB: 'aws://222222222222/cn-northwest-1', + }); + + githubApp.workflowFile.patch(JsonPatch.replace('/jobs/Build-Build/runs-on', 'macos-latest')); + + // synth to write the deploy.yml the first time + githubApp.synth(); + + // simulate GitHub environment with the same deploy.yml + wrapEnv('GITHUB_WORKFLOW', 'deploy', () => githubApp.synth()); + }); + }); + + test('turn off diff protection', () => { + // set GITHUB_WORKFLOW env variable to simulate GitHub environment + wrapEnv('GITHUB_WORKFLOW', 'deploy', () => withTemporaryDirectory((dir) => { + app.node.setContext('cdk-pipelines-github:diffProtection', false); + new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + expect(() => app.synth()).not.toThrowError(); + })); + }); + + test('turn off diff protection using string', () => { + // set GITHUB_WORKFLOW env variable to simulate GitHub environment + wrapEnv('GITHUB_WORKFLOW', 'deploy', () => withTemporaryDirectory((dir) => { + app.node.setContext('cdk-pipelines-github:diffProtection', 'false'); + new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + expect(() => app.synth()).not.toThrowError(); + })); + }); +}); + +test('can escape hatch into workflow file', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + github.addStage(stage); + + // escape hatch + github.workflowFile.patch( + JsonPatch.add('/on/workflow_call', {}), + JsonPatch.remove('/on/workflow_dispatch'), + JsonPatch.replace('/jobs/Build-Build/runs-on', 'macos-latest'), + ); + + app.synth(); + + const file = readFileSync(github.workflowPath, 'utf-8'); + expect(file).toContain('workflow_call: {}\n'); + expect(file).not.toContain('workflow_dispatch: {}\n'); + expect(file).toContain('runs-on: macos-latest\n'); + }); +}); + +function wrapEnv(variable: string, value: string, cb: () => void) { + const original = process.env[variable]; + try { + process.env[variable] = value; + cb(); + } finally { + process.env[variable] = original; + } +} diff --git a/test/runner-provided.cn.test.ts b/test/runner-provided.cn.test.ts new file mode 100644 index 00000000..11655ccf --- /dev/null +++ b/test/runner-provided.cn.test.ts @@ -0,0 +1,45 @@ +import { readFileSync } from 'fs'; +import { Stack, Stage } from 'aws-cdk-lib'; +import { ShellStep } from 'aws-cdk-lib/pipelines'; +import { withTemporaryDirectory, TestApp } from './testutil'; +import { GitHubWorkflow, AwsCredentials } from '../src'; + +let app: TestApp; +beforeAll(() => { process.env.CDK_AWS_PARTITION = 'aws-cn'; }); +afterAll(() => { process.env.CDK_AWS_PARTITION = undefined; }); + +beforeEach(() => { + const tempOutDir = 'runner-provided.cn.out'; + app = new TestApp({ + outdir: tempOutDir, + }); +}); + +afterEach(() => { + app.cleanup(); +}); + +test('pipeline without aws credentials', () => { + withTemporaryDirectory((dir) => { + const github = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + awsCreds: AwsCredentials.runnerHasPreconfiguredCreds(), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + github.addStage(stage); + + app.synth(); + + expect(readFileSync(github.workflowPath, 'utf-8')).toMatchSnapshot(); + }); +}); diff --git a/test/stage-options.cn.test.ts b/test/stage-options.cn.test.ts new file mode 100644 index 00000000..9f941b77 --- /dev/null +++ b/test/stage-options.cn.test.ts @@ -0,0 +1,580 @@ +import { readFileSync } from 'fs'; +import { Stack, Stage } from 'aws-cdk-lib'; +import { ShellStep } from 'aws-cdk-lib/pipelines'; +import * as YAML from 'yaml'; +import { withTemporaryDirectory, TestApp } from './testutil'; +import { + GitHubWorkflow, + StackCapabilities, + GitHubActionStep, + AddGitHubStageOptions, + GitHubStage, + GitHubStageProps, +} from '../src'; + +beforeAll(() => { process.env.CDK_AWS_PARTITION = 'aws-cn'; }); +afterAll(() => { process.env.CDK_AWS_PARTITION = undefined; }); + +let app: TestApp; +beforeEach(() => { + const tempOutDir = 'stage.cn.out'; + app = new TestApp({ + outdir: tempOutDir, + }); +}); + +afterEach(() => { + app.cleanup(); +}); + +describe('github environment', () => { + test('can specify one github environment at the stage level', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(stage, { + gitHubEnvironment: { name: 'test' }, + }); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toContain( + 'environment: test\n', + ); + }); + }); + + test('can specify one github environment with url', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(stage, { + gitHubEnvironment: { name: 'test', url: 'test.com' }, + }); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatch(/.*environment:\s+name: test\s+url: test\.com.*/m); + }); + }); + + test('can specify multiple github environments', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + // Two stages + const testStage = new Stage(app, 'MyStage1', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + const prodStage = new GitHubStage(app, 'MyStage2', { + env: { account: '222222222222', region: 'cn-northwest-1' }, + gitHubEnvironment: { name: 'prod' }, + }); + + // Two stacks + new Stack(testStage, 'MyStack'); + new Stack(prodStage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(testStage, { + gitHubEnvironment: { name: 'test' }, + }); + pipeline.addStage(prodStage); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); + }); +}); + +describe('cloudformation stack capabilities', () => { + test('can specify stack capabilities', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(stage, { + stackCapabilities: [StackCapabilities.NAMED_IAM], + }); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); + }); + + test('can specify multiple capabilities', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(stage, { + stackCapabilities: [ + StackCapabilities.NAMED_IAM, + StackCapabilities.IAM, + StackCapabilities.AUTO_EXPAND, + ], + }); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); + }); +}); + +describe('job settings', () => { + test('can specify job settings at stage level', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(stage, { + jobSettings: { + if: "github.repository == 'github/repo'", + }, + }); + + app.synth(); + + expect(readFileSync(pipeline.workflowPath, 'utf-8')).toMatchSnapshot(); + }); + }); + + test('stage-level job settings override app-level settings', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + jobSettings: { + if: "github.repository == 'another/repoA'", + }, + }); + + const stage = new Stage(app, 'MyStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStageWithGitHubOptions(stage, { + jobSettings: { + if: "github.repository == 'github/repoB'", + }, + }); + + app.synth(); + + const workflowFileContents = readFileSync(pipeline.workflowPath, 'utf-8'); + expect(workflowFileContents).toContain( + "if: github.repository == 'another/repoA'\n", + ); + expect(workflowFileContents).toContain( + "if: github.repository == 'github/repoB'\n", + ); + }); + }); +}); + +test('can set pre/post github action job step', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Synth', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + jobSettings: { + if: 'contains(fromJson(\'["push", "pull_request"]\'), github.event_name)', + }, + }); + + const stage = new GitHubStage(app, 'MyPrePostStack', { + env: { account: '111111111111', region: 'cn-north-1' }, + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deploy')", + }, + }); + + new Stack(stage, 'MyStack'); + + pipeline.addStage(stage, { + pre: [ + new GitHubActionStep('PreDeployAction', { + jobSteps: [ + { + name: 'pre deploy action', + uses: 'my-pre-deploy-action@1.0.0', + with: { + 'app-id': 1234, + 'secrets': 'my-secrets', + }, + }, + ], + }), + ], + + post: [ + new GitHubActionStep('PostDeployAction', { + jobSteps: [ + { + name: 'Checkout', + uses: 'actions/checkout@v4', + }, + { + name: 'post deploy action', + uses: 'my-post-deploy-action@1.0.0', + with: { + 'app-id': 4321, + 'secrets': 'secrets', + }, + }, + ], + }), + ], + }); + + app.synth(); + + const workflowFileContents = readFileSync(pipeline.workflowPath, 'utf-8'); + expect(workflowFileContents).toMatchSnapshot(); + expect(workflowFileContents).toContain('my-pre-deploy-action@1.0.0'); + expect(workflowFileContents).toContain('my-post-deploy-action@1.0.0'); + expect(workflowFileContents).toContain('actions/checkout@v4'); + expect(workflowFileContents).toContain( + 'contains(fromJson(\'["push", "pull_request"]\'), github.event_name)', + ); + expect(workflowFileContents).toContain( + "success() && contains(github.event.issue.labels.*.name, 'deploy')", + ); + }); +}); + +test('stages in github waves works', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stageA = new Stage(app, 'MyStageA', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stageA, 'MyStackA'); + + const wave = pipeline.addGitHubWave('MyWave'); + + const stageAOptions: AddGitHubStageOptions = { + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deployToA')", + }, + }; + wave.addStageWithGitHubOptions(stageA, stageAOptions); + + const stageBOptions: GitHubStageProps = { + env: { account: '12345678901', region: 'cn-north-1' }, + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deployToB')", + }, + }; + const stageB = new GitHubStage(app, 'MyStageB', stageBOptions); + + new Stack(stageB, 'MyStackB'); + + wave.addStage(stageB); + + app.synth(); + + const workflowFileContents = readFileSync(pipeline.workflowPath, 'utf-8'); + expect(workflowFileContents).toMatchSnapshot(); + + const yaml = YAML.parse(workflowFileContents); + expect(yaml).toMatchObject({ + jobs: { + 'MyWave-MyStageA-MyStackA-Deploy': { + if: stageAOptions.jobSettings?.if, + }, + 'MyWave-MyStageB-MyStackB-Deploy': { + if: stageBOptions.jobSettings?.if, + }, + }, + }); + }); +}); + +test('github stages in waves works', () => { + withTemporaryDirectory((dir) => { + const buildIfStatement = + "contains(github.event.issue.labels.*.name, 'deployToA') || contains(github.event.issue.labels.*.name, 'deployToB')"; + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + jobSettings: { + if: buildIfStatement, + }, + }); + + const stageAOptions: GitHubStageProps = { + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deployToA')", + }, + }; + const stageA = new GitHubStage(app, 'MyStageA', { + env: { account: '111111111111', region: 'cn-north-1' }, + ...stageAOptions, + }); + + new Stack(stageA, 'MyStackA'); + + const stageBOptions: GitHubStageProps = { + env: { account: '12345678901', region: 'cn-north-1' }, + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deployToB')", + }, + }; + const stageB = new GitHubStage(app, 'MyStageB', stageBOptions); + + new Stack(stageB, 'MyStackB'); + + // Make a wave to have the stages be parallel (not depend on each other) + const wave = pipeline.addGitHubWave('MyWave', { + pre: [ + new GitHubActionStep('PreWaveAction', { + jobSteps: [ + { + name: 'pre wave action', + uses: 'my-pre-wave-action@1.0.0', + with: { + 'app-id': 1234, + 'secrets': 'my-secrets', + }, + }, + ], + }), + ], + + post: [ + new GitHubActionStep('PostWaveAction', { + jobSteps: [ + { + name: 'Checkout', + uses: 'actions/checkout@v4', + }, + { + name: 'post wave action', + uses: 'my-post-wave-action@1.0.0', + with: { + 'app-id': 4321, + 'secrets': 'secrets', + }, + }, + ], + }), + ], + }); + wave.addStage(stageA); + wave.addStage(stageB); + + app.synth(); + + const workflowFileContents = readFileSync(pipeline.workflowPath, 'utf-8'); + expect(workflowFileContents).toMatchSnapshot(); + + const yaml = YAML.parse(workflowFileContents); + expect(yaml).toMatchObject({ + jobs: { + 'Build-Build': { + if: buildIfStatement, + }, + 'MyWave-MyStageA-MyStackA-Deploy': { + if: stageAOptions.jobSettings?.if, + }, + 'MyWave-MyStageB-MyStackB-Deploy': { + if: stageBOptions.jobSettings?.if, + }, + }, + }); + }); +}); + +test('stages in pipeline works with `if`', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stageA = new Stage(app, 'MyStageA', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + + new Stack(stageA, 'MyStackA'); + + const stageAOptions: AddGitHubStageOptions = { + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deployToA')", + }, + }; + pipeline.addStageWithGitHubOptions(stageA, stageAOptions); + + const stageBOptions: GitHubStageProps = { + env: { account: '12345678901', region: 'cn-north-1' }, + jobSettings: { + if: "success() && contains(github.event.issue.labels.*.name, 'deployToB')", + }, + }; + const stageB = new GitHubStage(app, 'MyStageB', stageBOptions); + + new Stack(stageB, 'MyStackB'); + + pipeline.addStage(stageB); + + app.synth(); + + const workflowFileContents = readFileSync(pipeline.workflowPath, 'utf-8'); + expect(workflowFileContents).toMatchSnapshot(); + expect(workflowFileContents).toContain('actions/checkout@v4'); + + const yaml = YAML.parse(workflowFileContents); + expect(yaml).toMatchObject({ + jobs: { + 'MyStageA-MyStackA-Deploy': { + if: stageAOptions.jobSettings?.if, + }, + 'MyStageB-MyStackB-Deploy': { + if: stageBOptions.jobSettings?.if, + }, + }, + }); + }); +}); + +test('stages added to a pipeline after build will fail', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const stageA = new Stage(app, 'MyStageA', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + new Stack(stageA, 'MyStackA'); + pipeline.addStageWithGitHubOptions(stageA, {}); + + const stageB = new GitHubStage(app, 'MyStageB', {}); + new Stack(stageB, 'MyStackB'); + + app.synth(); + + expect(() => pipeline.addStage(stageB)).toThrowErrorMatchingInlineSnapshot('"addStage: can\'t add Stages anymore after buildPipeline() has been called"'); + }); +}); + +// cannot test adding a stage to a GitHubWave post-build, since Waves to not throw an error in that case... + +test('waves added to a pipeline after build will fail', () => { + withTemporaryDirectory((dir) => { + const pipeline = new GitHubWorkflow(app, 'Pipeline', { + workflowPath: `${dir}/.github/workflows/deploy.yml`, + synth: new ShellStep('Build', { + installCommands: ['yarn'], + commands: ['yarn build'], + }), + }); + + const wave = pipeline.addGitHubWave('wave'); + + const stageA = new Stage(app, 'MyStageA', { + env: { account: '111111111111', region: 'cn-north-1' }, + }); + new Stack(stageA, 'MyStackA'); + wave.addStage(stageA, {}); + + const stageB = new GitHubStage(app, 'MyStageB', {}); + new Stack(stageB, 'MyStackB'); + + app.synth(); + + expect(() => pipeline.addGitHubWave('wave2')).toThrowErrorMatchingInlineSnapshot('"addWave: can\'t add Waves anymore after buildPipeline() has been called"'); + }); +});