すぎしーのXRと3DCG

主にXR, Unity, 3DCG系の記事を投稿していきます。

【GitHub Packages for Unity】限定配布も可能, GitHub Packages で Unity アセット配布

f:id:tsgcpp:20210731231035j:plain

概要

今回はUnity向けにGitHub Pakcagesでアセットを配布する方法を紹介します。

社内やチーム内でUnityのパッケージを限定配布できたりもするので、
良かったら活用してみてください!

記事の最後にサンプルを記載しています。

記事内でのキーワード略称

  • GitHub Packages -> GHP
  • GitHub Actions -> GHA
  • Unity Package Manager -> UPM

GitHub Packages について

簡単に言えば「パッケージ公開サービス」でGitHubから提供されています。

github.com

様々なパッケージ形式に対応

  • npm, gradle, docker container などあらゆるパッケージ形式に対応

docs.github.com

GitHubの仕組みでパッケージのアクセス権限を制御可能

Publicは無料、Privateは従量課金制

  • Publicパッケージは無料で配布可能
  • Privateパッケージでも Free, Team, Enterpriseそれぞれにも無料枠有り
    • ストレージ枠とデータ転送枠が使用されます
  • billing ページにて使用状況を確認可能
    • Data transfer out がデータ転送枠

docs.github.com

GitHub Actions 経由でリポジトリからアップロード

  • Repository -> Actions -> Packages の流れでアップロード

今回は GHA での簡単なアップロード例を紹介します


アップロードまでの流れ

まずはパッケージをアップロードするまでを紹介します!

Package Manager形式でアセットを用意

  • UPM向けにアセットを用意
    • アセット + package.json
  • meta ファイルも必ず生成
    • UPMで必須、存在しないと取り込んだときエラー

サンプルコードにも簡単なパッケージ用アセットを4つ用意しています。

f:id:tsgcpp:20210731173145p:plain

package.json の name について

  • nameの推奨文字は a-z0-9.-_大文字は非推奨
  • com.<org>.<name>(.<sub name>) のようにドメインを含めること推奨
    • UPMで使用する際の Scoped Registriesドメイン部分でアクセス先を制御するため
    • jp.co, jp.ne などでも可
com.tsgcpp.unitygithubpackageexample.integration
com.tsgcpp.tscubemapgenerator
jp.co.tsgcpp.groupname.categoryname

package.json について

  • publishConfig 項目が必須
    • UserもしくはOrganizationの前には @ が必須
    • すべて小文字 (アカウント名がSampleAccの場合は@sampleacc)
    • パッケージをアップロード先として使用される
    • 余談: GitHub上ではアカウント名は tsgcppTsGCpP も同じ扱い
  • unity 項目もUnity向けのため必須
  • それ以外は通常のUPMと同様
"publishConfig": {
        "registry": "https://npm.pkg.github.com/@<user or organization>"
    }

サンプルの全体は以下となります

{
    "name": "com.tsgcpp.unitygithubpackageexample.integration",
    "version": "1.2.3",
    "displayName": "Integration Package Example",
    "description": "Integration Package Example for UnityGithubPackageExample",
    "unity": "2019.4",
    "keywords": [
        "tsgcpp",
        "main"
    ],
    "license": "UNLICENSED",
    "dependencies": {
        "com.tsgcpp.unitygithubpackageexample.script": "2.3.4",
        "com.tsgcpp.unitygithubpackageexample.prefab": "3.4.5"
    },
    "author": {
        "name": "tsgcpp",
        "url": "https://github.com/tsgcpp"
    },
    "scripts": {
        "test": "exit 0"
    },
    "repository": {
        "type": "git",
        "url": "git+https://github.com/tsgcpp/UnityGithubPackageExample.git"
    },
    "bugs": {
        "url": "https://github.com/tsgcpp/UnityGithubPackageExample/issues"
    },
    "publishConfig": {
        "registry": "https://npm.pkg.github.com/@tsgcpp"
    }
}

アップロード用アクションを定義

  • GHA の Yaml を定義
    • サンプルでは .github/workflows/release-package.yml に定義
  • packagePath にパッケージの相対パスを指定(複数可)
  • actions/setup-node のstepは必須
  • npm publish でパッケージをアップロード

せっかくGHAを使うので、アップロード処理前にテストも組み込みましょう!

name: Unity Example Packages Publish

