From 8f8f4e878075250161032bf8bd38308964fb4593 Mon Sep 17 00:00:00 2001 From: Mohan Veerachamy <76078705+mohanranjith@users.noreply.github.com> Date: Wed, 18 Mar 2026 21:17:17 -0500 Subject: [PATCH] ci: add CI/CD pipeline via OpsTools --- .github/workflows/ci-cd.yml | 194 ++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 .github/workflows/ci-cd.yml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000..359b6c0 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -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 \ \ No newline at end of file