UNPKG

deployable-awscdk-app-ts

Version:
666 lines • 93.7 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.DeployableAwsCdkTypeScriptAppStepsFactory = void 0; exports.getDeployJobId = getDeployJobId; exports.getDiffAnnotationJobId = getDiffAnnotationJobId; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const projen_1 = require("projen"); const github_1 = require("projen/lib/github"); const workflows_model_1 = require("projen/lib/github/workflows-model"); const javascript_1 = require("projen/lib/javascript"); const types_1 = require("./types"); const checkActiveDeploymentStepId = 'deployment-check'; const skipIfAlreadyActiveDeploymentCondition = `steps.${checkActiveDeploymentStepId}.outputs.has_active_deployment != 'true'`; const formattedDiffAnnotationCommentStepId = 'formatted_diff_annotation_comment'; /** * Factory to create reusable steps for the deployment workflow * @experimental */ class DeployableAwsCdkTypeScriptAppStepsFactory { /** * Validate that the provided environment deployment dependencies are valid * @param deployOptions The deployment options * @param environmentDependencies The environment deployment dependencies to validate */ static validateEnvironmentDeploymentDependencies(deployOptions, environmentDependencies) { if (deployOptions.jobStrategy !== types_1.DeployJobStrategy.MULTI_JOB) { throw new Error('Environment deployment dependencies are only supported for MULTI_JOB strategy'); } Object.entries(environmentDependencies).forEach(([env, deps]) => { const hasEnvironment = deployOptions.environments.some(e => e.name === env); if (!hasEnvironment) { throw new Error(`Environment "${env}" defined in dependencies does not exist in deployOptions.environments`); } deps.forEach(dep => { const hasDepEnvironment = deployOptions.environments.some(e => e.name === dep); if (!hasDepEnvironment) { throw new Error(`Dependency environment "${dep}" for environment "${env}" does not exist in deployOptions.environments`); } }); }); } /** * Create a new DeployableAwsCdkTypeScriptAppStepsFactory * @param project The project * @param props The factory properties */ constructor(project, props) { this.project = project; this.props = props; } /** * Condition to skip a step if an active deployment is already present * @returns JobStep condition or undefined if checkActiveDeployment is false */ get skipIfAlreadyActiveDeploymentCondition() { return this.props.checkActiveDeployment ? { if: `\${{ ${skipIfAlreadyActiveDeploymentCondition} }}` } : undefined; } get checkoutStep() { return github_1.WorkflowSteps.checkout({ with: { fetchDepth: 0, ref: '${{ github.sha }}', }, }); } /** * Step to run before installing dependencies if exists * @returns JobStep or undefined if no preInstallTaskName is provided */ get preInstallDependenciesStep() { if (!this.props.preInstallTaskName) { return undefined; } return { ...this.skipIfAlreadyActiveDeploymentCondition, name: this.props.preInstallTaskName, run: `npx projen ${this.props.preInstallTaskName}`, }; } /** * Step to check if there is an active deployment for the environment in the matrix strategy * @returns JobStep */ get checkActiveDeploymentStepForMatrix() { return this.getCheckActiveDeploymentStepForEnvironment('${{ matrix.environment }}'); } /** * Step to check if there is an active deployment for a specific environment * @param environment The environment to check * @returns JobStep */ getCheckActiveDeploymentStepForEnvironment(environment) { if (!this.props.checkActiveDeployment) { return undefined; } return { id: checkActiveDeploymentStepId, uses: 'AminFazlMondo/check-deployed-environment@v1', with: { environment: environment, }, env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}', }, }; } /** * Step to setup AWS credentials in the environment for the matrix strategy * @returns JobStep[] */ get setupAwsCredentialsStepsForMatrix() { return [ this.setupAwsCredentialsInEnvironmentForMatrix, this.assumeAwsRoleStepForMatrix, ]; } /** * Get the steps to setup AWS credentials for a specific environment * @param environmentOptions The environment options * @returns JobStep[] */ getSetupAwsCredentialsStepsForEnvironment(environmentOptions) { const steps = []; const fromEnvVariableStep = this.getSetupAwsCredentialsInEnvironmentForEnvironment(environmentOptions.awsCredentials.roleToAssume ? true : false, environmentOptions.awsCredentials.accessKeyIdSecretName ?? 'AWS_ACCESS_KEY_ID', environmentOptions.awsCredentials.secretAccessKeySecretName ?? 'AWS_SECRET_ACCESS_KEY', environmentOptions.awsCredentials.region); if (fromEnvVariableStep) { steps.push(fromEnvVariableStep); } const assumeRoleStep = this.getAssumeAwsRoleStepForEnvironment(environmentOptions.awsCredentials.roleToAssume ? true : false, environmentOptions.awsCredentials.accessKeyIdSecretName ?? 'AWS_ACCESS_KEY_ID', environmentOptions.awsCredentials.secretAccessKeySecretName ?? 'AWS_SECRET_ACCESS_KEY', environmentOptions.awsCredentials.region, environmentOptions.awsCredentials.roleToAssume ?? '', environmentOptions.awsCredentials.assumeRoleDurationSeconds ?? 900); if (assumeRoleStep) { steps.push(assumeRoleStep); } return steps; } /** * Step to setup AWS credentials in the environment for the matrix strategy * @returns JobStep */ get setupAwsCredentialsInEnvironmentForMatrix() { return this.getSetupAwsCredentialsInEnvironmentForEnvironment('matrix.assumeRole', 'matrix.accessKeyIdSecretName', 'matrix.secretAccessKeySecretName', '${{ matrix.region }}'); } /** * Step to setup AWS credentials in the environment for a specific environment * @param assumeRoleFlag Whether to assume a role, can be a boolean or a string for matrix strategy * @param accessKeyIdSecretName The GitHub secret name for the access key ID * @param secretAccessKeySecretName The GitHub secret name for the secret access key * @param region The region * @returns JobStep or undefined if no AWS credentials are provided, * if assumeRoleFlag is boolean will be evaluated and return a JobStep only if false * if assumeRoleFlag is string will always return a JobStep (for matrix strategy) */ getSetupAwsCredentialsInEnvironmentForEnvironment(assumeRoleFlag, accessKeyIdSecretName, secretAccessKeySecretName, region) { function getCondition(factory) { if (typeof assumeRoleFlag === 'boolean') { if (assumeRoleFlag) { return undefined; } return factory.props.checkActiveDeployment ? skipIfAlreadyActiveDeploymentCondition : undefined; } return factory.props.checkActiveDeployment ? `\${{ ${assumeRoleFlag} == 'false' && ${skipIfAlreadyActiveDeploymentCondition} }}` : `\${{ ${assumeRoleFlag} == 'false' }}`; } const commands = [ 'echo "AWS_ACCESS_KEY_ID=$accessKeyId" >> $GITHUB_ENV', 'echo "AWS_SECRET_ACCESS_KEY=$secretAccessKey" >> $GITHUB_ENV', 'echo "AWS_REGION=$region" >> $GITHUB_ENV', ]; if (typeof assumeRoleFlag === 'boolean' && assumeRoleFlag) { return undefined; } const condition = getCondition(this); return { if: condition, name: 'Configure AWS Credentials', run: `${commands.join('\n')}`, env: { accessKeyId: `\${{ secrets[${accessKeyIdSecretName}] }}`, secretAccessKey: `\${{ secrets[${secretAccessKeySecretName}] }}`, region, }, }; } /** * Step to assume an AWS role for the matrix strategy * @returns JobStep */ get assumeAwsRoleStepForMatrix() { return this.getAssumeAwsRoleStepForEnvironment('matrix.assumeRole', 'matrix.accessKeyIdSecretName', 'matrix.secretAccessKeySecretName', '${{ matrix.region }}', '${{ matrix.roleToAssume }}', '${{ matrix.assumeRoleDurationSeconds }}'); } /** * Step to assume an AWS role for a specific environment * @param assumeRoleFlag Whether to assume a role, can be a boolean or a string for matrix strategy * @param accessKeyIdSecretName The GitHub secret name for the access key ID * @param secretAccessKeySecretName The GitHub secret name for the secret access key * @param region The region * @param roleToAssume The role to assume * @param assumeRoleDurationSeconds The duration for assuming the role * @returns JobStep or undefined if assumeRoleFlag is boolean and false * if assumeRoleFlag is string will always return a JobStep (for matrix strategy) */ getAssumeAwsRoleStepForEnvironment(assumeRoleFlag, accessKeyIdSecretName, secretAccessKeySecretName, region, roleToAssume, assumeRoleDurationSeconds) { function getCondition(factory) { if (typeof assumeRoleFlag === 'boolean') { if (!assumeRoleFlag) { return undefined; } return factory.props.checkActiveDeployment ? skipIfAlreadyActiveDeploymentCondition : undefined; } return factory.props.checkActiveDeployment ? `\${{ ${assumeRoleFlag} == 'true' && ${skipIfAlreadyActiveDeploymentCondition} }}` : `\${{ ${assumeRoleFlag} == 'true' }}`; } if (typeof assumeRoleFlag === 'boolean' && !assumeRoleFlag) { return undefined; } const condition = getCondition(this); const secretsParams = this.props.authProvider === javascript_1.CodeArtifactAuthProvider.ACCESS_AND_SECRET_KEY_PAIR ? { 'aws-access-key-id': `\${{ secrets[${accessKeyIdSecretName}] }}`, 'aws-secret-access-key': `\${{ secrets[${secretAccessKeySecretName}] }}`, } : undefined; return { if: condition, name: 'Assume AWS Role', uses: 'aws-actions/configure-aws-credentials@v4', with: { ...secretsParams, 'role-to-assume': roleToAssume, 'aws-region': region, 'role-duration-seconds': assumeRoleDurationSeconds, }, }; } /** * Step to setup NPM config if provided * @returns JobStep or undefined if no npmConfig is provided */ get setupNpmConfigForMatrix() { return this.getSetupNpmConfigForEnvironment('${{ matrix.environment }}'); } getSetupNpmConfigForEnvironment(environment) { const { npmConfigEnvironment } = this.props; if (!npmConfigEnvironment) { return undefined; } const environmentVariableName = 'CONFIG_VALUE'; return { ...this.skipIfAlreadyActiveDeploymentCondition, name: 'Setting NPM Config', env: { [environmentVariableName]: environment, }, run: `npm config set ${npmConfigEnvironment} $${environmentVariableName}`, }; } /** * Get the step to run a specific script * @param scriptName The name of the script to run * @param stepName The name of the step in the workflow * @param hasScriptFlag Whether the script should be run * @returns The job step to run the script or undefined if not applicable * If hasScriptFlag is boolean and false will return undefined * If hasScriptFlag is string will always return a JobStep (for matrix strategy) */ getRunScriptStep(scriptName, stepName, hasScriptFlag) { function getCondition(factory) { if (typeof hasScriptFlag === 'boolean') { if (!hasScriptFlag) { return undefined; } return factory.props.checkActiveDeployment ? skipIfAlreadyActiveDeploymentCondition : undefined; } return factory.props.checkActiveDeployment ? `\${{ ${hasScriptFlag} == 'true' && ${skipIfAlreadyActiveDeploymentCondition} }}` : `\${{ ${hasScriptFlag} == 'true' }}`; } if (typeof hasScriptFlag === 'boolean' && !hasScriptFlag) { return undefined; } const condition = getCondition(this); return { if: condition, name: `Run ${stepName}`, run: `${this.project.runScriptCommand} ${scriptName}`, }; } /** * Step to deploy the workflow * @returns JobStep */ get deploymentStep() { return this.getRunScriptStep('deploy:workflow', 'Deployment', true); } /** * Step to run post deployment script in matrix strategy * @returns JobStep */ get preDeploymentStepForMatrix() { return this.getPreDeploymentStepForEnvironment('matrix.hasPreDeployTask', '${{ matrix.preDeploymentScript }}'); } /** * Get the pre-deployment step for a specific environment * @param hasPreDeployTaskFlag Whether the pre-deployment task should be run * @param preDeploymentScript The script to run * @returns The job step to run the pre-deployment script or undefined if not applicable * If hasPreDeployTaskFlag is boolean and false will return undefined * If hasPreDeployTaskFlag is string will always return a JobStep (for matrix strategy) */ getPreDeploymentStepForEnvironment(hasPreDeployTaskFlag, preDeploymentScript) { return this.getRunScriptStep(preDeploymentScript, 'Pre Deployment', hasPreDeployTaskFlag); } /** * Step to run post deployment script in matrix strategy * @returns JobStep */ get postDeploymentStepForMatrix() { return this.getPostDeploymentStepForEnvironment('matrix.hasPostDeployTask', '${{ matrix.postDeploymentScript }}'); } /** * Get the post-deployment step for a specific environment * @param hasPostDeployTaskFlag Whether the post-deployment task should be run * @param postDeploymentScript The script to run * @returns The job step to run the post-deployment script or undefined if not applicable * If hasPostDeployTaskFlag is boolean and false will return undefined * If hasPostDeployTaskFlag is string will always return a JobStep (for matrix strategy) */ getPostDeploymentStepForEnvironment(hasPostDeployTaskFlag, postDeploymentScript) { return this.getRunScriptStep(postDeploymentScript, 'Post Deployment', hasPostDeployTaskFlag); } /** * Get all deployment jobs whether for matrix strategy or not * @returns Record of jobs */ get deploymentJobs() { if (this.props.deployOptions.environments.length === 0) { this.project.logger.warn('The project does not have any environment set, make sure this is desired setting'); } return this.props.jobStrategy === types_1.DeployJobStrategy.MATRIX ? this.deploymentJobsForMatrix : this.deploymentJobsForMultiJob; } /** * Get deployment jobs for matrix strategy * @returns Record of jobs */ get deploymentJobsForMatrix() { const { environments, environmentVariableName } = this.props.deployOptions; const include = environments.map(environmentOptions => { const { awsCredentials } = environmentOptions; const assumeRole = awsCredentials.roleToAssume ? 'true' : 'false'; const assumeRoleSettings = awsCredentials.roleToAssume ? { roleToAssume: awsCredentials.roleToAssume, assumeRoleDurationSeconds: awsCredentials.assumeRoleDurationSeconds || 900, } : undefined; const accessKeyIdSecretName = awsCredentials.accessKeyIdSecretName ?? 'AWS_ACCESS_KEY_ID'; const secretAccessKeySecretName = awsCredentials.secretAccessKeySecretName ?? 'AWS_SECRET_ACCESS_KEY'; const hasPostDeployTask = environmentOptions.postDeployWorkflowScript ? 'true' : 'false'; const hasPreDeployTask = environmentOptions.preDeployWorkflowScript ? 'true' : 'false'; return { environment: environmentOptions.name, accessKeyIdSecretName, secretAccessKeySecretName, region: awsCredentials.region, assumeRole, hasPostDeployTask, postDeploymentScript: environmentOptions.postDeployWorkflowScript || '', hasPreDeployTask, preDeploymentScript: environmentOptions.preDeployWorkflowScript || '', ...assumeRoleSettings, }; }); const deployJobEnv = environmentVariableName ? { [environmentVariableName]: '${{ matrix.environment }}', } : undefined; const jobDefinition = { runsOn: ['ubuntu-latest'], concurrency: { 'group': '${{ matrix.environment }}-deploy', 'cancel-in-progress': false, }, needs: [ 'release_github', ], permissions: { contents: workflows_model_1.JobPermission.READ, deployments: workflows_model_1.JobPermission.WRITE, idToken: this.props.authProvider === javascript_1.CodeArtifactAuthProvider.GITHUB_OIDC ? workflows_model_1.JobPermission.WRITE : undefined, }, strategy: { maxParallel: 1, matrix: { domain: { environment: include.map(e => e.environment), }, include, }, }, environment: { name: '${{ matrix.environment }}', }, env: deployJobEnv, steps: [], }; jobDefinition.steps.push(this.checkoutStep); const preInstallDependenciesStep = this.preInstallDependenciesStep; if (preInstallDependenciesStep) { jobDefinition.steps.push(preInstallDependenciesStep); } jobDefinition.steps.push(...(this.project).renderWorkflowSetup()); const checkActiveDeploymentStepForMatrix = this.checkActiveDeploymentStepForMatrix; if (checkActiveDeploymentStepForMatrix) { jobDefinition.steps.push(checkActiveDeploymentStepForMatrix); } jobDefinition.steps.push(...this.setupAwsCredentialsStepsForMatrix); const setupNpmConfigStep = this.setupNpmConfigForMatrix; if (setupNpmConfigStep) { jobDefinition.steps.push(setupNpmConfigStep); } jobDefinition.steps.push(this.preDeploymentStepForMatrix); jobDefinition.steps.push(this.deploymentStep); jobDefinition.steps.push(this.postDeploymentStepForMatrix); return { deploy: jobDefinition }; } /** * Get the IDs of the jobs that must be completed before the specified environment's deployment job * @param environmentName The name of the environment * @returns An array of job IDs */ getDeploymentJobPrerequisiteJobIds(environmentName) { const result = []; if (!this.props.environmentDependencies) { const index = this.props.deployOptions.environments.findIndex(env => env.name === environmentName); const prerequisiteEnvironment = index > 0 ? this.props.deployOptions.environments[index - 1] : undefined; if (prerequisiteEnvironment) { result.push(getDeployJobId(prerequisiteEnvironment.name)); } } else { const dependencies = this.props.environmentDependencies[environmentName]; if (dependencies) { dependencies.forEach(dep => { result.push(getDeployJobId(dep)); }); } } if (result.length === 0) { result.push('release_github'); } return result; } /** * Get deployment jobs for multi-job strategy * @returns Record of jobs */ get deploymentJobsForMultiJob() { const { environmentVariableName, environments } = this.props.deployOptions; const jobs = environments.map((environmentOptions) => { return [getDeployJobId(environmentOptions.name), this.getJobForEnvironment(environmentOptions, environmentVariableName)]; }); return Object.fromEntries(jobs); } /** * Get the job definition for a specific environment * @param environmentOptions The environment options * @param environmentVariableName The name of the environment variable to set with the environment name, if any * @returns The job definition for the environment */ getJobForEnvironment(environmentOptions, environmentVariableName) { const { name } = environmentOptions; const deployJobEnv = environmentVariableName ? { [environmentVariableName]: name, } : undefined; const jobDefinition = { runsOn: ['ubuntu-latest'], concurrency: { 'group': `${name}-deploy`, 'cancel-in-progress': false, }, needs: this.getDeploymentJobPrerequisiteJobIds(name), permissions: { contents: workflows_model_1.JobPermission.READ, deployments: workflows_model_1.JobPermission.WRITE, idToken: this.props.authProvider === javascript_1.CodeArtifactAuthProvider.GITHUB_OIDC ? workflows_model_1.JobPermission.WRITE : undefined, }, environment: { name: name, }, env: deployJobEnv, steps: [], }; jobDefinition.steps.push(this.checkoutStep); const preInstallDependenciesStep = this.preInstallDependenciesStep; if (preInstallDependenciesStep) { jobDefinition.steps.push(preInstallDependenciesStep); } jobDefinition.steps.push(...(this.project).renderWorkflowSetup()); const checkActiveDeploymentStep = this.getCheckActiveDeploymentStepForEnvironment(name); if (checkActiveDeploymentStep) { jobDefinition.steps.push(checkActiveDeploymentStep); } jobDefinition.steps.push(...this.getSetupAwsCredentialsStepsForEnvironment(environmentOptions)); const setupNpmConfigStep = this.getSetupNpmConfigForEnvironment(name); if (setupNpmConfigStep) { jobDefinition.steps.push(setupNpmConfigStep); } const preDeploymentStep = this.getPreDeploymentStepForEnvironment(environmentOptions.preDeployWorkflowScript ? true : false, environmentOptions.preDeployWorkflowScript || ''); if (preDeploymentStep) { jobDefinition.steps.push(preDeploymentStep); } jobDefinition.steps.push(this.deploymentStep); const postDeploymentStep = this.getPostDeploymentStepForEnvironment(environmentOptions.postDeployWorkflowScript ? true : false, environmentOptions.postDeployWorkflowScript || ''); if (postDeploymentStep) { jobDefinition.steps.push(postDeploymentStep); } return jobDefinition; } /** * Step to generate the diff output * @returns JobStep */ get generateDiffStep() { return this.getRunScriptStep('diff:output', 'Generate Diff Output', true); } /** * Get the job to annotate the PR with the diff output for all environments * @param dependentJobNames The names of the jobs that the annotation job depends on * @returns The job definition for annotating the PR with the diff output */ getAnnotateDiffJob(dependentJobNames) { return { runsOn: ['ubuntu-latest'], needs: dependentJobNames, permissions: { contents: workflows_model_1.JobPermission.READ, pullRequests: workflows_model_1.JobPermission.WRITE, }, steps: [ projen_1.github.WorkflowSteps.downloadArtifact({ name: 'Download all diff artifacts', with: { pattern: 'diff-output-*', path: 'diff-outputs', mergeMultiple: true, }, }), { name: 'Annotate PR with Diff Output', uses: 'mshick/add-pr-comment@v3', with: { 'message-id': 'diff-output', 'refresh-message-position': true, 'message-path': 'diff-outputs/*.md', }, }, ], }; } /** * Get the step to format the diff output into a GitHub annotation comment for a specific environment * @param environment The environment to format the diff for * @returns JobStep */ getFormattedDiffAnnotationCommentStepForEnvironment(environment) { return { name: 'Get formatted diff annotation comment', id: formattedDiffAnnotationCommentStepId, run: [ 'mkdir -p diff-output', `echo "### Changes for environment ${environment}" > diff-output/diff-${environment}.md`, 'echo "" >> diff-output/diff-${environment}.md', 'echo "<details>" >> diff-output/diff-${environment}.md', 'echo "<summary>Show diff</summary>" >> diff-output/diff-${environment}.md', 'echo "" >> diff-output/diff-${environment}.md', "echo '\`\`\`' >> diff-output/diff-${environment}.md", 'for file in $(find . -path "**/cdk.out/diff.log" 2>/dev/null); do', ' echo "========== $file ==========" >> diff-output/diff-${environment}.md', ' sed \'s/\\x1B\\[[0-9;]*[mGKHF]//g\' "$file" >> diff-output/diff-${environment}.md', ' echo "" >> diff-output/diff-${environment}.md', 'done', "echo '\`\`\`' >> diff-output/diff-${environment}.md", 'echo "</details>" >> diff-output/diff-${environment}.md', 'echo "" >> diff-output/diff-${environment}.md', ].join('\n'), env: { environment: environment, }, }; } /** * Get the deployment method argument for the deploy command * @param environmentOptions The environment options * @param environmentVariableName The name of the environment variable to set with the environment name, if any * @returns The diff annotation job for the environment */ getDiffAnnotationJobForEnvironment(environmentOptions, environmentVariableName) { const { name } = environmentOptions; const deployJobEnv = environmentVariableName ? { [environmentVariableName]: name, } : undefined; const jobDefinition = { runsOn: ['ubuntu-latest'], needs: ['build'], permissions: { contents: workflows_model_1.JobPermission.READ, idToken: this.props.authProvider === javascript_1.CodeArtifactAuthProvider.GITHUB_OIDC ? workflows_model_1.JobPermission.WRITE : undefined, }, env: deployJobEnv, steps: [], }; jobDefinition.steps.push(this.checkoutStep); const preInstallDependenciesStep = this.preInstallDependenciesStep; if (preInstallDependenciesStep) { jobDefinition.steps.push(preInstallDependenciesStep); } jobDefinition.steps.push(...(this.project).renderWorkflowSetup()); jobDefinition.steps.push(...this.getSetupAwsCredentialsStepsForEnvironment(environmentOptions)); const setupNpmConfigStep = this.getSetupNpmConfigForEnvironment(name); if (setupNpmConfigStep) { jobDefinition.steps.push(setupNpmConfigStep); } jobDefinition.steps.push(this.generateDiffStep); jobDefinition.steps.push(this.getFormattedDiffAnnotationCommentStepForEnvironment(name)); // Upload the diff output as an artifact jobDefinition.steps.push(projen_1.github.WorkflowSteps.uploadArtifact({ name: 'Upload diff output', with: { name: `diff-output-${name}`, path: 'diff-output/', retentionDays: 1, }, })); return jobDefinition; } /** * Get diff annotation jobs for all environments * @returns Record of jobs */ get diffAnnotationJobs() { const { environmentVariableName, environments } = this.props.deployOptions; const jobEntries = environments.map((environmentOptions) => { return [getDiffAnnotationJobId(environmentOptions.name), this.getDiffAnnotationJobForEnvironment(environmentOptions, environmentVariableName)]; }); const jobs = Object.fromEntries(jobEntries); jobs['Diff-Annotation-Comment'] = this.getAnnotateDiffJob(Object.keys(jobs)); return jobs; } } exports.DeployableAwsCdkTypeScriptAppStepsFactory = DeployableAwsCdkTypeScriptAppStepsFactory; _a = JSII_RTTI_SYMBOL_1; DeployableAwsCdkTypeScriptAppStepsFactory[_a] = { fqn: "deployable-awscdk-app-ts.DeployableAwsCdkTypeScriptAppStepsFactory", version: "0.1.839" }; /** * Get the deploy job ID for a specific environment * @param environmentName The name of the environment * @returns The deploy job ID */ function getDeployJobId(environmentName) { return `Deploy-${environmentName}`; } /** * Get the diff annotation job ID for a specific environment * @param environmentName The name of the environment * @returns The diff annotation job ID */ function getDiffAnnotationJobId(environmentName) { return `Diff-Annotation-${environmentName}`; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3RlcHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQTQxQkEsd0NBRUM7QUFPRCx3REFFQzs7QUF2MkJELG1DQUE0QztBQUM1Qyw4Q0FBa0Q7QUFDbEQsdUVBQWdGO0FBQ2hGLHNEQUFpRTtBQUNqRSxtQ0FBa0g7QUFFbEgsTUFBTSwyQkFBMkIsR0FBRyxrQkFBa0IsQ0FBQztBQUN2RCxNQUFNLHNDQUFzQyxHQUFFLFNBQVMsMkJBQTJCLDBDQUEwQyxDQUFDO0FBQzdILE1BQU0sb0NBQW9DLEdBQUcsbUNBQW1DLENBQUM7QUF3Q2pGOzs7R0FHRztBQUNILE1BQWEseUNBQXlDO0lBRXBEOzs7O09BSUc7SUFDSSxNQUFNLENBQUMseUNBQXlDLENBQ3JELGFBQTRCLEVBQzVCLHVCQUEwRDtRQUcxRCxJQUFJLGFBQWEsQ0FBQyxXQUFXLEtBQUsseUJBQWlCLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDOUQsTUFBTSxJQUFJLEtBQUssQ0FBQywrRUFBK0UsQ0FBQyxDQUFDO1FBQ25HLENBQUM7UUFFRCxNQUFNLENBQUMsT0FBTyxDQUFDLHVCQUF1QixDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtZQUM5RCxNQUFNLGNBQWMsR0FBRyxhQUFhLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7WUFDNUUsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUNwQixNQUFNLElBQUksS0FBSyxDQUFDLGdCQUFnQixHQUFHLHdFQUF3RSxDQUFDLENBQUM7WUFDL0csQ0FBQztZQUNELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQ2pCLE1BQU0saUJBQWlCLEdBQUcsYUFBYSxDQUFDLFlBQVksQ0FBQyxJQUFJ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