---
AWSTemplateFormatVersion: 2010-09-09

Description: ServerlessSinatra
Parameters:
  GitSourceRepo:
    Type: String
    Description: GitHub source repository
    Default: serverless-sinatra-sample
    MinLength: 1
    MaxLength: 100
    ConstraintDescription: You must enter a GitHub repository name
  GitBranch:
    Type: String
    Default: master
    Description: GitHub git repository branch - change triggers a new build
    MinLength: 1
    MaxLength: 100
    ConstraintDescription: You must enter a GitHub repository branch name
  GitHubToken:
    Type: String
    NoEcho: true
    Description: GitHub API token - see https://github.com/blog/1509-personal-api-tokens
    MinLength: 3
    MaxLength: 100
    ConstraintDescription: You must enter a GitHub personal access token
  GitHubUser:
    Type: String
    Description: GitHub username or organization
    MinLength: 3
    MaxLength: 100
    ConstraintDescription: You must enter a GitHub username or organization
  CodeBuildImage:
    Type: String
    Default: aws/codebuild/ruby:2.5.3
    Description: Default AWS CodeBuild Ruby 2.5.3 image
    MinLength: 3
    MaxLength: 100
    ConstraintDescription: You must enter a CodeBuild image
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: GitHub
        Parameters:
          - GitHubUser
          - GitHubToken
          - GitSourceRepo
          - GitBranch
      - Label:
          default: CodeBuild
        Parameters:
          - CodeBuildImage
    ParameterLabels:
      GitHubUser:
        default: Username
      GitHubToken:
        default: Access token
      GitSourceRepo:
        default: Repository
      GitBranch:
        default: Branch
      CodeBuildImage:
        default: CodeBuild image

Resources:
  CodePipelineArtifactBucket:
    Description: Creating Amazon S3 bucket for AWS CodePipeline artifacts
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "serverless-sinatra-${AWS::AccountId}-${AWS::Region}"
      VersioningConfiguration:
        Status: Enabled
  S3ArtifactBucketPolicy:
    DependsOn: [CodePipelineArtifactBucket]
    Description: Setting Amazon S3 bucket policy for AWS CodePipeline access
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref CodePipelineArtifactBucket
      PolicyDocument:
        Version: "2012-10-17"
        Id: SSEAndSSLPolicy
        Statement:
        - Sid: DenyInsecureConnections
          Effect: Deny
          Principal: "*"
          Action: s3:*
          Resource: !Sub "arn:aws:s3:::${CodePipelineArtifactBucket}/*"
          Condition:
            Bool:
              aws:SecureTransport: false
  CodePipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: codepipeline.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: codepipeline-access
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Resource: "*"
                Effect: Allow
                Action:
                  - codebuild:StartBuild
                  - codebuild:BatchGetBuilds
                  - codecommit:GetBranch
                  - codecommit:GetCommit
                  - codecommit:UploadArchive
                  - codecommit:GetUploadArchiveStatus
                  - codecommit:CancelUploadArchive
                  - cloudformation:CreateStack
                  - cloudformation:DeleteStack
                  - cloudformation:DescribeStacks
                  - cloudformation:UpdateStack
                  - cloudformation:CreateChangeSet
                  - cloudformation:DeleteChangeSet
                  - cloudformation:DescribeChangeSet
                  - cloudformation:ExecuteChangeSet
                  - cloudformation:SetStackPolicy
                  - cloudformation:ValidateTemplate
                  - iam:PassRole
              - Resource: !Sub arn:aws:s3:::${CodePipelineArtifactBucket}/*
                Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketVersioning
    DependsOn: CodePipelineArtifactBucket
  CFNRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: cfn-access
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Resource: '*'
                Effect: Allow
                Action:
                  - 'cloudformation:*'
                  - 'dynamodb:*'
                  - 'iam:*'
                  - 'lambda:*'
                  - 'apigateway:*'
                  - 's3:*'
  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: codebuild-access
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Resource: '*'
                Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
              - Resource: !Sub arn:aws:s3:::${CodePipelineArtifactBucket}/*
                Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:GetObjectVersion
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: codepipeline
      Source:
        Type: codepipeline
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Type: LINUX_CONTAINER
        Image: !Ref CodeBuildImage
        EnvironmentVariables:
          - Name: REPOSITORY_NAME
            Value: !Ref GitSourceRepo
          - Name: REPOSITORY_BRANCH
            Value: !Ref GitBranch
          - Name: S3_BUCKET
            Value: !Ref CodePipelineArtifactBucket
      Name: !Ref AWS::StackName
      ServiceRole: !GetAtt CodeBuildServiceRole.Arn

  CodePipelineGitHub:
    DependsOn: [CodePipelineArtifactBucket, CodeBuildProject, CFNRole]
    Description: Creating a deployment pipeline for your project in AWS CodePipeline
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn: !GetAtt CodePipelineServiceRole.Arn
      ArtifactStore:
        Type: S3
        Location: !Ref CodePipelineArtifactBucket
      Stages:
        - Name: Source
          Actions:
            - Name: App
              ActionTypeId:
                Category: Source
                Owner: ThirdParty
                Version: 1
                Provider: GitHub
              Configuration:
                Owner: !Ref GitHubUser
                Repo: !Ref GitSourceRepo
                Branch: !Ref GitBranch
                OAuthToken: !Ref GitHubToken
              OutputArtifacts:
                - Name: App
              RunOrder: 1
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              Configuration:
                ProjectName: !Ref CodeBuildProject
              InputArtifacts:
                - Name: App
              OutputArtifacts:
                - Name: BuildOutput
              RunOrder: 1
        - Name: Deploy
          Actions:
          - Name: create-changeset
            InputArtifacts:
            - Name: BuildOutput
            ActionTypeId:
              Category: Deploy
              Owner: AWS
              Version: "1"
              Provider: CloudFormation
            OutputArtifacts: []
            Configuration:
              StackName: "serverless-sinatra-stack"
              ActionMode: CHANGE_SET_REPLACE
              RoleArn: !GetAtt CFNRole.Arn
              ChangeSetName: pipeline-changeset
              Capabilities: CAPABILITY_NAMED_IAM
              TemplatePath: !Sub "BuildOutput::template-export.yaml"
            RunOrder: 1
          - Name: execute-changeset
            InputArtifacts: []
            ActionTypeId:
              Category: Deploy
              Owner: AWS
              Version: "1"
              Provider: CloudFormation
            OutputArtifacts: []
            Configuration:
              StackName: "serverless-sinatra-stack"
              ActionMode: CHANGE_SET_EXECUTE
              ChangeSetName: pipeline-changeset
            RunOrder: 2