Skip to content

Commit ab3215d

Browse files
committed
ci: add CI/CD pipeline via OpsTools
1 parent 211fedb commit ab3215d

1 file changed

Lines changed: 212 additions & 0 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
name: Node.js API CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- develop
8+
pull_request:
9+
branches:
10+
- main
11+
- develop
12+
13+
env:
14+
AWS_REGION: us-east-1
15+
ECR_REPOSITORY: node-api
16+
ECS_SERVICE: node-api-service
17+
ECS_CLUSTER: production
18+
19+
permissions:
20+
contents: read
21+
id-token: write
22+
23+
jobs:
24+
lint:
25+
runs-on: ubuntu-22.04
26+
steps:
27+
- name: Checkout code
28+
uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9
29+
30+
- name: Setup Node.js
31+
uses: actions/setup-node@60edb5dd545a775178fac7f3f667f4173c5c7605
32+
with:
33+
node-version: '18.18.0'
34+
cache: npm
35+
36+
- name: Install dependencies
37+
run: npm ci
38+
39+
- name: Run ESLint
40+
run: npm run lint --if-present
41+
42+
test:
43+
runs-on: ubuntu-22.04
44+
needs: lint
45+
steps:
46+
- name: Checkout code
47+
uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9
48+
49+
- name: Setup Node.js
50+
uses: actions/setup-node@60edb5dd545a775178fac7f3f667f4173c5c7605
51+
with:
52+
node-version: '18.18.0'
53+
cache: npm
54+
55+
- name: Install dependencies
56+
run: npm ci
57+
58+
- name: Run tests
59+
run: npm test --if-present
60+
61+
- name: Generate coverage report
62+
run: npm run test:coverage --if-present
63+
64+
- name: Upload coverage to Codecov
65+
uses: codecov/codecov-action@v3.1.4
66+
with:
67+
files: ./coverage/coverage-final.json
68+
flags: unittests
69+
fail_ci_if_error: false
70+
71+
build:
72+
runs-on: ubuntu-22.04
73+
needs: test
74+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
75+
outputs:
76+
image_uri: ${{ steps.image.outputs.uri }}
77+
steps:
78+
- name: Checkout code
79+
uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9
80+
81+
- name: Configure AWS credentials
82+
uses: aws-actions/configure-aws-credentials@v4.0.1
83+
with:
84+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
85+
aws-region: ${{ env.AWS_REGION }}
86+
role-duration-seconds: 900
87+
88+
- name: Login to Amazon ECR
89+
id: login-ecr
90+
uses: aws-actions/amazon-ecr-login@v2.0.1
91+
92+
- name: Build Docker image
93+
id: docker_build
94+
uses: docker/build-push-action@v5.1.0
95+
with:
96+
context: .
97+
push: false
98+
tags: |
99+
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
100+
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
101+
cache-from: type=registry,ref=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:buildcache
102+
cache-to: type=registry,ref=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:buildcache,mode=max
103+
outputs: type=docker,dest=/tmp/image.tar
104+
105+
- name: Push Docker image to ECR
106+
run: |
107+
docker load --input /tmp/image.tar
108+
docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
109+
docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
110+
111+
- name: Output image URI
112+
id: image
113+
run: echo "uri=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}" >> $GITHUB_OUTPUT
114+
115+
validate-terraform:
116+
runs-on: ubuntu-22.04
117+
needs: test
118+
steps:
119+
- name: Checkout code
120+
uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9
121+
122+
- name: Setup Terraform
123+
uses: hashicorp/setup-terraform@v2.1.0
124+
with:
125+
terraform_version: 1.6.0
126+
127+
- name: Terraform Format Check
128+
run: terraform fmt -check -recursive ./terraform
129+
130+
- name: Terraform Init
131+
run: cd terraform && terraform init -backend=false
132+
133+
- name: Terraform Validate
134+
run: cd terraform && terraform validate
135+
136+
- name: TFLint
137+
uses: terraform-linters/setup-tflint@v4.0.0
138+
with:
139+
tflint_version: v0.48.0
140+
141+
- name: Run TFLint
142+
run: cd terraform && tflint --init && tflint
143+
144+
deploy-to-ecs:
145+
runs-on: ubuntu-22.04
146+
needs: [build, validate-terraform]
147+
if: github.ref == 'refs/heads/main'
148+
environment: production
149+
steps:
150+
- name: Checkout code
151+
uses: actions/checkout@9bb56186c3b09b1872191b74733305c135a6d0e9
152+
153+
- name: Configure AWS credentials
154+
uses: aws-actions/configure-aws-credentials@v4.0.1
155+
with:
156+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
157+
aws-region: ${{ env.AWS_REGION }}
158+
role-duration-seconds: 1800
159+
160+
- name: Setup Terraform
161+
uses: hashicorp/setup-terraform@v2.1.0
162+
with:
163+
terraform_version: 1.6.0
164+
165+
- name: Terraform Init
166+
run: cd terraform && terraform init
167+
168+
- name: Terraform Plan
169+
run: cd terraform && terraform plan -var="image_tag=${{ needs.build.outputs.image_uri }}" -out=tfplan
170+
171+
- name: Terraform Apply
172+
if: github.ref == 'refs/heads/main'
173+
run: cd terraform && terraform apply -auto-approve tfplan
174+
175+
- name: Update ECS service
176+
run: |
177+
aws ecs update-service \
178+
--cluster ${{ env.ECS_CLUSTER }} \
179+
--service ${{ env.ECS_SERVICE }} \
180+
--force-new-deployment \
181+
--region ${{ env.AWS_REGION }}
182+
183+
- name: Wait for ECS service update
184+
run: |
185+
aws ecs wait services-stable \
186+
--cluster ${{ env.ECS_CLUSTER }} \
187+
--services ${{ env.ECS_SERVICE }} \
188+
--region ${{ env.AWS_REGION }}
189+
190+
notify:
191+
runs-on: ubuntu-22.04
192+
needs: [lint, test, build, validate-terraform, deploy-to-ecs]
193+
if: always()
194+
steps:
195+
- name: Slack notification on failure
196+
if: failure()
197+
uses: slackapi/slack-github-action@v1.24.0
198+
with:
199+
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
200+
payload: |
201+
{
202+
"text": "GitHub Action failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
203+
}
204+
205+
- name: Slack notification on success
206+
if: success()
207+
uses: slackapi/slack-github-action@v1.24.0
208+
with:
209+
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
210+
payload: |
211+
{
212+
"text": "GitHub Action succeeded: ${{ github.server_url }}/${{ github.repository }}/

0 commit comments

Comments
 (0)