Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 2 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ on:
branches:
- main
- develop

pull_request:
branches:
- main
- develop

jobs:
build:
name: Build & Test
verify:
name: Unit and Integration Verification
runs-on: ubuntu-latest

steps:
Expand All @@ -30,35 +29,8 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build -x test

- name: Run unit tests
run: ./gradlew test

- name: Run integration tests
run: ./gradlew integrationTest

- name: Upload unit test results
uses: actions/upload-artifact@v4
if: always()
with:
name: unit-test-results
path: build/reports/tests/test/
retention-days: 7

- name: Upload integration test results
uses: actions/upload-artifact@v4
if: always()
with:
name: integration-test-results
path: build/reports/tests/integrationTest/
retention-days: 7

- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: success()
with:
name: jar-artifact
path: build/libs/*.jar
retention-days: 7
25 changes: 25 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,34 @@ env:
IMAGE_NAME: git-ranker

jobs:
verify:
name: Pre-deploy Verification
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Java 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Run unit tests
run: ./gradlew test

- name: Run integration tests
run: ./gradlew integrationTest

docker:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: verify

steps:
- name: Checkout code
Expand Down
45 changes: 0 additions & 45 deletions .github/workflows/quality-gate.yml

This file was deleted.

15 changes: 0 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<a href="#badge">Badge</a> •
<a href="#data-refresh">Data Refresh</a> •
<a href="#faq">FAQ</a> •
<a href="#development-verification">Development Verification</a> •
<a href="#contributing">Contributing</a> •
<a href="#roadmap">Roadmap</a> •
<a href="#license">License</a> •
Expand Down Expand Up @@ -283,20 +282,6 @@ GitHub 프로필(`README.md`)에 동적 배지를 삽입해, 현재 티어와

---

<a id="development-verification"></a>
## 🧪 Development Verification

로컬 변경 후 backend 검증은 아래 순서로 실행합니다.

- `./gradlew test jacocoTestCoverageVerification`: 단위 테스트와 커버리지 검증을 실행합니다. Docker가 없어도 동작합니다.
- `./gradlew verifyDockerAvailable`: Testcontainers 기반 통합 테스트 전에 Docker CLI와 daemon 연결 가능 여부를 fail-fast로 확인합니다.
- `./gradlew integrationTest`: `verifyDockerAvailable`를 먼저 실행한 뒤 `*IT` 통합 테스트를 수행합니다. Docker가 준비되지 않았으면 환경 문제로 즉시 실패합니다.

> [!TIP]
> `verifyDockerAvailable`가 실패하면 먼저 `docker version`이 성공하는지 확인한 뒤 `./gradlew integrationTest`를 다시 실행하세요.

---

<a id="contributing"></a>
## 🤝 Contributing

Expand Down
70 changes: 8 additions & 62 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
id 'jacoco'
}

group = 'com.gitranker'
Expand Down Expand Up @@ -55,7 +54,6 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:mysql'
testImplementation 'com.tngtech.archunit:archunit-junit5:1.4.1'

testRuntimeOnly 'com.h2database:h2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand All @@ -67,26 +65,11 @@ tasks.named('test') {
exclude '**/*IT.class'
}

tasks.named('processResources') {
filteringCharset = 'UTF-8'
filesMatching('static/swagger-ui/index.html') {
expand(swaggerUiVersion: swaggerUiVersion)
}
}

tasks.register('verifyDockerAvailable', JavaExec) {
group = 'verification'
description = 'Fails fast when Docker is unavailable for Testcontainers-based integration tests.'
mainClass = 'com.gitranker.api.testsupport.DockerPreflightMain'
classpath = sourceSets.test.runtimeClasspath

dependsOn tasks.named('testClasses')
}

// 통합 테스트: *IT.java만 실행 (Docker/Testcontainers 필요)
// check 라이프사이클에 포함하지 않음 — Docker 없는 환경에서 build가 실패하지 않도록 의도적 제외
// CI에서는 별도 단계로 명시적 실행: ./gradlew integrationTest
// 통합 테스트: Testcontainers 기반 *IT.java만 별도 lane에서 실행
// check 라이프사이클에는 연결하지 않고 CI/deploy verification이 명시적으로 호출한다.
tasks.register('integrationTest', Test) {
group = 'verification'
description = 'Runs Testcontainers-backed integration tests.'
useJUnitPlatform()
include '**/*IT.class'

Expand All @@ -95,50 +78,13 @@ tasks.register('integrationTest', Test) {
testClassesDirs = sourceSets.test.output.classesDirs
classpath = sourceSets.test.runtimeClasspath

dependsOn tasks.named('verifyDockerAvailable')

// Docker 29+는 최소 API 1.44를 요구하지만 docker-java 3.4.0은 기본값 1.32로 요청함
systemProperty 'api.version', '1.44'
}

jacoco {
toolVersion = '0.8.12'
}

tasks.named('jacocoTestReport') {
dependsOn tasks.named('test')
reports {
xml.required = true
html.required = true
csv.required = false
}
}

tasks.named('jacocoTestCoverageVerification') {
dependsOn tasks.named('test')
violationRules {
rule {
element = 'BUNDLE'
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.45
}
}
tasks.named('processResources') {
filteringCharset = 'UTF-8'
filesMatching('static/swagger-ui/index.html') {
expand(swaggerUiVersion: swaggerUiVersion)
}
}

def trackedOpenApiSpec = layout.projectDirectory.file('docs/openapi/openapi.json')

tasks.register('generateOpenApiSpec', Test) {
group = 'documentation'
description = 'Generates the tracked OpenAPI specification snapshot.'
useJUnitPlatform()
include '**/OpenApiDocsTest.class'
testClassesDirs = sourceSets.test.output.classesDirs
classpath = sourceSets.test.runtimeClasspath
systemProperty 'openapi.output', trackedOpenApiSpec.asFile.absolutePath
outputs.file(trackedOpenApiSpec)

dependsOn tasks.named('testClasses')
}
28 changes: 0 additions & 28 deletions docs/openapi/README.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/openapi/openapi.json

This file was deleted.

This file was deleted.

Loading
Loading