Skip to content

Commit 2b2b4a3

Browse files
committed
chore: build ci/cd pipeline
1 parent 208062c commit 2b2b4a3

File tree

9 files changed

+307
-5
lines changed

9 files changed

+307
-5
lines changed

.github/workflows/CICD_DEVELOP.yml

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
name: CI/CD FOR DEVELOP
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
8+
env:
9+
DOCKERHUB_REPOSITORY: fontory-server
10+
11+
jobs:
12+
CI:
13+
name: Continuous Integration
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
18+
steps:
19+
- name: Get short SHA
20+
id: slug
21+
run: echo "sha7=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_OUTPUT
22+
23+
- name: Discord Webhook Action
24+
uses: tsickert/[email protected]
25+
with:
26+
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
27+
content: |
28+
New Commit[${{ steps.slug.outputs.sha7 }}] detected on branch ${{ github.ref_name }}
29+
Commit Link: https://github.com/${{ github.repository }}/commit/${{ github.sha }}
30+
GitHub Action Link: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
31+
32+
- name: Checkout
33+
uses: actions/checkout@v4
34+
35+
- name: Set up JDK 17
36+
uses: actions/setup-java@v4
37+
with:
38+
java-version: '17'
39+
distribution: 'temurin'
40+
41+
- name: Setup MySQL
42+
uses: mirromutth/[email protected]
43+
with:
44+
host port: 3308
45+
mysql database: 'TESTDB'
46+
mysql user: 'fontory'
47+
mysql password: 'fontoryPW'
48+
49+
- name: Setup Redis
50+
uses: supercharge/[email protected]
51+
with:
52+
redis-version: 6
53+
54+
- name: Setup Gradle
55+
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
56+
57+
- name: Generate application.properties
58+
run: |
59+
echo "commit.hash=${{ steps.slug.outputs.sha7 }}" >> ./src/main/resources/application-prod.properties
60+
echo "spring.datasource.url=jdbc:mysql://${{ secrets.DATASOURCE_DB_URL }}:3306/FONTORY?characterEncoding=UTF-8&serverTimezone=Asia/Seoul" >> ./src/main/resources/application-prod.properties
61+
echo "spring.datasource.username=${{ secrets.DATASOURCE_DB_USERNAME }}" >> ./src/main/resources/application-prod.properties
62+
echo "spring.datasource.password=${{ secrets.DATASOURCE_DB_PASSWORD }}" >> ./src/main/resources/application-prod.properties
63+
echo "spring.data.redis.host=${{ secrets.REDIS_URL }}" >> ./src/main/resources/application-prod.properties
64+
65+
- name: Build with Gradle Wrapper
66+
# run: ./gradlew test -i
67+
run: ./gradlew build
68+
69+
- name: Upload jar file to Artifact
70+
uses: actions/upload-artifact@v4
71+
with:
72+
name: jar_files
73+
path: build/libs/*.jar
74+
75+
- name: Upload Dockerfile to Artifact
76+
uses: actions/upload-artifact@v4
77+
with:
78+
name: Dockerfile
79+
path: ./Dockerfile
80+
81+
CD_Delivery:
82+
name: Delivery
83+
needs: CI
84+
runs-on: ubuntu-latest
85+
86+
permissions:
87+
contents: read
88+
89+
steps:
90+
- name: Download jar file from Artifact
91+
uses: actions/download-artifact@v4
92+
with:
93+
name: jar_files
94+
path: build/libs
95+
96+
- name: Download Dockerfile file from Artifact
97+
uses: actions/download-artifact@v4
98+
with:
99+
name: Dockerfile
100+
path: ./
101+
102+
- name: Log in to Docker Hub
103+
uses: docker/login-action@v3
104+
with:
105+
username: ${{ secrets.DOCKER_USERNAME }}
106+
password: ${{ secrets.DOCKER_PASSWORD }}
107+
108+
- name: Get short SHA
109+
id: slug
110+
run: echo "sha7=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_OUTPUT
111+
112+
- name: Build, tag, and push image to DockerHub
113+
id: build-image
114+
env:
115+
USERNAME: ${{ secrets.DOCKER_USERNAME }}
116+
IMAGE_TAG: ${{ steps.slug.outputs.sha7 }}
117+
118+
run: |
119+
docker build -t $USERNAME/$DOCKERHUB_REPOSITORY:$IMAGE_TAG -t $USERNAME/$DOCKERHUB_REPOSITORY:latest .
120+
docker push $USERNAME/$DOCKERHUB_REPOSITORY --all-tags
121+
echo "image=$USERNAME/$DOCKERHUB_REPOSITORY:$IMAGE_TAG&latest" >> $GITHUB_OUTPUT
122+
123+
CD_Deploy:
124+
name: Deploy
125+
needs: CD_Delivery
126+
runs-on: ubuntu-latest
127+
128+
steps:
129+
- name: Get short SHA
130+
id: slug
131+
run: echo "sha7=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_OUTPUT
132+
133+
- name: Executing remote ssh commands
134+
uses: appleboy/[email protected] # ssh 접속하는 오픈소스
135+
with:
136+
host: ${{ secrets.REMOTE_IP }} # 인스턴스 IP
137+
username: ${{ secrets.REMOTE_USER }} # 우분투 아이디
138+
key: ${{ secrets.REMOTE_PRIVATE_KEY }} # ec2 instance pem key
139+
port: ${{ secrets.REMOTE_SSH_PORT }} # 접속포트
140+
script: | # 실행할 스크립트
141+
cd /home/ubuntu/cicd/scripts
142+
./rolling-update.sh
143+
144+
- name: Discord Webhook Action
145+
uses: tsickert/[email protected]
146+
with:
147+
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
148+
content: |
149+
:o: Server successfully updated!
150+
Commit: [${{ github.sha }}]
151+
Branch: ${{ github.ref_name }}
152+
Commit Link: https://github.com/${{ github.repository }}/commit/${{ github.sha }}
153+
GitHub Action Link: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
154+
155+
failure_notification:
156+
name: Failure Notification
157+
runs-on: ubuntu-latest
158+
needs: [CI, CD_Delivery, CD_Deploy]
159+
if: failure()
160+
161+
steps:
162+
- name: Discord Webhook Action on Failure
163+
uses: tsickert/[email protected]
164+
with:
165+
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
166+
content: |
167+
:x: A job failed in the CI/CD pipeline!
168+
Commit: [${{ github.sha }}]
169+
Branch: ${{ github.ref_name }}
170+
Commit Link: https://github.com/${{ github.repository }}/commit/${{ github.sha }}
171+
GitHub Action Link: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
172+
Please check the logs for more details.

.github/workflows/CI_TEST.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: CI TEST
2+
3+
on:
4+
push:
5+
branches-ignore:
6+
- main
7+
- develop
8+
9+
jobs:
10+
CI:
11+
name: Continuous Integration
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Set up JDK 17
21+
uses: actions/setup-java@v4
22+
with:
23+
java-version: '17'
24+
distribution: 'temurin'
25+
26+
- name: Setup MySQL
27+
uses: mirromutth/[email protected]
28+
with:
29+
host port: 3308
30+
mysql database: 'TESTDB'
31+
mysql user: 'fontory'
32+
mysql password: 'fontoryPW'
33+
34+
- name: Setup Redis
35+
uses: supercharge/[email protected]
36+
with:
37+
redis-version: 6
38+
39+
- name: Setup Gradle
40+
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
41+
42+
- name: Get short SHA
43+
id: slug
44+
run: echo "sha7=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_OUTPUT
45+
46+
- name: Generate application.properties
47+
run: |
48+
# add properties
49+
50+
- name: Build with Gradle Wrapper
51+
run: ./gradlew build
52+

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM openjdk:17-alpine
2+
ARG JAR_FILE=build/libs/*.jar
3+
COPY ${JAR_FILE} app.jar
4+
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "/app.jar"]

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ test {
2929

3030
dependencies {
3131
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
32-
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
33-
implementation 'org.springframework.boot:spring-boot-starter-security'
32+
// implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
33+
// implementation 'org.springframework.boot:spring-boot-starter-security'
3434
implementation 'org.springframework.boot:spring-boot-starter-web'
3535
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
3636
compileOnly 'org.projectlombok:lombok'
3737
developmentOnly 'org.springframework.boot:spring-boot-devtools'
3838
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
3939
annotationProcessor 'org.projectlombok:lombok'
4040
testImplementation 'org.springframework.boot:spring-boot-starter-test'
41-
testImplementation 'org.springframework.security:spring-security-test'
41+
// testImplementation 'org.springframework.security:spring-security-test'
4242
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
4343
}
4444

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.fontory.fontorybe.common.controller;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.stereotype.Controller;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.ResponseBody;
7+
8+
@Controller
9+
public class HealthCheck {
10+
11+
@Value("${commit.hash}")
12+
public String commitHash;
13+
14+
@ResponseBody
15+
@GetMapping("/health-check")
16+
public String healthCheck() { return commitHash; }
17+
}

src/main/resources/application-test.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
spring.datasource.url=jdbc:mariadb://localhost:3308/TESTDB?characterEncoding=UTF-8&serverTimezone=Asia/Seoul
1+
spring.datasource.url=jdbc:mariadb://localhost:3308/TESTDB?characterEncoding=UTF-8&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true&useSSL=false
22
spring.datasource.username=fontory
33
spring.datasource.password=fontoryPW
44

src/main/resources/application.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ spring.jpa.show-sql=true
66
spring.jpa.properties.hibernate.format_sql=true
77

88
spring.data.redis.host=localhost
9-
spring.data.redis.port=6379
9+
spring.data.redis.port=6379
10+
11+
commit.hash=local
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.fontory.fontorybe.port;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.beans.factory.annotation.Autowired;
5+
import org.springframework.boot.test.context.SpringBootTest;
6+
7+
import javax.sql.DataSource;
8+
import java.sql.Connection;
9+
import java.sql.SQLException;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.assertj.core.api.Fail.fail;
13+
14+
@SpringBootTest
15+
public class DBConnectivityTest {
16+
17+
@Autowired
18+
private DataSource dataSource;
19+
20+
@Test
21+
void testDatabaseConnectivity() {
22+
try (Connection conn = dataSource.getConnection()) {
23+
assertThat(conn).isNotNull();
24+
} catch (SQLException e) {
25+
fail("DB 연결 실패: " + e.getMessage());
26+
}
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.fontory.fontorybe.port;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.beans.factory.annotation.Autowired;
5+
import org.springframework.boot.test.context.SpringBootTest;
6+
import org.springframework.data.redis.core.RedisTemplate;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
@SpringBootTest
11+
public class RedisConnectivityTest {
12+
13+
@Autowired
14+
private RedisTemplate<String, String> redisTemplate;
15+
16+
@Test
17+
void testRedisConnectivity() {
18+
final String key = "key";
19+
final String value = "value";
20+
21+
redisTemplate.opsForValue().set(key, value);
22+
23+
String storedValue = redisTemplate.opsForValue().get(key);
24+
25+
assertThat(storedValue).isEqualTo(value);
26+
}
27+
}

0 commit comments

Comments
 (0)