Skip to content

Commit

Permalink
Step4 carracing (#5541)
Browse files Browse the repository at this point in the history
* step1 squash

* step2 squash

* step3 squash

* docs(README): STEP4 README.md 작성

* feat(car): Move, getDistance 구현

* feat(car): name 필드

* feat(car): Car 구현 완료 및 정리

* feat(Race): Race 생성자 및 getter 처리

* feat(Race): Race runRound

- 이전 study test depreacated 주석처리

* feat(Input): Input 구현

* feat(result): 자동차 이름과 함께 움직임 출력

* feat(result): 최종 우승자 출력: 1명 이상 일 수 있음

* feat(result): result 구현 완료

* check: UI를 InputView, ResultView로 분리

* 메서드가 15라인을 넘어가지 않도록 구현

- pmd로 ncss 15line 강제화
- jdk21 apply
- 기존 에
* 에러 정의 차이

리플렉션을 사용하여 생성자를 호출하면, 생성자 내부에서 발생하는 예외는 InvocationTargetException에 감싸져서 발생합니다. 이 때문에 예외가 직접적으로 UnsupportedOperationException가 아니라 InvocationTargetException으로 포착되는 것입니다.

* 최적화

* Car 상수 사용 및 보완

* formatting

* 가독성

* workflow 수정

* workflow 수정

* pmdtest4에 step4 넣음

* workflow에 pmd summary 추가

* 15라인 rule은 main 코드에만 ㅋㅋ

* Extract PMD info and update step summary

* test dependon pmdmain

* pmd 실패여도 진행

* xmllint 사용 제거

* 메시지 추출 부분 수정

* 일단 원복

* awk로 개선된 스크립트

설명
파일 처리:

awk를 사용하여 <file> 태그로 시작하고 </file> 태그로 끝나는 블록을 찾습니다. 이는 awk '/<file name=/,/<\/file>/' 명령으로 처리합니다.
파일 내부 처리:

awk 스크립트는 각 파일 블록을 처리하면서 파일 이름을 추출하고, 각 위반 사항의 정보를 파싱합니다.
파일 이름은 gensub() 함수를 사용하여 추출하고, 위반의 라인 번호, 메시지, URL을 추출하여 출력합니다.
Markdown 형식:

추출된 정보는 콘솔에 출력되고 pmd_summary.md 파일에 Markdown 형식으로 기록됩니다.
최종적으로, 이 Markdown 파일은 GitHub Actions 단계 요약에 추가됩니다.
장점
성능: awk는 스트림을 처리하면서 발생하는 데이터를 효율적으로 처리할 수 있으므로, 큰 XML 파일에 대해서도 성능상의 이점이 있습니다.
간결성: awk를 사용하면 복잡한 grep 및 sed 조합을 하나의 명령으로 대체할 수 있어 스크립트가 더욱 간결해집니다.
유지 관리: 스크립트가 간결해지므로 유지 관리가 용이해지며, 변경 사항을 적용하기 쉬워집니다.

* awk로 개선된 스크립트2 - 텍스트 한정

변경된 부분 설명
태그 내용 처리 로직: <violation> 태그를 만나면 내용 캡처를 시작하고, </violation> 태그를 만나면 내용 캡처를 종료하며, 그 사이에 있는 모든 텍스트를 content 변수에 누적합니다.
텍스트 출력: 최종적으로 각 violation의 설명이 content 변수에 저장되고, 이를 Markdown 링크의 텍스트로 사용하여 출력합니다.
이 수정을 통해 PMD 요약 정보에는 각 violation의 상세 설명이 <violation> 태그 사이의 텍스트로 정확히 제공됩니다. 이 방법은 XML 데이터에서 필요한 정보만을 추출하여 보다 명확하고 유용한 요약을 생성하는 데 도움이 됩니다.

* message 수정

* workflow-PR 생성

* NCSS 5->15

* NCSS 5->15

* NCSS 15->5

* README.md 수정

* onPRTest

* onPRTest -             $GITHUB_STEP_SUMMARY

* onPRTest

* Comment SUMMARY Report on PR body check

* body-path: 'PR_summary.md'

* body-path: 'PR_summary.md'

* PUSH_summary.md 에 모으기

* PR_summary.md 에 total count 추가

* push workflow는 pr이 있으면 작동하지 않음

* pr workflow type 지정

* PR시에는 build task

* github.event.pull_request삭제 - pr workflow에서만 true 가능

* types 가독성

* graalvm 적용

* 정리

* 언어 정리

* pmd pmdtest는 전부 제외, pmdmin은 step4만

* 메서드라인은 15라인

* 문제가 없을시 pmd report 요약 액션 에러 수정

* push workflow - 문제가 없을시 pmd report 요약 액션 에러 수정

* PR 멈추기

* push test

* push test2

* error 수정: branches-ignore: ['*']

* total_violations 출력 수정

* 극단적 test

* 극단적 test2

* 극단적 test3

* PMD 리포트 요약 복원

* grep 명령 실패 허용

* jacoco summary 지워지는 거 방지

* PR workflow 활성화

---------

Co-authored-by: GeunChang Ahn <[email protected]>

* Step4 - 단일 책임원칙 확인

* psvm 클래스 rename

* 패키지 이동

* 메서드명 변경

* CarRacingRunner 생성

* 단일책임 원칙

---------

Co-authored-by: GeunChang Ahn <[email protected]>

* Merge remote-tracking branch 'origin/step4_carracing' into step4_carr… (#3)

conflict 해결 ㅠ

* conflict 해결 및 전략 패턴 적용 (#4)

* conflict ㅎㅐ결

* RandomMovingStrategy 작성

* stragegy 패턴 적용

* 포맷팅
  • Loading branch information
rkaehdaos authored Apr 18, 2024
1 parent 9fd75c9 commit d1ae780
Show file tree
Hide file tree
Showing 21 changed files with 715 additions and 46 deletions.
18 changes: 18 additions & 0 deletions .github/pmd/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<ruleset name="Custom ruleset"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
메서드 길이를 15줄로 제한하는 custom ruleset
</description>

<!-- https://docs.pmd-code.org/latest/pmd_rules_java_design.html#ncsscount-->
<rule ref="category/java/design.xml/NcssCount">
<properties>
<property name="methodReportLevel" value="15"/> <!-- 기본값 60 -->
<property name="classReportLevel" value="1500"/> <!--default-->
</properties>
</rule>

</ruleset>
113 changes: 113 additions & 0 deletions .github/workflows/PR-mytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: Gradle PR test On GitHub Action
on:
pull_request:
types: [opened,reopened,synchronize]

jobs:
onPRTest:
runs-on: ubuntu-latest
steps:
- name: '소스 checkout'
uses: actions/checkout@master

- name: 'graalvm jdk21 setup'
uses: graalvm/setup-graalvm@v1
with:
java-version: '21'
distribution: 'graalvm'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
cache: 'gradle'

- name: 'gradle 빌드'
run: gradle build --no-daemon --parallel

- name: '커버리지 정보 및 요약'
run: |
echo 'CSV 파일에서 커버리지 정보 추출';
awk -F',' 'NR > 1 {instructions_covered += $5; instructions_missed += $4; branches_covered += $7; branches_missed += $6} END {print instructions_covered, instructions_missed, branches_covered, branches_missed}' build/reports/jacoco/test/jacocoTestReport.csv > coverage.txt
read instructions_covered instructions_missed branches_covered branches_missed < coverage.txt
echo '커버리지 계산';
total_instructions=$((instructions_covered + instructions_missed))
total_branches=$((branches_covered + branches_missed))
instruction_coverage=$(echo "scale=2; $instructions_covered / $total_instructions * 100" | bc)
echo '분모가 0일 경우, 커버리지를 'N/A'로 설정';
if [ "$total_instructions" -eq 0 ]; then
instruction_coverage="N/A"
else
instruction_coverage=$(echo "scale=2; $instructions_covered / $total_instructions * 100" | bc)%
fi
if [ "$total_branches" -eq 0 ]; then
branch_coverage="N/A"
else
branch_coverage=$(echo "scale=2; $branches_covered / $total_branches * 100" | bc)%
fi
echo '# GitHub Action Summary' >> PR_summary.md
echo 'GITHUB_STEP_SUMMARY에 커버리지 정보 추가';
echo "## JaCoCo 커버리지 요약" >> PR_summary.md
echo "- Instruction Coverage: $instruction_coverage" >> PR_summary.md
echo "- Branch Coverage: $branch_coverage" >> PR_summary.md
- name: 'PMD 리포트 요약'
run: |
echo 'PMD 파일에서 정보 추출: XML 구조에 의존적이므로 구조가 변경되면 스크립트도 업데이트가 필요';
echo 'xml이 매우 크면 성능에 문제가 생길 수 있으므로 더 효율적인 파싱 방법의 고려가 필요';
echo "## PMD Code Analysis" >> PR_summary.md
total_violations=$(grep -c '<violation' build/reports/pmd/main.xml||true)
if [ "$total_violations" -eq 0 ]; then
echo "### 문제 없음" >> PR_summary.md
else
echo "### Total Violations: $total_violations" >> PR_summary.md
echo '각 file 태그를 찾아 파일 경로를 추출하고, 내부의 violation 정보를 처리'
awk '/<file name=/,/<\/file>/' build/reports/pmd/main.xml | awk '
/<file name="/ {
filename=gensub(/.*<file name="([^"]+).*/, "\\1", "g");
print "### File: " filename;
print "### File: " filename >> "PR_summary.md";
next;
}
/<violation/,/<\/violation>/ {
if ($0 ~ /<violation/) {
line=gensub(/.*beginline="([^"]+).*/, "\\1", "g");
url=gensub(/.*externalInfoUrl="([^"]+).*/, "\\1", "g");
capturing = 1;
content = "";
} else if ($0 ~ /<\/violation>/) {
print "- Line " line ": [" content "](" url ")";
print "- Line " line ": [" content "](" url ")" >> "PR_summary.md";
capturing = 0;
} else if (capturing) {
content = content $0;
}
}
'
fi
cat PR_summary.md >> $GITHUB_STEP_SUMMARY
- name: 'PR Comment에 SUMMARY Report 작성'
if: github.repository == 'rkaehdaos/java-racingcar'
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body-path: 'PR_summary.md'

