Parameters:
  GitHubRepo:
    Type: String
  GitHubBranch:
    Type: String
  GitHubUser:
    Type: String
  EnvironmentName:
    Type: String
    Default: production
  ServiceName:
    Type: String
    Description: The name of the service
    AllowedValues: [server, cache, database]
  TriggerPattern:
    Type: String
    Description: A commit message that triggers the build process
    Default: \[BuildAll\]
  ArtifactBucket:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /Microservices/ArtifactBucket
  CodePipelineServiceRoleArn:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /Microservices/CodePipelineServiceRoleArn

Resources:

  #-----------------------------------------------------------------------------#
  # ECR
  #-----------------------------------------------------------------------------#
  Repository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Sub ${EnvironmentName}/${ServiceName}

  #-----------------------------------------------------------------------------#
  # CodeBuild Project
  #-----------------------------------------------------------------------------#
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub ${EnvironmentName}-${ServiceName}
      Artifacts:
        Type: S3
        Location: !Ref ArtifactBucket
        Path: imagedefinitions
        Name: !Sub ${ServiceName}.zip
        Packaging: ZIP
        EncryptionDisabled: true
      Source:
        Type: GITHUB
        Location: !Sub https://github.com/${GitHubUser}/${GitHubRepo}.git
        BuildSpec: deployments/buildspec/service.yml
      SourceVersion: !Ref GitHubBranch
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:5.0
        Type: LINUX_CONTAINER
        PrivilegedMode: true
        EnvironmentVariables:
          - Name: AWS_ACCOUNT_ID
            Value: !Sub ${AWS::AccountId}
          - Name: SERVICE
            Value: !Ref ServiceName
          - Name: REPO_URI
            Value: !Sub ${Repository.RepositoryUri}
      Triggers:
        Webhook: true
        FilterGroups:
        - - Type: EVENT
            Pattern: PUSH
            ExcludeMatchedPattern: false
          - Type: HEAD_REF
            Pattern: !Sub ^refs/heads/${GitHubBranch}$
            ExcludeMatchedPattern: false
          - Type: COMMIT_MESSAGE
            Pattern: !Ref TriggerPattern
            ExcludeMatchedPattern: false
      ServiceRole: !Ref CodeBuildServiceRole
      TimeoutInMinutes: 10

  #-----------------------------------------------------------------------------#
  # CodePipeline
  #-----------------------------------------------------------------------------#
  CloudWatchEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        detail-type: [CodeBuild Build State Change]
        source: [aws.codebuild]
        detail:
          build-status: [SUCCEEDED]
          project-name: [!Ref CodeBuildProject]
      Targets:
        - Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
          RoleArn: !GetAtt CloudWatchEventRole.Arn
          Id: !Sub ${ServiceName}-pipeline

  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub ${EnvironmentName}-${ServiceName}
      RoleArn: !Ref CodePipelineServiceRoleArn
      ArtifactStore:
        Type: S3
        Location: !Ref ArtifactBucket
      Stages:

        #-----------------------------------------------------------------------------#
        # Source
        #-----------------------------------------------------------------------------#
        - Name: Source
          Actions:
            - Name: Image
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: S3
              Configuration:
                S3Bucket: !Ref ArtifactBucket
                S3ObjectKey: !Sub imagedefinitions/${ServiceName}.zip
                PollForSourceChanges: false
              OutputArtifacts:
                - Name: Image
              RunOrder: 1

        #-----------------------------------------------------------------------------#
        # Deploy
        #-----------------------------------------------------------------------------#
        - Name: Deploy
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: ECS
              Configuration:
                ClusterName:
                  Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
                ServiceName: !Ref ServiceName
                FileName: imagedefinitions.json
              InputArtifacts:
                - Name: Image

  #-----------------------------------------------------------------------------#
  # Role for CodeBuild service
  #-----------------------------------------------------------------------------#
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Resource: "*"
                Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                  - ecr:GetAuthorizationToken
              - Resource: !Sub arn:aws:s3:::${ArtifactBucket}*
                Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:GetObjectVersion
              - Resource: !GetAtt Repository.Arn
                Effect: Allow
                Action:
                  - ecr:GetDownloadUrlForLayer
                  - ecr:BatchGetImage
                  - ecr:BatchCheckLayerAvailability
                  - ecr:PutImage
                  - ecr:InitiateLayerUpload
                  - ecr:UploadLayerPart
                  - ecr:CompleteLayerUpload

  #-----------------------------------------------------------------------------#
  # Role for CloudWatch service
  #-----------------------------------------------------------------------------#
  CloudWatchEventRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: cwe-pipeline-execution
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: codepipeline:StartPipelineExecution
                Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}

Outputs:
  PipelineUrl:
    Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
