🚀 Add CI/CD pipeline (via OpsTools) #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Node.js API CI/CD Pipeline | |
| 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: production | |
| permissions: | |
| contents: read | |
| id-token: write | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@60edb5dd545a775178fac7f3f667f4173c5c7605 | |
| with: | |
| node-version: '18.18.0' | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run ESLint | |
| run: npm run lint --if-present | |
| test: | |
| runs-on: ubuntu-22.04 | |
| needs: lint | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@60edb5dd545a775178fac7f3f667f4173c5c7605 | |
| with: | |
| node-version: '18.18.0' | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run tests | |
| run: npm test --if-present | |
| - name: Generate coverage report | |
| run: npm run test:coverage --if-present | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v3.1.4 | |
| with: | |
| files: ./coverage/coverage-final.json | |
| flags: unittests | |
| fail_ci_if_error: false | |
| build: | |
| runs-on: ubuntu-22.04 | |
| needs: test | |
| if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') | |
| outputs: | |
| image_uri: ${{ steps.image.outputs.uri }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9 | |
| - 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-duration-seconds: 900 | |
| - name: Login to Amazon ECR | |
| id: login-ecr | |
| uses: aws-actions/amazon-ecr-login@v2.0.1 | |
| - name: Build Docker image | |
| id: docker_build | |
| uses: docker/build-push-action@v5.1.0 | |
| with: | |
| context: . | |
| push: false | |
| tags: | | |
| ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }} | |
| ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest | |
| cache-from: type=registry,ref=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:buildcache | |
| cache-to: type=registry,ref=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:buildcache,mode=max | |
| outputs: type=docker,dest=/tmp/image.tar | |
| - name: Push Docker image to ECR | |
| run: | | |
| docker load --input /tmp/image.tar | |
| docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }} | |
| docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest | |
| - name: Output image URI | |
| id: image | |
| run: echo "uri=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}" >> $GITHUB_OUTPUT | |
| validate-terraform: | |
| runs-on: ubuntu-22.04 | |
| needs: test | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9 | |
| - name: Setup Terraform | |
| uses: hashicorp/setup-terraform@v2.1.0 | |
| with: | |
| terraform_version: 1.6.0 | |
| - name: Terraform Format Check | |
| run: terraform fmt -check -recursive ./terraform | |
| - name: Terraform Init | |
| run: cd terraform && terraform init -backend=false | |
| - name: Terraform Validate | |
| run: cd terraform && terraform validate | |
| - name: TFLint | |
| uses: terraform-linters/setup-tflint@v4.0.0 | |
| with: | |
| tflint_version: v0.48.0 | |
| - name: Run TFLint | |
| run: cd terraform && tflint --init && tflint | |
| deploy-to-ecs: | |
| runs-on: ubuntu-22.04 | |
| needs: [build, validate-terraform] | |
| if: github.ref == 'refs/heads/main' | |
| environment: production | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9 | |
| - 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-duration-seconds: 1800 | |
| - name: Setup Terraform | |
| uses: hashicorp/setup-terraform@v2.1.0 | |
| with: | |
| terraform_version: 1.6.0 | |
| - name: Terraform Init | |
| run: cd terraform && terraform init | |
| - name: Terraform Plan | |
| run: cd terraform && terraform plan -var="image_tag=${{ needs.build.outputs.image_uri }}" -out=tfplan | |
| - name: Terraform Apply | |
| if: github.ref == 'refs/heads/main' | |
| run: cd terraform && terraform apply -auto-approve tfplan | |
| - name: Update ECS service | |
| run: | | |
| aws ecs update-service \ | |
| --cluster ${{ env.ECS_CLUSTER }} \ | |
| --service ${{ env.ECS_SERVICE }} \ | |
| --force-new-deployment \ | |
| --region ${{ env.AWS_REGION }} | |
| - name: Wait for ECS service update | |
| run: | | |
| aws ecs wait services-stable \ | |
| --cluster ${{ env.ECS_CLUSTER }} \ | |
| --services ${{ env.ECS_SERVICE }} \ | |
| --region ${{ env.AWS_REGION }} | |
| notify: | |
| runs-on: ubuntu-22.04 | |
| needs: [lint, test, build, validate-terraform, deploy-to-ecs] | |
| if: always() | |
| steps: | |
| - name: Slack notification on failure | |
| if: failure() | |
| uses: slackapi/slack-github-action@v1.24.0 | |
| with: | |
| webhook-url: ${{ secrets.SLACK_WEBHOOK }} | |
| payload: | | |
| { | |
| "text": "GitHub Action failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| } | |
| - name: Slack notification on success | |
| if: success() | |
| uses: slackapi/slack-github-action@v1.24.0 | |
| with: | |
| webhook-url: ${{ secrets.SLACK_WEBHOOK }} | |
| payload: | | |
| { | |
| "text": "GitHub Action succeeded: ${{ github.server_url }}/${{ github.repository }}/ |