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
194 changes: 194 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
name: CI/CD Pipeline - Node.js API to AWS ECS

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

env:
AWS_REGION: us-east-1
ECR_REPOSITORY: node-api
ECS_SERVICE: node-api-service
ECS_CLUSTER: node-api-cluster

permissions:
id-token: write
contents: read

jobs:
lint:
name: Lint Code
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f69735febad081b8f525ce356e475d86 # v4.1.1

- name: Setup Node.js
uses: actions/setup-node@60edb5dd545a775178fbb3563ff8483803168bc5 # v4.0.2
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

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

test:
name: Run Tests
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f69735febad081b8f525ce356e475d86 # v4.1.1

- name: Setup Node.js
uses: actions/setup-node@60edb5dd545a775178fbb3563ff8483803168bc5 # v4.0.2
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test

- name: Upload coverage
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f64a43ec8d490d8de9 # v3.1.4
if: always()

build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-22.04
needs: [lint, test]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
outputs:
image-tag: ${{ steps.image.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f69735febad081b8f525ce356e475d86 # v4.1.1

- name: Configure AWS credentials with OIDC
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
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@062b18b96a7aabf0d32092427e2b915fcc71c7de # v2.0.1

- name: Build and tag image
id: image
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
COMMIT_SHA: ${{ github.sha }}
BRANCH_NAME: ${{ github.ref_name }}
run: |
IMAGE_TAG="${BRANCH_NAME}-${COMMIT_SHA::8}"
docker build -t $REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker tag $REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $REGISTRY/$ECR_REPOSITORY:latest
echo "tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
echo "registry=$REGISTRY" >> $GITHUB_OUTPUT

- name: Push image to ECR
env:
REGISTRY: ${{ steps.image.outputs.registry }}
IMAGE_TAG: ${{ steps.image.outputs.tag }}
run: |
docker push $REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $REGISTRY/$ECR_REPOSITORY:latest

terraform-plan:
name: Terraform Plan
runs-on: ubuntu-22.04
needs: [build-and-push]
if: github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f69735febad081b8f525ce356e475d86 # v4.1.1

- name: Configure AWS credentials with OIDC
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
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@3523b56c0e4a3f2d19eff39fe629ab42f7c5e2e4 # v2.4.0

- name: Terraform Init
working-directory: terraform
run: terraform init

- name: Terraform Format Check
working-directory: terraform
run: terraform fmt -check

- name: Terraform Validate
working-directory: terraform
run: terraform validate

- name: Terraform Plan
working-directory: terraform
env:
TF_VAR_image_tag: ${{ needs.build-and-push.outputs.image-tag }}
run: terraform plan -out=tfplan

- name: Upload Terraform Plan
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5d # v4.3.1
with:
name: tfplan
path: terraform/tfplan

deploy:
name: Deploy to AWS ECS
runs-on: ubuntu-22.04
needs: [build-and-push, terraform-plan]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment:
name: production
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f69735febad081b8f525ce356e475d86 # v4.1.1

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

- name: Download Terraform Plan
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.1
with:
name: tfplan
path: terraform

- name: Setup Terraform
uses: hashicorp/setup-terraform@3523b56c0e4a3f2d19eff39fe629ab42f7c5e2e4 # v2.4.0

- name: Terraform Init
working-directory: terraform
run: terraform init

- name: Terraform Apply
working-directory: terraform
env:
TF_VAR_image_tag: ${{ needs.build-and-push.outputs.image-tag }}
run: terraform apply -auto-approve tfplan

- name: Update ECS Service
run: |
aws ecs update-service \
--cluster $ECS_CLUSTER \
--service $ECS_SERVICE \
--force-new-deployment \
Loading