cdk-constructs icon indicating copy to clipboard operation
cdk-constructs copied to clipboard

codepipeline-slack usage with multiple pipelines in a single stack

Open ChristopheBougere opened this issue 4 years ago • 0 comments

Context

I'm following this tutorial to setup a CDK pipeline. As I want to follow a gitflow like workflow (develop deploying to Staging and main deploying to Prod), I am creating multiple CDK pipelines within a single CDK stack. And for each pipeline, I would like to setup a slack notifier and in some case a slack approval action. However when deploying, I am facing this error:

[Container] 2020/12/16 11:09:22 Running command npx cdk synth
Bundling asset MyProjectPipelineStack/Staging/MyStack/MyLambda/Code/Stage...
There is already a Construct with name 'SlackNotifierFunction' in MyProjectPipelineStack [MyProjectPipelineStack]
Subprocess exited with error 1

This is due to the fact that all the resources in @cloudcomponents/cdk-codepipeline-slack have static names, widh prevent from deploying multiple instances in the same stack, in this case SlackNotifierFunction.

My first thought was that we should add the construct ID to the resources it creates. However, that means it would create multiples lambda and API gateway endpoints, which would mean creating multiple slack apps (one for each endpoints) and wouldn't be convenient.

What is, in your opinion, the best way to allow deploying multiple pipelines with slack in a single stack?

Code of the pipeline stack

import * as codepipeline from '@aws-cdk/aws-codepipeline';
import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions';
import { Construct, SecretValue, Stack, StackProps } from '@aws-cdk/core';
import { CdkPipeline, SimpleSynthAction } from '@aws-cdk/pipelines';
import { SlackApprovalAction, SlackNotifier } from '@cloudcomponents/cdk-codepipeline-slack';
import { MyProjectStage } from './my-project-stage';

export class MyProjectPipelineStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    this.createPipeline('develop', 'Staging');
    this.createPipeline('main', 'Prod', true);
  }

  createPipeline(branch: string, stage: string, slack=false) {
    const sourceArtifact = new codepipeline.Artifact();
    const cloudAssemblyArtifact = new codepipeline.Artifact();
    const pipeline = new CdkPipeline(this, `${stage}-Pipeline`, {
      // The pipeline name
      pipelineName: `${stage}-MyProjectPipeline`,
      cloudAssemblyArtifact,

      // Where the source can be found
      sourceAction: new codepipeline_actions.GitHubSourceAction({
        actionName: 'GitHub',
        output: sourceArtifact,
        oauthToken: SecretValue.secretsManager('github-token'),
        owner: '<GITHUB_OWNER>',
        repo: '<GITHUB_REPO>',
        branch,
      }),

      // How it will be built and synthesized
      synthAction: SimpleSynthAction.standardNpmSynth({
        sourceArtifact,
        cloudAssemblyArtifact,

        // We need a build step to compile the TypeScript Lambda
        buildCommand: 'npm run build',
      }),
    });

    const slackBotToken = SecretValue.secretsManager('slack-bot-token').toString();
    const slackSigningSecret = SecretValue.secretsManager('slack-signing-secret').toString();
    const slackChannel = 'notifications-aws';

    const applicationStage = pipeline.addApplicationStage(new MyProjectStage(this, stage, {
      env: { account: '<AWS_ACCOUNT_ID>', region: '<AWS_REGION>' },
    }));
    if (slack) {
      applicationStage.addActions(new SlackApprovalAction({
        actionName: `${stage}-SlackApproval`,
        slackBotToken,
        slackSigningSecret,
        slackChannel,
        // externalEntityLink: 'http://cloudcomponents.org',
        additionalInformation: `Would you like to promote the build to ${stage}?`,
      }));
      new SlackNotifier(this, `${stage}-SlackNotifier`, {
        pipeline: pipeline.codePipeline,
        slackBotToken,
        slackSigningSecret,
        slackChannel,
      });
    }

    return pipeline;
  }
}

ChristopheBougere avatar Dec 16 '20 13:12 ChristopheBougere