- name: '실패 시 보고서 업로드'
uses: actions/upload-artifact@v4
if: failure()
with:
name: report-jacoco
path: |
build/reports/jacoco/test/html
build/reports/pmd/*.html
- name: 'slack 알림'
uses: 8398a7/action-slack@v3
if: github.repository == 'rkaehdaos/java-racingcar'
with:
status: ${{ job.status }}
author_name: my workflow bot
fields: repo,message,commit,author,eventName,ref,workflow,job,took,
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
73 changes: 55 additions & 18 deletions .github/workflows/push-test.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
name: Gradle test On GitHub Action
on:
push:
branches-ignore: [ 'main','master','rkaehdaos' ]
branches-ignore: ['main','master']

jobs:
onPushTest:
if: github.event.pull_request.opened == false
runs-on: ubuntu-latest
steps:
- name: Checkout source code
- name: '소스 checkout'
uses: actions/checkout@master

- name: setup-java-21
- name: 'jdk21 setup'
uses: actions/setup-java@v4
with:
distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '11'
distribution: 'zulu'
java-version: '21'
cache: 'gradle'

- name: test
- name: 'gradle test'
run: |
echo "Available processors: $(nproc)"
gradle test jacocoTestCoverageVerification --no-daemon --parallel
gradle test --no-daemon --parallel
- name: Extract coverage info and update step summary
- name: '커버리지 정보 및 요약'
run: |
echo 'CSV 파일에서 커버리지 정보 추출';
awk -F',' 'NR > 1 {instructions_covered += $5; instructions_missed += $4; branches_covered += $7; branches_missed += $6} END {print instructions_covered, instructions_missed, branches_covered, branches_missed}' build/reports/jacoco/test/jacocoTestReport.csv > coverage.txt
Expand All @@ -43,25 +42,63 @@ jobs:
else
branch_coverage=$(echo "scale=2; $branches_covered / $total_branches * 100" | bc)%
fi
echo '# GitHub Action Summary' >> PUSH_summary.md
echo 'GITHUB_STEP_SUMMARY에 커버리지 정보 추가';
echo "JaCoCo 커버리지 요약" >> $GITHUB_STEP_SUMMARY
echo "Instruction Coverage: $instruction_coverage" >> $GITHUB_STEP_SUMMARY
echo "Branch Coverage: $branch_coverage" >> $GITHUB_STEP_SUMMARY
echo "## JaCoCo 커버리지 요약" >> PUSH_summary.md
echo "- Instruction Coverage: $instruction_coverage" >> PUSH_summary.md
echo "- Branch Coverage: $branch_coverage" >> PUSH_summary.md
- name: Upload JaCoCo coverage report
- name: 'PMD 리포트 요약'
run: |
echo 'PMD 파일에서 정보 추출: XML 구조에 의존적이므로 구조가 변경되면 스크립트도 업데이트가 필요';
echo 'xml이 매우 크면 성능에 문제가 생길 수 있으므로 더 효율적인 파싱 방법의 고려가 필요';
echo "## PMD Code Analysis" >> PUSH_summary.md
total_violations=$(grep -c '<violation' build/reports/pmd/main.xml||true)
if [ "$total_violations" -eq 0 ]; then
echo "### 문제 없음" >> PUSH_summary.md
else
echo "### Total Violations: $total_violations" >> PUSH_summary.md
echo '각 file 태그를 찾아 파일 경로를 추출하고, 내부의 violation 정보를 처리'
awk '/<file name=/,/<\/file>/' build/reports/pmd/main.xml | awk '
/<file name="/ {
filename=gensub(/.*<file name="([^"]+).*/, "\\1", "g");
print "### File: " filename;
print "### File: " filename >> "PUSH_summary.md";
next;
}
/<violation/,/<\/violation>/ {
if ($0 ~ /<violation/) {
line=gensub(/.*beginline="([^"]+).*/, "\\1", "g");
url=gensub(/.*externalInfoUrl="([^"]+).*/, "\\1", "g");
capturing = 1;
content = "";
} else if ($0 ~ /<\/violation>/) {
print "- Line " line ": [" content "](" url ")";
print "- Line " line ": [" content "](" url ")" >> "PUSH_summary.md";
capturing = 0;
} else if (capturing) {
content = content $0;
}
}
'
fi
cat PUSH_summary.md >> $GITHUB_STEP_SUMMARY
- name: '실패 시 보고서 업로드'
uses: actions/upload-artifact@v4
if: failure()
with:
name: jacoco-report
path: build/reports/jacoco/test/html
name: report-jacoco
path: |
build/reports/jacoco/test/html
build/reports/pmd/*.html
- name: Notification
- name: 'slack 알림'
uses: 8398a7/action-slack@v3
if: always()
with:
status: ${{ job.status }}
author_name: GeunChang Ahn
job_name: onPushTest
author_name: my workflow bot
fields: repo,message,commit,author,eventName,ref,workflow,job,took,
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
52 changes: 32 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
# 자동차 경주 게임
## 진행 방법
* 자동차 경주 게임 요구사항을 파악한다.
* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다.
* 코드 리뷰 피드백에 대한 개선 작업을 하고 다시 PUSH한다.
* 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다.
# 🚀 4단계 - 자동차 경주(우승자)

## 온라인 코드 리뷰 과정
* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview)
- 구현할 기능 목록 단위 추가
- commit 단위는 정리한 기능 목록 단위로 추가할 것!!

UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다.
## 기능 요구사항
- [x] 기능을 구현하기 전에 README.md 파일에 구현할 기능 목록을 정리해 추가
- [x] Car 구현
- [x] move 구현: random4이상시 움직임
- [x] getDistance: 차의 움직인 거리 getter
- [x] 이름: 5자 제한, 생성할때 부여, getter 필요, Lombok `@getter` 처리
- [] Race 구현
- [x] Race 생성자 : 자동차들 list 준비,
- [x] 자동차 리스트 가져오기: `@getter` 처리
- [x] Race runRound

- [x] Input 구현
- [x] 자동차 이름 입력
- [x] : validate: 5자 : 이미 Car 생성자에서 구현

## 기능 목록 및 commit 로그 요구사항
- commit message 종류 구분
```text
feat (feature)
fix (bug fix)
docs (documentation)
style (formatting, missing semi colons, …)
refactor
test (when adding missing tests)
chore (maintain)
```
- [x] result 구현
- [x] 자동차 이름과 함께 움직임 출력
- [x] 최종 우승자 출력: 1명 이상 일 수 있음

## Check 사항
- [ ] 들여쓰기 1까지인지 확인
- [x] 메서드가 15라인을 넘어가지 않도록 구현
- [x] ~~pmd 15 line 적용 시도~~
- https://github.com/pmd/pmd/issues/2127#issue-527718378
- Enforcing length limits with LoC("lines of code") is not very meaningful, could even be called a bad practice
- **LoC로 길이 제한을 적용하는 것은 그다지 의미가 없으며, 심지어 나쁜 관행이라고 할 수도 있습니다**
- [x] NCSS 15 라인 설정 - PMD Custom Rule apply

- [x] 단일 책임 원칙으로 메서드가 되어 있는지 확인
- [ ] 모든 로직에 단위 테스트 구현 - UI 제외
- [x] UI를 `InputView`, `ResultView`로 분리
39 changes: 37 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id 'java'
id 'jacoco'
id 'pmd'
}

version '1.0'
Expand All @@ -19,14 +20,45 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

// java
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
languageVersion = JavaLanguageVersion.of(21)
}
}

tasks.named('compileJava') {
dependsOn clean
}

tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:deprecation"
}

// pmd
pmd {
toolVersion = "7.0.0"
consoleOutput = true
ignoreFailures = true
incrementalAnalysis = true
ruleSets = []
ruleSetFiles = files(rootProject.file(".github/pmd/ruleset.xml") as Object)
}

tasks.named('pmdMain') {
// excludes =['**/*',]
includes = ['**/step4_winner/*',]
// ruleSetFiles = files(rootProject.file(".github/pmd/ruleset.xml") as Object)
}

tasks.named('pmdTest') {
excludes =['**/*',]
// includes = ['**/step4_winner/*',]
}

tasks.named('test') {
useJUnitPlatform() // Junit5 사용: 테스트 종속성에 JUnit Jupiter API와 JUnit Jupiter Engine을 포함해야 함.
dependsOn pmdMain
useJUnitPlatform()
maxParallelForks = Runtime.runtime.availableProcessors()
finalizedBy jacocoTestCoverageVerification
}
Expand All @@ -35,4 +67,7 @@ jacocoTestReport {
}
jacocoTestCoverageVerification {
dependsOn jacocoTestReport
violationRules {
rule { limit { minimum = 0.8 } }
}
}
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStorePath=wrapper/dists
Loading

0 comments on commit d1ae780

Please sign in to comment.