Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
name: Node.js REST API CI/CD Pipeline

on:
push:
branches:
- main
- develop
paths:
- 'src/**'
- 'package.json'
- 'package-lock.json'
- 'Dockerfile'
- '.github/workflows/**'
- 'terraform/**'
pull_request:
branches:
- main
- develop
workflow_dispatch:

permissions:
id-token: write
contents: read

env:
AWS_REGION: us-east-1
ECR_REGISTRY_ALIAS: registry-alias
ECS_CLUSTER_NAME: production-cluster
ECS_SERVICE_NAME: nodejs-api-service
ECS_TASK_FAMILY: nodejs-api-task

jobs:
lint-and-test:
runs-on: ubuntu-22.04
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1

- name: Setup Node.js
uses: actions/setup-node@v4.0.1
with:
node-version: ${{ matrix.node-version }}
cache: npm

- name: Install dependencies
run: npm ci

- name: Run linter
run: npm run lint --if-present

- name: Run tests
run: npm run test --if-present

- name: Generate coverage report
run: npm run coverage --if-present
continue-on-error: true

- name: Upload coverage to CodeCov
uses: codecov/codecov-action@v3.1.5
with:
files: ./coverage/lcov.info
flags: unittests
fail_ci_if_error: false

build-and-push:
needs: lint-and-test
runs-on: ubuntu-22.04
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
outputs:
image-uri: ${{ steps.image.outputs.uri }}
image-tag: ${{ steps.image.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
role-session-name: github-actions-session

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2.0.1
with:
registry-type: private

- name: Build image
id: docker-build
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build \
-t $ECR_REGISTRY/$ECS_TASK_FAMILY:$IMAGE_TAG \
-t $ECR_REGISTRY/$ECS_TASK_FAMILY:latest \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VCS_REF=${{ github.sha }} \
--build-arg VERSION=${{ github.ref_name }} \
.
echo "image_uri=$ECR_REGISTRY/$ECS_TASK_FAMILY:$IMAGE_TAG" >> $GITHUB_OUTPUT

- name: Push image to Amazon ECR
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker push $ECR_REGISTRY/$ECS_TASK_FAMILY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECS_TASK_FAMILY:latest
echo "Images pushed successfully"

- name: Set image output
id: image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
echo "uri=$ECR_REGISTRY/$ECS_TASK_FAMILY:$IMAGE_TAG" >> $GITHUB_OUTPUT
echo "tag=$IMAGE_TAG" >> $GITHUB_OUTPUT

terraform-plan:
runs-on: ubuntu-22.04
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
role-session-name: github-actions-session

- name: Setup Terraform
uses: hashicorp/setup-terraform@v2.1.0
with:
terraform_version: 1.6.0

- name: Terraform format check
working-directory: ./terraform
run: terraform fmt -check -recursive

- name: Terraform init
working-directory: ./terraform
run: terraform init -backend=false

- name: Terraform validate
working-directory: ./terraform
run: terraform validate

- name: Terraform plan
working-directory: ./terraform
run: terraform plan -no-color
continue-on-error: true

terraform-apply:
needs: build-and-push
runs-on: ubuntu-22.04
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
role-session-name: github-actions-session

- name: Setup Terraform
uses: hashicorp/setup-terraform@v2.1.0
with:
terraform_version: 1.6.0

- name: Terraform init
working-directory: ./terraform
run: terraform init

- name: Terraform plan
working-directory: ./terraform
run: terraform plan -out=tfplan

- name: Terraform apply
working-directory: ./terraform
run: terraform apply -auto-approve tfplan

deploy-to-ecs:
needs: [build-and-push, terraform-apply]
runs-on: ubuntu-22.04
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
role-session-name: github-actions-session

- name: Get task definition
run: |
aws ecs describe-task-definition \
--task-definition ${{ env.ECS_TASK_FAMILY }} \
--query taskDefinition > task-definition.json

- name: Update task definition with new image
id: task-def
uses: aws-actions/render-task-definition@v1.1.3
with:
task-definition: task-definition.json
container-name: ${{ env.ECS_TASK_FAMILY }}
image: ${{ needs.build-and-push.outputs.image-uri }}

- name: Register new task definition
run: |
aws ecs register-task-definition \
--cli-
Loading