Gitub Actions를 통해 PR이 올라오면 자동으로 테스트를 돌려주는 기능을 적용하면서 삽질을 했던 것을 풀어보려고 한다. 아직 완벽하게 해결하지 못한 문제가 있어서 밤이 깊어가는데도 마음 한구석에 찝찝하고 아쉬움이 남았다. 이 과정에서 배운 것도 많고, 앞으로 더 개선할 부분에 대한 고민도 많이 하게 되었다..🤣
삽질을 해야 얻는 게 많아, 너무 잘 풀리면 배우는 게 없어 ~ (라고 세뇌 중....)
12/06 결국 해결완료🔥🔥
workflows에서 Actions이 작동이 안 한다!?
name: Java CI with Gradle
on:
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 🍀 JDK 17 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🍀 gradlew 실행 권한 설정
run: chmod +x gradlew
- name: 🍀 테스트 진행
run: ./gradlew --info test
가장 첫 ci.yml파일은 말랑님 블로그를 참고해서 우선 잘 모르고 세팅해서 부족한 부분이 아주 많다.
- applicatoin.yml 파일을. gitignore 했거나 환경변수로 대체해 놨을 텐데 어떻게 세팅하지?
- 그런데 왜 Actions가 작동을 안 하지? - (작동하면서 테스트를 실패해야 하는 게 아닌가?)
- 근데 이게 어디서 실행되지?
일단 2번은 이유조차 모르겠고 3번은 git에 runner라는 게 실행시켜 준다는 것 같아 우선 넘어가고 1번부터 해결하기로 했다.
1. PR 테스트 자동화에서 환경변수 다루기
Github에서 사용할 수 있는 Actions secrets와 submodule을 사용해서 구성했다.
왜 두 개 다 사용했지?
: submodule을 private로 해놓긴 했지만 혹시나 하는 불상사를 막기 위해
그렇지만 모든 것을 다 secrets에 넣은 건 아닌 진짜 중요한 key들이나 비밀번호만 넣었다.
= 최대한 변경이 없는 것과 중요한 것만 secrets로 넣었기 때문에?! 한 번만 설정하면 그다음엔 건들지 않아도 된다.
name: Java CI with Gradle
on:
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 🍀 서브모듈 추가
with:
token: ${{ secrets.GIT_TOKEN }}
submodules: true
- uses: actions/checkout@v3
- name: 🍀 JDK 17 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🍀 gradlew 실행 권한 설정
run: chmod +x gradlew
- name: 🍀 비밀 설정 파일 복사
run: ./gradlew copySecret
- name: 🍀 테스트 진행
env:
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }}
PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
run: ./gradlew test
그렇게 탄생한 ci.yml 파일이다. 그렇지만 여기서 또 에러가 발생하는데...
Error: .github#L1
every step must define a `uses` or `run` key
계속 수정 수정하면서 yml파일이 조금 많이 살이 찐 것 같다.. 우선 name 옆에 -이 있고 uses를 두 번 쓴 곳도 있다.
➜ 워크플로에 문법오류가 있어서 실행자체가 안 된 것 같다. (잘 확인하길 바라며..)
최종 ci.yml 파일
이 전에 삽질을 좀 많이 하면서 workflows에 대한 이해가 조금조금씩 생겨 많이 깔끔해지고 기능도 추가했다.
name: Java CI with Gradle
on:
pull_request:
types: [ opened, reopened ]
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: 🍀 서브모듈 추가
uses: actions/checkout@v3
with:
token: ${{ secrets.GIT_TOKEN }}
submodules: true
- name: 🍀 JDK 17 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🍀 gradlew 실행 권한 설정
run: chmod +x gradlew
- name: 🍀 비밀 설정 파일 복사
run: ./gradlew copySecret
- name: 🍀 테스트 진행
env:
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }}
PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
run: ./gradlew test
그런데 왜 Github Actions가 실행을 안 하지..?
2. Actions이 작동을 안 한다.
이것저것 찾아보고 계속되는 삽질과 테스트로 얻은 정보들이 있다.
- 찐 main(즉 upstream main)에서 branch를 파고 PR을 올리면 Actions가 작동을 한다. ☑️
- 찐 main에서 Fork를 하고 나의 main에서 branch를 파서 PR을 올리면 Actions이 작동을 안 한다. 🚫
삽질 중 Actions 테스트를 하려고 PR을 close 하고 reopen 하는 것을 반복했는데 나중엔
`types: [ opened, reopened, synchronize ]`를 추가해서 commit을 해도 Actions가 작동하도록 수정했다.
결국 Fork 한 곳에서 PR을 올려도 Actions가 작동하는 방법을 알아냈다!
"Setting > Actions > General > Run workflows from fork pull requests"를 체크해 주면 된다..!
(참고로 Repository에서 설정하면 저게 선택이 안 되는데 Repository 내에서 설정하는 게 아니라 Organization을 사용하는 경우는 Organization에서 설정해야 한다.)
이제 Actions가 작동은 하는데 바로 실패한다.
Error: Input required and not supplied: token
secrets에 등록해 놓은 GIT_TOKEN을 못 가져오는 것 같다.
3. 실마리가 보인다!
그래서?
- 여기서 근본적인 의문이 생겼다. Fork를 한 곳에서 PR을 요청했을 때 secrets를 못 가져오는 게 맞나? (그렇지만 나의 계정엔 ADMIN 권한이 있는데..?)
- ADMIN 권한이 있는 계정에서도 secrets를 못 가져오는 게 맞나? - 근데 생각해 보면 보안상으로도 누구나 할 수 있는 Fork단에서도 Actions가 잘 작동하면 보안상으로 위협이 될 것 같긴 하다.
혹시나 이거에 대해 아시는 내용이 있다거나 저의 추측이 틀렸다면 댓글을 달아주세요. 🙏
우선은 곧 public으로 바꿀 Repository이고 오픈소스로 기여할 프로젝트는 아니기 때문에 Fork를 못하게 다시 막고 PR은 main에서 branch를 파고 하기로 했다.
마음이 불편해서 마지막까지 테스트
12/03 새로운 시도!
혹시나 "포크 된 레포에서 시크릿을 설정하면 되지 않을까?"라는 추천을 받아서 해봤는데 안 된다..
12/06 또 새로운 시도, 드디어 성공?!
12/3에 했던 포크 된 레포에서 시크릿을 설정하는 게 반은 맞았던 것이었다..!
포크 된 레포에서 시크릿을 설정하고, " Run workflows from fork pull requests"도 체크해 주고! 마지막으로
관련 글을 찾아보다가 30일로 안 해서 삽질했다는 글을 봤던 기억이 있어서 30일로 설정한 토큰을 줬는데?! 성공했다..
(너무 여러 개를 건드려서 이게 확실한지는 정확하게 확신할 순 없지만 맞는 것 같다. 그 글을 찾고 싶었는데 너무 많은 방문기록 때문에 ㅠㅠ)
실패에 대한 workflows를 더 추가해서 다시 난관에 부딪혔다.
...
- name: 🍀 테스트 결과 Report
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: 'build/test-results/**/*.xml'
- name: 🍀 테스트 실패 Comment
uses: mikepenz/action-junit-report@v3
if: always()
with:
report_paths: 'build/test-results/test/TEST-*.xml'
- name: 🍀 테스트 실패시 슬랙 알림
if: failure()
uses: rtCamp/action-slack-notify@v2
env:
SLACK_CHANNEL: ${{ secrets.SLACK_GIT_ACTIONS_CHANNEL_NAME }}
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: '테스트 실패: ${{ github.repository }}'
SLACK_TITLE: '럭키즈 서버 PR 테스트 실패 알림 🍀'
SLACK_USERNAME: GitHub Actions
SLACK_WEBHOOK: ${{ secrets.SLACK_GIT_ACTIONS_WEBHOOK_URL }}
우선 이렇게 테스트 실행 후에 3개의 flow들을 추가했다.
그리고 실행해 봤는데 아래와 같이 에러가 떴다. `테스트 결과 Report`를 실행할 때 쓰기 권한이 없는 것 같다.
Annotations
1 error and 1 warning
test
❌ Failed to create checks using the provided token. (HttpError: Resource not accessible by integration)
test
⚠️ This usually indicates insufficient permissions. More details: https://github.com/mikepenz/action-junit-report/issues/23
이거에 대한 해결방안은 우선 `checks: write`를 추가해 주고 "Send write tokens to workflows from fork pull requests."를 체크해 주는 것이다.
name: Java CI with Gradle
on:
pull_request:
types: [ opened, reopened, synchronize ]
branches: [ "main" ]
permissions:
contents: read
checks: write # 추가
jobs:
test:
runs-on: ubuntu-latest
...
물론 이렇게 권한을 많이 주면 줄수록 보안에 대한 걱정을 해야 한다. 특히 public으로 공개한다면 더욱더 신경을 써야 한다. fork를 지정된 인원만 되게 하거나 다른 제한을 둘 필요가 있다.
결론
최종 `ci.yml` 파일
name: Java CI with Gradle
on:
pull_request:
types: [ opened, reopened, synchronize ]
branches: [ "main" ]
permissions:
contents: read
checks: write
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: 🍀 서브모듈 추가
uses: actions/checkout@v3
with:
token: ${{ secrets.GIT_TOKEN }}
submodules: true
- name: 🍀 JDK 17 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🍀 gradlew 실행 권한 설정
run: chmod +x gradlew
- name: 🍀 비밀 설정 파일 복사
run: ./gradlew copySecret
- name: 🍀 테스트 진행
env:
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }}
PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
run: ./gradlew test
- name: 🍀 테스트 결과 Report
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: 'build/test-results/**/*.xml'
- name: 🍀 테스트 실패 Comment
uses: mikepenz/action-junit-report@v3
if: always()
with:
report_paths: 'build/test-results/test/TEST-*.xml'
- name: 🍀 테스트 실패시 슬랙 알림
if: failure()
uses: rtCamp/action-slack-notify@v2
env:
SLACK_CHANNEL: ${{ secrets.SLACK_GIT_ACTIONS_CHANNEL_NAME }}
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: '테스트 실패: ${{ github.repository }}'
SLACK_TITLE: '럭키즈 서버 PR 테스트 실패 알림 🍀'
SLACK_USERNAME: GitHub Actions
SLACK_WEBHOOK: ${{ secrets.SLACK_GIT_ACTIONS_WEBHOOK_URL }}
- Fork 된 상태에서 CI 테스트 자동화를 하고 싶다면
- "Setting > Actions > General > Run workflows from fork pull requests"부분 잘 체크하기
- yml파일 권한 잘 확인하기 (문법 오류도 잘 확인하기)
- 그렇지만 권한을 많이 늘렸기 때문에, 보안과 권한의 균형을 잘 고려하는 게 좋을 것 같다.
최종 성공 🤣
12/07 한 발 남았다.
Fork 된 메인에서 판 branch에서 올린 PR에서는 내가 의도한 대로 잘 작동했다. 그렇지만 이제 진짜 잘 될 것이라고 생각했는데 저렇게 오른쪽 이미지를 보면 테스트 결과 Report에서 에러가 난다.
// 주요 에러 내용
Request POST /repos/luck-kids/luck-kids-server/issues/61/comments failed with 403: Forbidden
2023-12-07 00:49:22 +0000 - github.GithubRetry - INFO - Request POST /repos/luck-kids/luck-kids-server/issues/61/comments failed with 403: Forbidden
...
File "/usr/local/lib/python3.8/site-packages/github/GithubRetry.py", line 179, in increment
raise Requester.createException(response.status, response.headers, content) # type: ignore
github.GithubException.GithubException: 403 {"message": "Resource not accessible by integration", "documentation_url": "https://docs.github.com/rest/issues/comments#create-an-issue-comment"}
권한에러가 난다. Fork 된 곳에서 권한을 이렇게 다 설정해서 다 해결했는데 왜 안 될까..... 추측으로는 아마 Fork 된 곳에서는 아예 코멘트를 쓸 접근조차 실행 안 한 것 같은데 찐 main에서는 코멘트를 작성하려다 보니 권한 문제가 발생한 것 같다. 이것저것 권한을 줘봤는데 에러가 계속 나서 코멘트가 꼭 필요한 것은 아니라 yml파일에서 삭제했다.
찐 최종 `ci. yml` 파일
name: Java CI with Gradle
on:
pull_request:
types: [ opened, reopened, synchronize ]
branches: [ "main" ]
permissions:
contents: read
checks: write
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: 🍀 서브모듈 추가
uses: actions/checkout@v3
with:
token: ${{ secrets.GIT_TOKEN }}
submodules: true
- name: 🍀 JDK 17 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 🍀 gradlew 실행 권한 설정
run: chmod +x gradlew
- name: 🍀 비밀 설정 파일 복사
run: ./gradlew copySecret
- name: 🍀 테스트 진행
env:
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }}
PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
run: ./gradlew test
- name: 🍀 테스트 결과 Report
uses: mikepenz/action-junit-report@v3
if: always()
with:
report_paths: 'build/test-results/test/TEST-*.xml'
- name: 🍀 테스트 실패시 슬랙 알림
if: failure()
uses: rtCamp/action-slack-notify@v2
env:
SLACK_CHANNEL: ${{ secrets.SLACK_GIT_ACTIONS_CHANNEL_NAME }}
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: '테스트 실패: ${{ github.repository }}'
SLACK_TITLE: '럭키즈 서버 PR 테스트 실패 알림 🍀'
SLACK_WEBHOOK: ${{ secrets.SLACK_GIT_ACTIONS_WEBHOOK_URL }}
아 그리고 위 글의 토큰을 발행하는 부분에서 30일로 해야 할 것 같다는 부분이 있는데 그것도 기한 없는 것으로 수정해서 테스트해 봤는데 잘 되었다 ㅎㅎ (30일마다 refresh 안 해도 될 것 같다.)
언제나 잘못된 설명이나 부족한 부분에 대한 피드백은 환영입니다🤍