1. 들어가며
지금 운영하고 있는 패키 프로젝트에서는 Flyway를 사용하여 DDL 생성을 자동화하고 있다.
Flyway를 사용하면 엔티티와 테이블 매핑이 일치하지 않을 때 애플리케이션 실행에 실패한다. 그렇기 때문에 테이블 컬럼을 수정하지 않아 나중에 서비스를 운영하다가 비즈니스 로직이 실패하는 문제 상황을 예방할 수 있다.
나는 해당 기능을 활용하여 개발/운영 환경을 배포하기 전에 로컬에서 profile을 dev와 prod로 변경한 뒤 애플리케이션을 실행해보며 배포 실패를 방지하고 있다. 최근에는 해당 단계를 깜빡하여 개발 환경 배포 시 애플리케이션 실행에 실패한 경험이 있다 ㅠㅠ
이번 포스트에서는 Github Actions에서 애플리케이션 실행을 대신하여 이러한 반쪽짜리 자동화를 발전시켜보자 !
2. FlywayApplication
참고로 패키는 멀티 모듈 프로젝트로 구성되어 있으며, 실제 SpringApplication이 실행되는 모듈은 api 모듈이다.
기존에는 flyway 관련 설정을 domain 모듈에서 진행했는데 해당 모듈은 api 모듈과 의존성을 가지고 있어 api 모듈과 독립된 flyway 모듈을 만들어 해당 모듈로 flyway 관련 설정을 옮겼다.
@EntityScan(basePackages = {"com.dilly.*"})
@SpringBootApplication
public class FlywayApplication {
public static void main(String[] args) {
System.setProperty("spring.config.name",
"application-domain, application-flyway");
ConfigurableApplicationContext ctx = SpringApplication.run(FlywayApplication.class, args);
ctx.close();
}
}
Github Actions에서 엔티티-테이블 매핑 검증 자동화를 위해 사용할 애플리케이션이다. 해당 애플리케이션은 검증에만 사용되고 계속 실행될 필요가 없으므로 close 메서드로 애플리케이션을 종료시켜주었다.
3. Github Actions 스크립트 수정
name: packy API Server - CI
on:
pull_request:
branches:
- main
- develop
permissions:
contents: read
jobs:
CI:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.ACTION_TOKEN }}
submodules: true
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Run build Flyway Module
run: ./gradlew clean packy-flyway:build
- name: Run FlywayApplication
run: java -Dspring.profiles.active=${{ env.PROFILE }} -jar ./packy-flyway/build/libs/packy-flyway-0.0.1-SNAPSHOT.jar
env:
PROFILE: ${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}
- name: Run build with Gradle Wrapper
run: ./gradlew clean build --parallel
- name: Report to CodeCov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: 'packy-support/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml'
위 step 중 Run build Flyway Module, Run FlywayApplication이 매핑 검증 단계이고 나머지는 기존 CI 스크립트에 있던 코드이다.
gradle build를 할 경우 모든 모듈이 빌드되기 때문에 flyway 모듈만 빌드하도록 하였으며, dev 또는 prod로 profile을 설정하여 FlywayApplication을 실행했다.
4. 결과
엔티티와 테이블 매핑이 일치하지 않는 상황을 만들기 위해 Member 엔티티에 임의로 test라는 컬럼을 추가하고 워크플로우를 실행시켜보았다.
@Entity
public class Member extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
// 중략 ...
String test;
}
스키마 불일치로 인해 어플리케이션 실행에 실패하여 워크플로우가 실패한 모습을 볼 수 있다.
5. 마치며
이제는 직접 SpringApplication을 실행해보는 작업을 하지 않아도 배포 이전에 엔티티-테이블 스키마가 일치하는지 확인할 수 있도록 자동화 단계를 추가하였다 :)
기존에 Flyway를 도입한 것도 자동화였지만, 일부 수동 작업이 필요한 자동화였다. 이번 경험을 통해 이미 자동화를 적용한 영역에서도 불편함을 찾아 자동화 단계를 보다 개선할 수 있음을 배웠고, 앞으로도 자동화를 거친 단계에 수동으롤 반복되는 작업이 더 없는가 다시 고민해보고 개선하는 자세로 프로젝트를 관리해야겠다.