ADVENT CALENDAR

Windows と MacOS 向けの配布用アーカイブファイルを CI で作るテンプレート

By wraikny

これは AmusementCreators 2022 アドベントカレンダー の 15日目の記事です。

大遅刻してすみません。(2022/12/16 3:36 現在)

概要

作成したアプリケーションを配布するのに、

  • Windows用: exeファイル作成して、zipに入れて配布。
  • macOS用: appを作成して、dmgに入れて配布。

したいけど面倒ですよね。 それらをまとめてCIでやるのが今回の内容です。

参考リポジトリ

wraikny/Altseed2Template - wraikny

.NET + Altseed2 向けのリポジトリですが、アーカイブ作る箇所はそれとは無関係なのでお気にせず。

こちらのリポジトリの build.fsx に処理を記述して .github/workflows/release.yml から実行しています。 ビルドスクリプトはF#で記述するFAKEを使っているので、雰囲気で読んで下さい。

Windows

やるだけ。

publish/win-x64以下にビルドした実行ファイルがあることを前提とする。

Target.create "Dist.win" (fun _ ->
  (* パス *)
  // zip化する一時ディレクトリ
  let tempDirToZip = $"publish/temp/win-x64/%s{ProjectName}"
  // zip名
  let targetZipName = $"publish/output/%s{WindowsZipName}"

  (* クリーン *)
  Trace.tracefn "Cleaning"
  File.delete targetZipName
  Directory.delete tempDirToZip

  (* ディレクトリ作成 *)
  Trace.tracefn "Ensuring"
  Directory.ensure tempDirToZip
  Directory.ensure "publish/output"

  (* ファイルのコピー *)
  Trace.tracefn "Copying files"
  Shell.cp_r $"dist/contents" $"%s{tempDirToZip}/"
  Shell.cp_r "publish/win-x64" tempDirToZip

  (* zip作成 *)
  Trace.tracefn "Creating zip"
  Zip.zipDirectory tempDirToZip targetZipName
)

build.fsx#L183-L213

MacOS

dist/App に app 化するディレクトリの概形を作ってあるため、これらをコピーしてきてファイルを追加する形で作成する。

その後、hdiutilコマンドを実行してdmgファイルを作成する。

publish/osx-x64以下にビルドした実行ファイルがあることを前提とする。

Target.create "Dist.osx" (fun _ ->
  // app化する一時ディレクトリ
  let tempDirToApp = $"%s{tempDirToDmg}/%s{ProjectName}.app"
  // 実行ファイルを置くディレクトリ
  let scriptDir = $"%s{tempDirToApp}/Contents/MacOS"
  // app が呼び出す特別なシェルスクリプトのパス
  let scriptPath = $"%s{scriptDir}/script.sh"
  // dmg化する一時ディレクトリ
  let tempDirToDmg = $"publish/temp/osx-x64/%s{ProjectName}"
  // dmg名
  let targetDmgName = $"publish/output/%s{MacOSDmgName}"

  (* クリーン *)
  Trace.tracefn "Cleaning"
  Directory.delete tempDirToApp
  Directory.delete tempDirToDmg
  File.delete targetDmgName

  (* ディレクトリ作成 *)
  Trace.tracefn "Ensuring"
  Directory.ensure tempDirToApp
  Directory.ensure "publish/output"

  (* ファイルのコピー *)
  Trace.tracefn "Copying files"
  Shell.cp_r $"dist/contents" $"%s{tempDirToDmg}/"
  // dist/App に app の構造を作成済みなので、コピーしてくる
  Shell.cp_r "dist/App" tempDirToApp

  (* script.sh 作成 *)
  Trace.tracefn "Creating script.sh"
  // スクリプトの内容を書き込む
  $"""#!/bin/bash
cd `dirname $0`
./%s{AssemblyName}
"""
  |> File.writeString false scriptPath

  Shell.cp_r "publish/osx-x64" scriptDir

  (* dmg作成 *)
  Trace.tracefn "Creating dmg"
  // hdiutil コマンドを叩いて dmg を作成する
  shell
    None
    "hdiutil"
    $"create %s{targetDmgName} -volname \"%s{ProjectName}\" -srcfolder \"%s{tempDirToDmg}\""
)

build.fsx#L215-L264

ちなみに、FAKEからchmod +x script.shみたいにするとなぜか実行が終わらなくなったため、script.shは実行権限を付けた状態でコミットしてあります。

参考

appの構造とかhdiutilの使い方とかはここ

GitHub Actions

ターゲット

OS毎にFAKEのターゲットを変えている。

os: [windows-latest, macOS-latest]
include:
  - os: windows-latest
    publish-target: publish.win
    dist-target: dist.win
  - os: macOS-latest
    publish-target: publish.osx
    dist-target: dist.osx

release.yaml#L12-L19

アップロード

softprops/action-gh-release を使うと、ファイルをRelease欄にアップロードできる。

- name: Release
  uses: softprops/action-gh-release@v1
  with:
    files: publish/output/*
    prerelease: ${{ contains(github.ref, 'beta') }}
    draft: true
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

release.yaml#L58-L65

SHARE THIS POST