ソースはここ。
何をするかというと
- gemspec の version を見て、rubygems.org に登録されているバージョンと比較
- GitHub のリポジトリに "v1.2.3" の形式のタグを生成
- gem を build し rubygems.org に push
するだけ。 普通なら Ruby で書くのだろうけど、GitHub Actions が Node.js 推しのようなのと TypeScript に挑戦してみたかったので TypeScript 製。
Dockerコンテナを起動する際に、環境変数で渡したパラメーターを使って設定ファイルを作りたいことがある。 例えばsambaにアクセスするとき、ユーザー名が foo なら許可、それ以外は不許可としたければ設定ファイルは以下のようにする。
[global] log file = /var/log/samba/%m [share] path = /mount guest ok = no valid users = foo # ユーザー foo ならアクセスを許可する
このユーザー名を可変にしたいとしよう。Docker で docker run -e USER=foo -e PASSWORD=pass ...
のようにしたいなら、以下のようになる。
FROM ubuntu:latest RUN apt update \ && apt install -y \ samba COPY samba.sh /root/ EXPOSE 139 445 CMD ["/root/samba.sh"]
#!/bin/sh # /etc/samba/smb.conf を生成する cat <<SMBCONF >> /etc/samba/smb.conf [global] log file = /var/log/samba/%m [share] path = /mount guest ok = no valid users = $USER SMBCONF # システムに foo ユーザーを追加し、foo ユーザーとしてアクセスできるようにする useradd $USER cat <<PASSWORD | passwd $USER $PASSWORD $PASSWORD PASSWORD cat <<PASSWORD | smbpasswd -a -s $USER $PASSWORD $PASSWORD PASSWORD # samba サーバーを起動する /usr/sbin/smbd -F -S --no-process-group
しかしこのファイル生成方法は、smb.conf
のテンプレートがスクリプト中にあって気持ちが悪い。
こんなとき Ruby なら ERB が使えるのだが、インストールすると依存する複数のパッケージも入ってしまうし、テンプレートを使いたいだけなのにちょっと大げさだ。
# Ubuntu 19.10 の場合 $ root@f86b2af49215:/# apt install ruby Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: ca-certificates fonts-lato javascript-common libgdbm-compat4 libgdbm6 libjs-jquery libruby2.5 libyaml-0-2 openssl rake ruby-did-you-mean ruby-minitest ruby-net-telnet ruby-power-assert ruby-test-unit ruby-xmlrpc ruby2.5 rubygems-integration unzip zip Suggested packages: apache2 | lighttpd | httpd gdbm-l10n ri ruby-dev bundler The following NEW packages will be installed: ca-certificates fonts-lato javascript-common libgdbm-compat4 libgdbm6 libjs-jquery libruby2.5 libyaml-0-2 openssl rake ruby ruby-did-you-mean ruby-minitest ruby-net-telnet ruby-power-assert ruby-test-unit ruby-xmlrpc ruby2.5 rubygems-integration unzip zip 0 upgraded, 21 newly installed, 0 to remove and 23 not upgraded. Need to get 7568 kB of archives. After this operation, 31.9 MB of additional disk space will be used. Do you want to continue? [Y/n]
Ruby には軽量版の mruby がある。
素の mruby のバイナリは Ubuntu 19.10 なら apt install mruby
でインストールできるが、これには ERB がバンドルされておらず利用できないので、代わりに mitamae を使うことにする。
プロビジョニングツールであり ERB を使ってテンプレートから設定ファイルを生成し配置する機能をもともと備えているし、シングルバイナリで 2.28MB (v1.10.5の場合)とコンパクトなので、インストールも手間がかからない。
FROM ubuntu:latest RUN apt update \ && apt install -y \ samba # mitamae の latest の URL を指定する。 # 最新版のバイナリへのリダイレクトを伴うためか、変更がなくとも docker build の度に毎回ダウンロードが走るので、気になる場合は指定バージョンの URL を使う。 ADD https://github.com/itamae-kitchen/mitamae/releases/latest/download/mitamae-x86_64-linux /root/mitamae RUN chmod +x /root/mitamae COPY samba.sh mitamae /root/ EXPOSE 139 445 CMD ["/root/samba.sh"]
#!/bin/sh (cd /root && mitamae local setup.rb) # mitamae にはユーザー追加機能も任意のコマンド実行機能もあるので、`passwd` `smbpasswd` も `setup.rb` に切り出してしまう。 # samba サーバーを起動する /usr/sbin/smbd -F -S --no-process-group
# /etc/samba/smb.conf 生成 template "/etc/samba/smb.conf" do variables(user: ENV["USER"]) end # ユーザー追加 user ENV["USER"] do password ENV["password"] end execute "Add a samba user" do command <<-COMMAND.gsub(/^ */, "") cat <<PASSWORD | smbpasswd -a -s #{ENV["USER"]} #{ENV["PASSWORD"]} #{ENV["PASSWORD"]} PASSWORD COMMAND end
[global] log file = /var/log/samba/%m [share] path = /mount guest ok = no valid users = <%= @user %>
テンプレート部を別ファイルに切り出せた。
また mitamae 化の他の利点として、実行時にシステムへの変更がわかりやすく差分表示されることを記しておきたい。
mitamae は JSON をパースできる。パラメーターを JSON で渡すことを考えてみる。
param = JSON.parse(ENV["SMB_PARAM"]) user = param["user"] template "/etc/samba/smb.conf" do variables(user: user["name"]) end user user["name"] do password user["password"] end execute "Add a samba user" do command <<-COMMAND.gsub(/^ */, "") cat <<PASSWORD | smbpasswd -a -s #{user["name"]} #{user["password"]} #{user["password"]} PASSWORD COMMAND end
$ smb_param=$(cat <<PARAM { "user": { "name": "foo", "password": "pass" } } PARAM $ sudo docker run --rm -p 139:139 -p 445:445 -e SMB_PARAM="$smb_param"
コード量をそれほど変えることなく JSON に対応することができた。 これにより
USER1
, USER2
, ... などとせず "user": [...]
とできる)などの利便性を得られる。
なお実装は nowlinuxing/docker-samba においてあるので、気になる方は参照されたし。
しばらく前からGitHub Actionsがパブリックベータとして公開されていた。 申請をしてから結構待つ必要があった(1〜2週間かかったと思う)が利用できるようになったので、自前のRubyプロジェクトのリポジトリに適用してみた。 なお今は申請するとすぐ利用できるとのこと。
いずれ何もしなくても使えるようになるのかもしれないが、現時点では申請が必要。
こちらからできる。
申請が通るとGitHubのリポジトリ上部に"Actions"というタブが表示される。
ここからワークフローの雛形を選べるので、"Ruby"を選択。 ワークフローの設定ファイルの編集画面になるので、適宜編集してコミット。 あとはこのファイルをカスタムしていく。
jobs.build.steps
を以下のようにする。
jobs: build: # 省略 steps: - uses: actions/checkout@v1 - name: Set up Ruby 2.6 uses: actions/setup-ruby@v1 with: ruby-version: 2.6.x - name: Build and test run: | # 依存するgemのインストールに必要なOSパッケージのインストールなどはこのあたりに記載する # sudo apt-get update # sudo apt-get install -y libsqlite3-dev gem install bundler bundle install --jobs 4 --retry 3 # rspec を実行する bundle exec rspec
複数のバージョンのrubyでテストする場合はjobs.build.strategy.matrixを追加し、jobs.build.steps
のSet Up Ruby 2.6
アクションのruby-version
を書き換える。
jobs: build: runs-on: ubuntu-latest # ここを追加。なお現時点で利用できる Ruby は 2.3.7, 2.4.6, 2.5.5, 2.6.3 の模様 strategy: matrix: ruby: - 2.5.x - 2.6.x # 略 steps: - uses: actions/checkout@v1 - name: Set up Ruby uses: actions/setup-ruby@v1 with: # matrix.ruby に置き換える ruby-version: ${{ matrix.ruby }}
依存するgemをマトリックスにする場合は、bundlerの環境変数BUNDLE_GEMFILE
でGemfileを指定して実行する機能を利用する。
自力で頑張ることもできるだろうが、thoughtbot/appraisalを使えばローカルでの複数バージョンテスト一括実行も楽に行えるのでおすすめ。
strategy: matrix: ruby: - 2.5.x - 2.6.x gemfile: - rails_5.2.gemfile - rails_6.0.gemfile # 略 steps: # 略 - name: Build and test # env を追加 env: BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }} run: | gem install bundler bundle install --jobs 4 --retry 3 bundle exec rspec
"Build and test"アクションの前後にcc-test-reporterを実行するアクションを追加する。
事前にCode Climate側でリポジトリを追加し、Test Reporter IDを取得しておく必要がある。
リポジトリのSetting
→Secrets
に登録しておくとYAML内で参照できるようになるため、CC_TEST_REPORTER_ID
として登録する。
steps: - uses: actions/checkout@v1 - name: Set up Ruby uses: actions/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} # - name: Setup Code Climate test-reporter env: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} run: | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter chmod +x ./cc-test-reporter ./cc-test-reporter before-build - name: Build and test env: BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }} run: | gem install bundler bundle install --jobs 4 --retry 3 bundle exec rspec - name: Upload coverage env: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} # GIT_COMMIT_SHA は設定しなくても参照できているが、ドキュメントに GIT_BRANCH と共に指定するよう記載されているので一応セットしておく GIT_COMMIT_SHA: ${{ github.sha }} run: | # ブランチ名のみを保持する環境変数や context は見つからなかったので、$GIT_BRANCH から抽出する GIT_BRANCH=$(echo $GITHUB_REF | sed -e 's|.*/||') ./cc-test-reporter after-build
なお、テストカバレッジを取得するにはテスト実行時にSimpleCovも実行しておかなければならない。
# spec/spec_helper.rb require 'simplecov' SimpleCov.start
テストカバレッジの取得をCI時のみに限る場合は以下のようにする。
if ENV["COVERAGE"] require 'simplecov' SimpleCov.start end
- name: Build and test env: BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }} # COVERAGE をセット COVERAGE: true run: | gem install bundler bundle install --jobs 4 --retry 3 bundle exec rspec
これでCode Climateで結果を確認できるようになる。
同時にRepo Settings
→Badges
でバッヂも取得できるので、READMEに追加する。