actions/upload-artifact@v2 は /tmp で使わないほうがいい

雑記。

Github Actions で成果物を永続するためのアクション actions/upload-artifact@v2 の落とし穴について。

TL; DR

  • 執筆時点で actions/upload-artifact@v2 は指定したファイルをアップロードすることはできない
  • Mac/tmp/private/tmp へのシンボリックリンクとなっていることに注意

以下の時点の情報

Example

以下のワークフローについて考える

on: [push]

jobs:
  upload-artifact:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
    - name: make aritfact
      run: |
        echo hello > /tmp/result.txt
    - name: upload
      uses: actions/upload-artifact@v2
      with:
        name: result-${{ matrix.os }}
        path: /tmp/result.txt

このワークフローは /tmp/result.txt を生成し、それを actions/upload-artifact@v2 を用いてビルドの成果物ととして保存する。また、このワークフローは Linux, Mac 両方でビルドを実行する。

なんてことのないジョブ定義だが、いざ実行すると Mac のビルドのみが upload ステップで失敗する。ログは以下の通り:

With the provided path, there will be 1 files uploaded
##[error]Provided rootDirectory /tmp is not a valid directory

原因

上述のエラーを生成するのは下記の箇所:

これによれば、actions/upload-artifact@v2 は指定したファイルのディレクトリにあたるパスを fs.lstatSync で確認し、ディレクトリでない場合にエラーとなる。そして、Mac における /tmp/private/tmp へのシンボリックリンクとなっているため、エラー終了する。

対策

アップロードしたいファイルの直接のディレクトリがシンボリックリンクでなければいい。例えば /tmp/artifact を作成するとか、ワークツリー内に一時ディレクトリを作成するなどで簡単に回避できる。

上記のワークフローの場合、以下のようにすればいい:

on: [push]

jobs:
  upload-artifact:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
    - name: make aritfact
      run: |
        mkdir /tmp/artifact
        echo hello > /tmp/artifact/result.txt
    - name: upload
      uses: actions/upload-artifact@v2
      with:
        name: result-${{ matrix.os }}
        path: /tmp/artifact/result.txt

(ところで fs.lstatsSync() の代わりに fs.statSync() を使うことでもこの問題は発生しない気がする。なにか理由はあるのだろうか?)


なおこの問題は Ruby の日本語ドキュメントに PR を出す過程でぶつかった。当初は Time#gmt_offset のサンプルを直して PR を送ったところ CI でコケてしまい、せっかくなのでとそっちも直していたら上述の問題も含め色々大変だった。