debianパッケージを作るGitHubActionsとrpmパッケージを作るGitHubActionsを作った

- debianパッケージを作るGitHubActionsとrpmパッケージを作るGitHubActionsを作った
- 使い方と仕組みを説明します

# なぜ作ろうと思ったか

GitHub Actionsからサクッとdebパッケージやrpmパッケージを作成してアップロードしたかったからです。

debパッケージもrpmパッケージも、作成するのに専用のツールが必要で、環境を整えるのが若干手間だと感じていました。
それならGitHubActionsのDockerベースアクションを使えば、CI環境を汚さずパッケージを作成できるのでは、と考えました。

既存のdebパッケージやrpmパッケージを作成するためのActionsも探していろいろ試した。
しかし直感的にわかりやすく使えるものが見つからなくて、仕方なく自分で作ることにしました。

debパッケージやrpmパッケージを作成するのは初めてだったので、いろんな記事を参考にしました。
debパッケージ作成に際しては以下を参考にしました。

- [Debian packaging for the modern developer - GitHub](https://github.com/phusion/debian-packaging-for-the-modern-developer)
- [Debian新メンテナガイド](https://www.debian.org/doc/manuals/maint-guide/)

また、rpmパッケージ作成に際しては以下の記事を参考にしました。

- [RPMパッケージを作ってみよう④SPECファイルから自作する方法](https://www.indetail.co.jp/blog/12550/)
- [SPEC ファイルを書いて RPM をビルドしてみた](https://momijiame.tumblr.com/post/32458077768/spec-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6-rpm-%E3%82%92%E3%83%93%E3%83%AB%E3%83%89%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F)

# ソースコード

ソースコードは以下。

- https://github.com/jiro4989/build-deb-action
- https://github.com/jiro4989/build-rpm-action

Marketにも公開しています。

- https://github.com/marketplace/actions/build-deb-action
- https://github.com/marketplace/actions/build-rpm-action

# 使い方

前述のMarketのREADMEにも書いているのですが、以下のように使います。

## build-deb-action

```yml
name: build

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: create sample script
        run: |
          mkdir -p .debpkg/usr/bin
          mkdir -p .debpkg/usr/lib/samplescript
          echo -e "echo sample" > .debpkg/usr/bin/samplescript
          chmod +x .debpkg/usr/bin/samplescript
          echo -e "a=1" > .debpkg/usr/lib/samplescript/samplescript.conf
      - uses: jiro4989/build-deb-action@v2
        with:
          package: samplescript
          package_root: .debpkg
          maintainer: your_name
          version: ${{ github.ref }} # refs/tags/v*.*.*
          arch: 'amd64'
          desc: 'this is sample package.'
```

## build-rpm-action

```yml
name: build

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: create sample script
        run: |
          mkdir -p .rpmpkg/usr/bin
          mkdir -p .rpmpkg/usr/lib/testbin
          echo -e "echo hello" > .rpmpkg/usr/bin/testbin
          echo -e "echo hello2" > .rpmpkg/usr/bin/testbin2
          echo -e "a=1" > .rpmpkg/usr/lib/testbin/testbin.conf
          chmod +x .rpmpkg/usr/bin/*

      - uses: jiro4989/build-rpm-action@v2
        with:
          summary: 'testbin is a test script'
          package: testbin
          package_root: .rpmpkg
          maintainer: jiro4989
          version: ${{ github.ref }} # refs/tags/v*.*.*
          arch: 'x86_64'
          desc: 'test package'
```

どちらも同じような使い方をします。

`package_root`変数に指定のディレクトリ配下に、配置したコマンド、設定ファイルをインストール時に同じ場所に配置するようにdebファイル、rpmファイルを作ります。

どういうことか、というと
`<package_root>/usr/bin/samplescript`ディレクトリにスクリプトを配置してbuild-deb-actionを実行してdebファイルを作ると、`dpkg -i`でインストールした時`samplescript`ファイルは`/usr/bin`ディレクトリにインストールされます。

# 仕組み

## パッケージ情報の埋め込み

どちらもActionsの入力変数 (input)にパッケージ情報と、パッケージに含めるファイルのパスを指定します。

渡されたinput変数は、build-deb-actionもbuild-rpm-actionも、それぞれのパッケージに必須のパッケージ情報を記述するファイルに埋め込まれます。
debパッケージでは `DEBIAN/control` ファイルに、rpmパッケージではspecファイルに埋め込まれます。

Actionsではユーザ入力を埋め込むためのテンプレートファイルを保持しており、ユーザ入力でテンプレートを置換します。
ユーザ入力を埋め込んだ後、所定のパスに配置し、パッケージを作成するコマンドを実行して各種パッケージを作成しています。

置換処理にはなんとなくNimを使いました。正直Nimである必要はなかったです。コンパイラのインストールに時間がかかるので、そのうちもっと早く処理が終わる何かに置き換えるかもしれません。

置換処理には何使っても良かったのですが`sed`は使えません。ユーザ入力を`sed`の置換式に使うと、`sed`のセパレータ文字がユーザ入力に含まれていた時に式不正でエラーになるからです。

```bash
INPUT=1/3
echo test | sed "s/test/$INPUT/g" # エラーになる
```

## バージョン番号処理

バージョン番号はGitHubのrefを使う前提にしています。
以下の処理でバージョン番号を加工しています。

```bash
INPUT_VERSION="$(echo "$INPUT_VERSION" | sed -E "s,^refs/tags/,,")"
```

前述の通り、どちらのワークフローもActionsの起動トリガーに`on.push.tags`を指定しています。
この時`github.ref`は`refs/tags/`で始まり、その後に`git tag`で設定したタグ名が続きます。
この入力を受取る前提で実装しています。

# 欠点

欠点としては、かなり単純なdebパッケージ、rpmパッケージしか作れない点です。
debパッケージもrpmパッケージも、インストール処理の前後にスクリプトを呼び出したりできるのですが、そこは特にサポートしていません。

「とにかく簡単なインタフェースで、コマンド、設定ファイルを所定の場所に配置できれば良い」としています。

一応こちらのissuesの通り、Actionsの作りを知っていればpostinstしたりできます。
https://github.com/jiro4989/build-deb-action/issues/20
が、推奨はしていないです。Actionsの作りを知っていないとできないやり方ですし。

# 感想

サクッと作れるようになって満足です。
すでにいくつかの自分のリポジトリでも導入しており、自作のツールの公開に大いに役立てています。

- https://github.com/jiro4989/nimjson
- https://github.com/jiro4989/textimg
- https://github.com/jiro4989/relma

# まとめ

以下の内容について書きました。

- debianパッケージを作るGitHubActionsのbuild-deb-actionの説明をしました
- rpmパッケージを作るGitHubActionsのbuild-rpm-actionの説明をしました
- どちらもディレクトリ構造を配布先に合わせるだけです

自作ツール公開の一助となれば幸いです。