From 60efdb6a29428099dc3e2607ce7e9b4dfe653cc3 Mon Sep 17 00:00:00 2001 From: Mohan Veerachamy <76078705+mohanranjith@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:13:36 -0500 Subject: [PATCH] ci: add CI/CD pipeline via OpsTools --- .github/workflows/ci-cd.yml | 225 ++++++++++++++++++++++++++++++++++++ 1 file changed, 225 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..dd6e3c5 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -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- \ No newline at end of file