Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

GitHub Actions 最近のやらかし一覧

FOSS開発で細かいやらかしを積み上げてきたのでまとめる。

テストの失敗原因レポートをartifactとしてアップロードしそこねる

actions/upload-artifactを使ってテストレポートをartifactとしてアップロードする際、以下の書き方だと失敗する。

# bad
    - run: |
      ./gradlew test --no-daemon --stacktrace
    - uses: actions/upload-artifact@v2
      with:
        name: reports
        path: build/reports

これはテストが失敗した時点で後続のstepsが実行されなくなるため。明示的に失敗時でもアップロードされるように指示する必要がある。

# bad
    - run: |
      ./gradlew test --no-daemon --stacktrace
    - uses: actions/upload-artifact@v2
      if: always() # this config is necessary to upload reports in case of build failure
      with:
        name: reports
        path: build/reports

forkからのPRではGITHUB_TOKENを除くsecretsを参照できない

secretsの存在を前提にしているコードがあると、forkからPRをもらったときにビルドが通らなくなる。

# bad
  - name: Decrypt file
    env:
      GPG_SECRET_PASSPHRASE: ${{ secrets.GPG_SECRET_PASSPHRASE }}
    run: |
      gpg --quiet --batch --yes --decrypt --passphrase="$GPG_SECRET_PASSPHRASE" --output decrypted encrypted
      # -> gpg: missing argument for option "--passphrase="

後述する方法でsecretsが空かどうか確認する必要がある。

if では $VAR で環境変数を参照できない

if で書くのはbashじゃくてexpressionなので、runに書くのと同じノリでやると失敗する。

# bad
    - name: Run SonarQube Scanner
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }}
      if: ${{ $SONAR_LOGIN != "" }}
      run: |
        ./gradlew sonarqube -Dsonar.login=$SONAR_LOGIN --no-daemon

正しくはenvコンテキストを参照する(なお${{ .. }} で囲むのは必須ではない)か、

# good
    - name: Run SonarQube Scanner
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }}
      if: env.SONAR_LOGIN != ""
      run: |
        ./gradlew sonarqube -Dsonar.login=$SONAR_LOGIN --no-daemon

bashで統一して読みやすくしたいなら run の中で判定する。

# good
    - name: Run SonarQube Scanner
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }}
      run: |
        if [ "$SONAR_LOGIN" != "" ]; then
          ./gradlew sonarqube -Dsonar.login=$SONAR_LOGIN --no-daemon
        fi

gradleで環境変数があるときだけ特定タスクを実行する場合は、こういう書き方もできるらしい。シンプル。

    - name: Run SonarQube Scanner
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }}
      run: |
        ./gradlew spotlessCheck build smoketest ${SONAR_LOGIN:+sonarqube} --no-daemon -Dsonar.login=$SONAR_LOGIN