diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..6800d3c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,66 @@ +name: Intelligent Code Review +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +jobs: + review: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: write + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install dependencies @actions/core and @actions/github + run: | + npm install @actions/core + npm install @actions/github + shell: bash + + - name: Check if required dependencies are installed + run: | + npm list @actions/core + npm list @actions/github + shell: bash + + - name: Debug GitHub Token + run: | + if [ -n "${{ secrets.GITHUB_TOKEN }}" ]; then + echo "GitHub Token is set" + else + echo "GitHub Token is not set" + fi + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: us-east-1 + + - name: Intelligent GitHub Actions + uses: aws-sample/aws-genai-cicd-suite@stable + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + aws-region: us-east-1 + model-id: anthropic.claude-3-sonnet-20240229-v1:0 + generate-code-review: 'true' + generate-code-review-level: 'detailed' + generate-code-review-exclude-files: '*.md,*.json' + generate-pr-description: 'true' + generate-unit-test: 'true' + generate-unit-test-source-folder: 'src' + output-language: 'en' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/backend.yml b/backend.yml index 2413336..b5c0a8c 100644 --- a/backend.yml +++ b/backend.yml @@ -1,17 +1,16 @@ AWSTemplateFormatVersion: "2010-09-09" -Description: CloudFormation template for Hotel App with DynamoDB and App Runner, without networking. +Description: CloudFormation template for Hotel app with DynamoDB and App Runner, without networking. Parameters: HotelName: Type: String Default: AWS App Runner Hotel - Description: Enter a name for the Hotel. Default is AWS App Runner Hotel. + Description: Enter a name for the Hotel. Default is AWS AppRunner Hotel. Environment: Type: String Default: dev Description: Enter a name for the Environment. Default is dev, this is used later in the workshop to tag the environments - Resources: # DynamoDB Table for Rooms RoomsTable: @@ -29,8 +28,11 @@ Resources: WriteCapacityUnits: 5 SSESpecification: SSEEnabled: true # Enable server-side encryption for the table + Tags: + - Key: "Project" + Value: !Sub "HotelApp-${Environment}" - # IAM Role for App Runner to access DynamoDB + # IAM Role for AppRunner to access DynamoDB AppRunnerInstanceRole: Type: AWS::IAM::Role Properties: @@ -88,25 +90,39 @@ Resources: - "sts:AssumeRole" ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess" - - #Sample Alarm - we will use this later to prove AWS CodePipeline Condition Gates - DynamoDBReadCapacityAlarm: - Type: "AWS::CloudWatch::Alarm" + + AppRunnerService: + Type: AWS::AppRunner::Service Properties: - AlarmName: !Sub "HighReadCapacityAlarm-${AWS::StackName}-${AWS::Region}" - AlarmDescription: "Alarm if DynamoDB read capacity exceeds 80% of provisioned units" - Namespace: "AWS/DynamoDB" - MetricName: "ConsumedReadCapacityUnits" - Dimensions: - - Name: "TableName" - Value: !Ref RoomsTable - Statistic: "Average" - Period: 60 - EvaluationPeriods: 1 - Threshold: 4 # 80% of 5 ReadCapacityUnits - ComparisonOperator: "GreaterThanThreshold" + ServiceName: !Sub "Hotel-${AWS::StackName}-${AWS::Region}" + SourceConfiguration: + AutoDeploymentsEnabled: false + ImageRepository: + ImageIdentifier: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/hotel-app:latest + ImageRepositoryType: ECR + ImageConfiguration: + Port: "8080" + RuntimeEnvironmentVariables: + - Name: DYNAMODB_TABLE_NAME + Value: !Ref RoomsTable + - Name: HOTEL_NAME + Value: !Sub ${HotelName}-${Environment}-2 + AuthenticationConfiguration: + AccessRoleArn: !GetAtt AppRunnerECRAccessRole.Arn + InstanceConfiguration: + InstanceRoleArn: !GetAtt AppRunnerInstanceRole.Arn + AppRunnerURLSSMParameter: + Type: "AWS::SSM::Parameter" + Properties: + Name: !Sub "/hotelapp/${Environment}/url" + Description: "Hotel app URI" + Type: "String" + Value: !Sub "https://${AppRunnerService.ServiceUrl}" Outputs: DynamoDBTableName: Description: "Name of the DynamoDB Table" Value: !Ref RoomsTable + AppRunnerServiceUrl: + Description: "URL of the AppRunner Service" + Value: !GetAtt AppRunnerService.ServiceUrl \ No newline at end of file diff --git a/buildspec_backend.yml b/buildspec_backend.yml new file mode 100644 index 0000000..2f0f25e --- /dev/null +++ b/buildspec_backend.yml @@ -0,0 +1,24 @@ +version: 0.2 + +phases: + pre_build: + commands: + - aws cloudformation validate-template --template-body file://backend.yml + + build: + commands: + - | + if [[ "$BRANCH_NAME" == main* ]]; then + DEPLOY_ENV="stage"; + elif [[ "$BRANCH_NAME" == feature* ]]; then + DEPLOY_ENV="dev"; + else + echo "Error: BRANCH_NAME must start with 'main' or 'feature'." + exit 1; + fi + - aws cloudformation deploy --template-file backend.yml --stack-name BaseInfraStack-$DEPLOY_ENV --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM --parameter-overrides Environment=$DEPLOY_ENV --no-fail-on-empty-changeset + - aws cloudformation wait stack-create-complete --stack-name BaseInfraStack-$DEPLOY_ENV + + post_build: + commands: + - aws cloudformation describe-stacks --stack-name BaseInfraStack-$DEPLOY_ENV \ No newline at end of file diff --git a/buildspec_docker.yml b/buildspec_docker.yml new file mode 100644 index 0000000..9a2f20c --- /dev/null +++ b/buildspec_docker.yml @@ -0,0 +1,36 @@ +version: 0.2 + +env: + variables: + IMAGE_TAG: "latest" # Default value for the tag. Can be overridden. + exported-variables: + - IMAGE_DIGEST + - IMAGE_IDENTIFIER + +phases: + install: + commands: + - npm install + + pre_build: + commands: + - echo "Extracting AWS Account ID from CODEBUILD_BUILD_ARN..." + - export ACCOUNT_ID=$(echo $CODEBUILD_BUILD_ARN | cut -f5 -d ':') + - export repository_name="hotel-app" # Set your repository name here + - echo "Logging into Amazon ECR..." + - aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com + + build: + commands: + - echo "Building the Docker image..." + - docker build -t $repository_name:$IMAGE_TAG . + - echo "Tagging the Docker image for ECR..." + - docker tag $repository_name:$IMAGE_TAG $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$repository_name:$IMAGE_TAG + - echo "Pushing the Docker image to ECR..." + - docker push $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$repository_name:$IMAGE_TAG + + post_build: + commands: + - echo "Retrieving the image digest from ECR..." + - IMAGE_DIGEST=$(aws ecr describe-images --repository-name $repository_name --image-ids imageTag=$IMAGE_TAG --query 'imageDetails[0].imageDigest' --output text) + - IMAGE_IDENTIFIER="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${repository_name}@${IMAGE_DIGEST}" \ No newline at end of file diff --git a/buildspec_unittests.yml b/buildspec_unittests.yml new file mode 100644 index 0000000..dbfbde6 --- /dev/null +++ b/buildspec_unittests.yml @@ -0,0 +1,19 @@ +version: 0.2 + +phases: + install: + commands: + - npm install + build: + commands: + - npx jest --ci --collectCoverage --reporters=jest-junit + +reports: + unittests: + files: + - junit.xml + file-format: JUNITXML + codecoverage: + files: + - 'coverage/cobertura-coverage.xml' + file-format: 'COBERTURAXML' \ No newline at end of file diff --git a/views/index.pug b/views/index.pug index 2b7e1b4..2485929 100644 --- a/views/index.pug +++ b/views/index.pug @@ -2,6 +2,6 @@ extends layout block content h1. - Welcome to #{menuTitle} + Welcome to #{menuTitle} - the best hotel on earth img(src='public/hotel_landing_pic.png' class='img-fluid' style='width:400px; height:400px;')