Step의 Fail을 제어하는 것이 필요한 이유
테스트를 돌렸는데 테스트가 Fail 되었을 때 Test 리포트를 업로드 하는 Step이 수행되어야 하는데 수행되지 않는다면 어떻게 될까? 테스트를 돌린 것 자체가 의미가 없어진다. 테스트가 Fail 되면 Test 리포트가 업로드 되어야 한다. 즉, 특정한 Step이 Fail 되더라도 다른 Step이 진행되어야 할 수 있다.
Job을 만들다 보면 위와 같은 상황을 자주 마주한다. 이번 글에서는 위 상황을 제어하는 방법에 대해 알아본다. 먼저 문제 상황을 만들어보자
문제 상황 만들기
이번 글에서 다룬 문제 상황은 바로 안드로이드에서 테스트를 돌렸는데 실패하는 경우이다.
Workflow 파일 만들기
app 모듈에 대해 testDebug Task를 실행하고 테스트 리포트를 upload-artifact를 통해 업로드한다.
name: Handle Failure - Not Handled
on:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Check out Repository
uses: actions/checkout@v3
- name: set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# Test with Gradle
- name: Test with Gradle
run: ./gradlew :app::testDebug
# Test Report Upload
- name: Upload Test
uses: actions/upload-artifact@v3
with:
name: test-report
path: app/build/reports/tests/testDebugUnitTest/index.html
Test 실패하도록 만들기
위 동작을 확인하기 위해서 실패하는 간단한 테스트를 만들도록 하자.
internal class GitHubActionTest {
@Test
fun testSuccess() {
assert(false)
}
}
문제 상황 실행해보기
여기까지 만들고 GitHub에 올려서 Workflow를 실행해보자. 그러면 Test with Gradle이 실패하자 Upload Test는 생략되는 것을 확인할 수 있다.
문제 상황 제어하기
문제가 발생한 이유
문제가 발생한 이유는 step은 무조건 순차적으로 실행되고 이전 step이 fail되면 이후 step은 진행하지 않도록 설정되어 있기 때문이다. 이를 해결하기 위해 step이 fail 되더라도 성공된 것으로 설정하는 프로퍼티가 바로 continue_on_error이다. 문서는 아래 링크에서 확인 가능하다.
continue_on_error 사용해 문제 상황 제어하기
위의 Test with Gradle Step에 continue_on_error: true 를 추가한 후 Workflow을 다시 실행해보자
- name: Test with Gradle
continue-on-error: true
run: ./gradlew :app::testDebug
그러면 Test with Gradle이 Fail 되더라도 Upload Test가 정상적으로 동작하는 것을 확인할 수 있다.
continue_on_error의 한계
하지만 continue_on_error 을 제어하면 실패 하더라도 표시가 나지 않는다. 또한 Step의 error가 무시되어서, 이후의 모든 Step이 진행된다. 하지만 실무에서 CI를 만들 때 일반적인 유즈케이스는 애러가 나면 애러와 관련된 로깅을 하거나 리포트만 올리는 것일 것이다. 따라서 continue_on_error를 사용하는 것은 문제가 있다.
이후에 만약 여러 Step이 있는데 Fail 시 특정 Step만 실행하고 싶다면 어떻게 해야할까? 바로 if 문과 GitHub Action에서 제공해주는 failure() 메서드를 사용해 위의 문제 상황을 제어하는 것이다.
if와 failure사용해 이전 step이 실패해도 실행되도록 만들기
위에서 Upload Test가 동작하지 않았던 이유는 아래 코드에 이전 코드가 success될 때만 실행된다는 메서드가 숨어있기 때문이다.
- name: Upload Test
uses: actions/upload-artifact@v3
with:
name: test-report
path: app/build/reports/tests/testDebugUnitTest/index.html
즉, 위 코드는 아래 코드와 같이 동작한다. success() 이전 Step이 모두 성공했을 때만 true를 반환하는 GitHub Action 메서드이다. 위에서 continue_on_error: true로 바꾸면 Test with Gradle Step이 실패하더라도 성공된 것으로 만들기 때문에 아래의 if 문을 통과한 것이다.
- name: Upload Test
if: success()
uses: actions/upload-artifact@v3
with:
name: test-report
path: app/build/reports/tests/testDebugUnitTest/index.html
따라서 이전 상황이 실패하더라도 해당 Step은 실행되어야 한다면, if: failure()을 추가해 명시적으로 위에 동작을 바꾸면 된다.
- name: Upload Test
if: failure()
uses: actions/upload-artifact@v3
with:
name: test-report
path: app/build/reports/tests/testDebugUnitTest/index.html
이렇게 바꾼 후 Workflow를 다시 실행해보면 Test with Gradle Step이 실패하더라도 Upload Test는 제대로 실행되는 것을 확인할 수 있다.
정리
이번 글에서는 특정 Step이 Fail 되었을 때 다른 Step을 제어하는 다양한 방법에 대해 알아보았다. 다음글에서는 특정 Step이 Fail 되었는지 체크 후 실행하는 방법에 대해 알아볼 것이다.