# release tagを発行時にアップロード
on:
  release:
    types: [created]

jobs:
  # Unity Test Runner の実行 (GameCIのunity-test-runnerを利用)
  test:
    name: Test in ${{ matrix.testMode }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        projectPath:
          - .
        unityVersion:
          - 2020.3.14f1
        testMode:
          - all
    steps:
      - uses: actions/checkout@v2
        with:
          lfs: true
      - uses: game-ci/unity-test-runner@v2
        id: tests
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
        with:
          unityVersion: ${{ matrix.unityVersion }}
          projectPath: ${{ matrix.projectPath }}
          testMode: ${{ matrix.testMode }}
          artifactsPath: ${{ matrix.testMode }}-artifacts
          githubToken: ${{ secrets.GITHUB_TOKEN }}
          checkName: ${{ matrix.testMode }} Test Results
      - uses: actions/upload-artifact@v2
        if: always()
        with:
          name: Test results for ${{ matrix.testMode }}
          path: ${{ steps.tests.outputs.artifactsPath }}

  # アップロード処理の実施
  publish:
    needs: test
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        packagePath:
          - ./Assets/Plugins/Script
          - ./Assets/Plugins/Material
          - ./Assets/Plugins/Prefab
          - ./Assets/Plugins/Integration
    permissions:
      packages: write
      contents: read
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 12
          registry-url: https://npm.pkg.github.com/
      - run: npm publish ${{ matrix.packagePath }}
        env:
          NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
  • 余談 .npmrc はUnityの場合は不要(node.jsプロジェクトではないため)

パッケージのアップロード

  • masterにアセット, package.json, GHAのYamlを追加
  • リポジトリの Releases ページの Draft a new release より release tag を発行
    • release tagの発行がアクションのトリガーのため
  • アクションが正常に完了すると Packages に登録される
    • 初回のみ反映されるまで若干時間がかかる可能性有り

f:id:tsgcpp:20210731212117p:plain

サンプルリポジトリは記事の最後に記載しています。


UPM経由でのパッケージのインストール

次はアップロードされたパッケージのUPM経由でのインストール方法を紹介します!

アクセストークンの発行

アクセストークンはAPI経由などでGitHubのコンテンツにアクセスするためのトークンになります。

  • GHPのアクセスにはアクセストークンが必要
  • public, private にどちらでも必要

アクセストークンの注意点

発行する前にアクセストークンの注意点についてです。

  • トークンの発行はパッケージにアクセスする本人のアカウントで実施
  • 発行したトークンは第三者へは非公開にし、基本的に本人のみ使用する
  • (任意)期限 (Expiration) を指定して定期的に更新 (セキュリティ観点)

f:id:tsgcpp:20210731213012p:plain

GitHub上でアクセストークンを発行

f:id:tsgcpp:20210731222321j:plain

  • Note 項目に任意の名前を指定 (ex: Package Access)
  • (任意) 期限(Expiration)を設定
  • read:packages をチェック
    • パッケージアクセスのみであれば read:packages のみで問題有りません

f:id:tsgcpp:20210731213813p:plain

  • ページ下部の "Generate token" ボタンで発行
  • 発行されたトークンをコピー
    • ページを閉じると再確認できません!

f:id:tsgcpp:20210731214220j:plain

.upmconfig.toml ファイルを作成

[npmAuth."https://npm.pkg.github.com/@<user or organization>"]
token = "<ACCESS TOKEN>"
alwaysAuth = true

以下は記入イメージ

[npmAuth."https://npm.pkg.github.com/@tsgcpp"]
token = "ghp_hogehogehogehogehoge"
alwaysAuth = true

これでUnityのパッケージインストール時にアクセストークンが使用されます

Unity で Scoped Registries とインストールパッケージを設定

  • Packages/manifest.json をエディタで開く
  • scopedRegistries 項目に記載
    • url には https://npm.pkg.github.com/@<user or organization>
    • scopesドメイン部分を記載

以下は記入例で、com.tsgcppとついたパッケージは GHP の @tsgcpp 経由で取得されます。

{
  "scopedRegistries": [
    {
      "name": "tsgcpp public",
      "url": "https://npm.pkg.github.com/@tsgcpp",
      "scopes": [
        "com.tsgcpp"
      ]
    }
  ],
  "dependencies": {
    "com.tsgcpp.unitygithubpackageexample.integration": "1.2.3",
    ...
  }
}

補足: com.tsgcpp.unitygithubpackageexample.integration (サンプルパッケージ) の依存グラフ について

  • 今回 integration, script, prefab, material のパッケージは以下の依存関係
  • com.tsgcpp.unitygithubpackageexample.integration のみの取り込みで他3パッケージも取得

f:id:tsgcpp:20210731220943j:plain

インストールの確認

  • Unityエディタ上で Packages 項目を確認しましょう

f:id:tsgcpp:20210731221437p:plain


以上がGHP経由での取込までの流れとなります!

ちなみに紹介したとおりに .upmconfig.tomlmanifest.json を設定すれば、
私が用意したサンプルパッケージ (public) が取り込まれます。

残りは GHP を使用する場合のメリット、デメリットを紹介します!


GitHub PackageでUnityパッケージを配布するメリット

package.json の dependencies に依存を定義可能

  • GHPにアップロードされたパッケージは dependencies 項目で依存パッケージを指定可能
  • UPMで取り込んだ場合は依存パッケージも合わせて取り込まれる
    • Git URL 経由では難しかった依存パッケージの同時取込が可能
{
    "name": "com.tsgcpp.unitygithubpackageexample.integration",
    "version": "1.2.3",
    "displayName": "Integration Package Example",
    "description": "Integration Package Example for UnityGithubPackageExample",
    "unity": "2019.4",
    ...
    "dependencies": {
        "com.tsgcpp.unitygithubpackageexample.script": "2.3.4",
        "com.tsgcpp.unitygithubpackageexample.prefab": "3.4.5"
    },
    ...
}

Privateリポジトリでのパッケージ配布が容易

補足: Git URLでもPrivateリポジトリから取り込みは一応可能

最近のUnityではGit URL経由の場合も、専用のアクセストークンを勝手に作ってくれたりします。

ただ、アクセストークンの削除が面倒だったり、WindowsMacで動作が異なったり、
チーム内での厳密な運用には若干向かない印象があります。

GitHubアカウントの仕組みでアクセス権限を制御可能

  • GitHubManage Access でパッケージのアクセス範囲を制御可能
    • 限定配布が容易になる理由の1つ

独自のnpmレジストリが不要

  • privateな独自のregistryの作成、保守、運用が不要


GitHub PackageでUnityパッケージを配布するデメリット

Unity Package Manager のパッケージ検索機能が使用不可

  • GHP側に検索API endpoint (/-/all, /-/v1/search)が提供されていない
  • UPMでパッケージ検索が発生すると毎回エラーログが出てしまう
    • UPMウィンドウを開いたときなどに scopedRegistries に登録されたレジストリ全体で検索が実施される仕様のため

f:id:tsgcpp:20210731165326p:plain

ビルド自体には影響しません

Packages以下で displayName で表示されない

パッケージの使用自体は問題ない (と思います)

  • 原因不明、検索機能が使えないことが原因?
  • displayName 自体は認識されている
  • Add package from git URL... の場合は問題なく displayName で表示される

f:id:tsgcpp:20210731171050p:plain

f:id:tsgcpp:20210731171836j:plain


GitHub Package を使用する場合の諸注意

  • privateの場合はストレージ枠に注意
    • アップロードされたパッケージ毎にストレージ枠を消費
    • 巨大なファイルをアップロードする場合は特に注意 (3Dモデル, サウンドファイル、動画ファイルなど)
  • パッケージ削除は一応可能ですが、基本的に削除しない方針を推奨
    • 作業コストとヒューマンエラーにつながる
    • 特にパッケージが大量になったときの手作業は担当者が地獄を見ます

おサイフと相談しましょう!ご利用は計画的に!

サンプル

サンプルリポジトリ

github.com

サンプルパッケージ

github.com

サンプルパッケージ発行時のアクション

github.com

参考

forum.unity.com

雑感

GitHubにサンプルを作成してからちょっと遅れてしまいました。

今週はちょっとドタバタしていたので、今日は集中して記事にしてみました!

GHP経由の場合は検索機能がありませんが、依存パッケージを定義できたりアクセス制御もGitHubの仕組みを流用できたりで運用上もメリットがあると思います!

あと、displayNameが反映されない問題は気になるのであとでUnityに報告しておきます(公開パッケージがあったほうが報告しやすかったので)。

それでは~