GitHub Actionsアクション自作からMarketplace公開まで
この記事は、klis Advent Calendar 2020の2120日目です。
今年も去年に引き続き、klis要素の薄い記事になります…
目次
- <a href="#%E4%BD%95%E3%82%92%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8B">何をするのか</a>
- <a href="#github-actions%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">GitHub Actionsについて</a>
- <a href="#%E9%81%B8%E6%8A%9E%E8%82%A2">選択肢</a>
- <a href="#docker-container%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E6%A7%8B%E6%88%90">Docker Containerアクションの構成</a>
- <a href="#%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">作ってみる</a>
- <a href="#actionsyml">actions.yml</a>
- <a href="#name-author-description">name, author, description</a>
- <a href="#inputs">inputs</a>
- <a href="#runs">runs</a>
- <a href="#branding">branding</a>
- <a href="#dockerfile">Dockerfile</a>
- <a href="#%E5%AE%9F%E9%9A%9B%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E8%A1%8C%E3%81%86%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0">実際の処理を行うプログラム</a>
- <a href="#actionsyml">actions.yml</a>
- <a href="#%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E3%83%86%E3%82%B9%E3%83%88%E3%81%99%E3%82%8B">作成したアクションをテストする</a>
- <a href="#marketplace%E3%81%AB%E5%85%AC%E9%96%8B%E3%81%99%E3%82%8B">Marketplaceに公開する</a>
- <a href="#%E5%85%AC%E9%96%8B%E3%81%97%E3%81%9F%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E5%AE%9A%E6%9C%9F%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">公開したアクションを定期実行して使ってみる</a>
- <a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a>
何をするのか
リポジトリ: eggplants/twitter-weathername-action
GitHub Actions上で動くアクションをPython+Dockerベースで作成し、GitHubのMarketplaceに公開するまでの手順を解説します。
例として作成するのは、Twitterのスクリーンネームを下の写真のように、明日の3時間天気予報にするものです。
また、普段お手持ちのサーバやVPS上で走らせているような毎日JST00:00になると自動で更新する定期実行のcronをGitHub Actions上で完全無料・サーバなしでやってみます。
但し、走らせるためのリポジトリを作成する必要がありますが…
今回作成したアクションを用いたWorkflowはこちら、またMarketplaceにアクションを公開したものはこちらです。
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/ufco0Vy7VO">https://t.co/ufco0Vy7VO</a></p>— 明日: ☀/☀/☀/☀/☀/☀/☁/☁ (@egpl0) <a href="https://twitter.com/egpl0/status/1341039332245741569?ref_src=twsrc^tfw">December 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
GitHub Actionsについて
GitHub Actionsとは、GitHubが提供しているCI/CDサービスです。リポジトリの.github/workflows
ディレクトリにyamlを書き、pushやpull request、また定期実行するscheduleなどのトリガで走らせることが出来ます。また、公開リポジトリであれば完全無料で回し放題なのも魅力的です。なお、非公開リポジトリやorganizationリポジトリでは一定量使用すると課金されます。
選択肢
Actions作成には3つの作り方があります。(actions.yml
に記述)
runs:
using: 'docker'
image: 'Dockerfile'
runs:
using: 'node12'
main: 'hogehoge.js'
runs:
using: 'composite'
今回はこのうちのDocker Containerアクションを作ります。
Docker Containerアクションの構成
大きく分けて3つの部分を書けばよく、
-
action.yml
- アクションの説明
- 渡す引数の名前、説明、属性、必須かどうか、返り値を定義
- Marketplaceでの公開時のアイコンとその背景色
-
Dockerfile
- 環境の構築
- 実際の処理を動かすプログラムを
ENTRYPOINT
として実行
-
実際の処理を行うプログラム
- 今回はPythonで記述
を記述します。
作ってみる
actions.yml
それぞれ記述するべき値を列挙します。
name
, author
, description
アクション公開時の「アクション名」、「作者」「アクションの説明」です。
inputs
アクションの実行時に渡せる、「引数の定義」です。
アクションは、workflowでの使用時にjobs.<job_id>.steps.with
で渡された引数を受け取ることが出来ます。
後述しますが、渡された引数XXX
は環境変数INPUT_XXX
として定義され、ENTRYPOINT内で参照できるようになります。
required: true
としたものに関しては、使用時に指定しないと実行できません。
またrequired: false
の場合(オプション引数)に、default
で引数のデフォルト値を定義できます。
<details><summary>今回定義した引数</summary><div>
- 必須引数
-
open_weather_api_token
- Openweathermap APIのトークン
-
twitter_consumer_key
,twitter_consumer_secret
,twitter_access_key
,twitter_access_secret
- Twitter APIのトークン
-
location_query
- 天気予報の場所
-
- オプション引数記述
-
time_zone
- 用いる予報のタイムゾーン
- デフォルトだと
location_query
の場所のタイムゾーンを用いる
-
name_format
- 天気予報をはめ込むフォーマット
-
icon_sep
- 天気を区切るパラメータ
-
forecast_day
- 予報する日数をn日先で設定
- 天気APIの都合上
0
~2
で指定 - "明日"だと
1
</div></details>
-
runs
今回はDocker Containerアクションなので、
runs:
using: "docker"
image: "Dockerfile"
とします。今回はimage
に、自分で作成したDockerfileを指定していますが、DockerHubの公開DockerイメージやGitHub Packagesの公開コンテナも指定できます。
branding
Marketplaceでの公開時のアイコンとその背景色を指定できます。
-
icon
- Featherと対応
-
color
-
white
,yellow
,blue
,green
,orange
,red
,purple
,gray-dark
の中から選べます。
-
icon: "link"
color: "green"
だと、
のようになります。
以下作成したactions.yml
です。
<details><summary>actions.yml</summary><div>
name: "Twitter Weathername"
author: "haruna"
description: "Update Twit記述ter Username to a daily forecast of given location"
inputs:
open_weather_api_token:
description: "Openweathermap API Token"
required: true
twitter_consumer_key:
description: "Twitter API consumer key"
required: true
twitter_consumer_secret:
description: "Twitter API consumer secret key"
required: true
twitter_access_key:
description: "Twitter API access key"
required: true
twitter_access_secret:
description: "Twitter API access secret key"
required: true
location_query:
description: "City name, state code and country code divided by comma, use ISO 3166 country codes"
required: true
time_zone:
description: "Time zone to be used as a time reference (ex. Asia/Tokyo) (def: LOCATION_QUERY's local time zone)"
required: false
name_format:
description: "Username format ({} is substituted by joined weather icons with icon_sep)"
required: false
default: "<{}"
icon_sep:
description: "String for joining icons"
required: false
default: ":"
forecast_day:
description: "Show the weather in the next n days (n=0 is today)"
required: false
default: "0"
runs:
using: "docker"
image: "Dockerfile"
branding:
icon: "link"
color: "green"
</div></details>
Dockerfile
今回はPythonを実行するので、Pythonを動かすための実行環境を作成するDockerfileを記述する。
また引数を受け取って、実際の処理を行う(ここではTwitterのユーザ名を、取得した天気予報に更新する)プログラムをENTRYPOINT
に指定します。CMD ["python", "/src/main.py"]
のように指定しても良いです。
以下作成したDockerfileです。
FROM python:latest
ADD src /src
ADD requirements.txt /requirements.txt
RUN pip install -r requirements.txt
RUN chmod +x src/main.py
ENTRYPOINT ["/src/main.py"]
実際の処理を行うプログラム
workflowで渡された引数(例えばXXX
)は、
from os import environ
xxx = environ.get('INPUT_XXX', 'default')
のように受け取れます。
今回は、
①3日間天気.jsonをOpenweathermap APIから取得
②3日間天気.jsonを名前に整形
③Twitter APIから名前を更新
を行うプログラムを書きます。作成したプログラムはこちらです。
作成したアクションをテストする
ここまでで作成したアクションがちゃんと動くかどうかはGitHub Actionsでテスト出来てしまいます。Marketplaceに公開する前に動くかどうかテストしましょう。
また、APIトークンなどの一般に公開したくない文字列は、リポジトリの[Settings]->[Secrets]->[New repository secret]
から追加でき、${{ secrets.XXX }}
で呼び出せます。
リポジトリでのpush毎に実行して、うまく更新できるか試すworkflowはこのようになります。
name: Test
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Change Name
uses: eggplants/twitter-weathername-action@main # アクションのリポジトリ
with:
open_weather_api_token: ${{ secrets.OPEN_WEATHER_API_TOKEN }}
twitter_consumer_key: ${{ secrets.TWITTER_CONSUMER_KEY }}
twitter_consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }}
twitter_access_key: ${{ secrets.TWITTER_ACCESS_KEY }}
twitter_access_secret: ${{ secrets.TWITTER_ACCESS_SECRET }}
location_query: tsukuba
name_format: "明日: {}"
icon_sep: "/"
forecast_day: 1 # 明日の天気
うまく動いたかどうかは、Actionsタブから確認できます。
Marketplaceに公開する
作成したアクションをMarketplaceに公開することで、誰にでも簡単に、すぐ作成したアクションを使ってもらえるように出来ます。
詳細な手順は公式ドキュメントがわかりやすいです。
action.yml
がリポジトリに存在していれば、リポジトリに[Draft a release]
バナーが出現します。
クリックすると
のように表示されるので、accept the GitHub Marketplace Developer Agreement
リンクをクリックすると、
GitHub Marketplace Developer Agreementに同意するように言われます。
同意すると、
のように、actions.yml
のメタデータが足りているか、またREADME
があるかどうかがチェックされ、不十分だと修正するように言われます。
カテゴリを設定し、[Publish release]
ボタン(画像ではUpdate release
ですが…)を押下して、公開できます。お疲れ様でした!
公開したアクションを定期実行して使ってみる
最初に書いたように、Actionsのworkflowの実行トリガには、cronのように定期実行できるschedule
トリガが存在しており、
on:
schedule:
- cron: "0 15 * * *" # JSTでは"0 0 * * *"
のように、まさにcronの構文で定期実行できます。ここで注意ですが、ActionsのworkflowはUTC(協定世界時)で実行されるため、日本時間に即した実行を行いたい場合はJST(日本標準時)-9の時間を指定しましょう。
以下が、現在実際に使っているcron workflowです。
name: Cron renamer
on:
schedule:
- cron: "0 15 * * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Change Name
uses: eggplants/twitter-weathername-action@v2
with:
open_weather_api_token: ${{ secrets.OPEN_WEATHER_API_TOKEN }}
twitter_consumer_key: ${{ secrets.TWITTER_CONSUMER_KEY }}
twitter_consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }}
twitter_access_key: ${{ secrets.TWITTER_ACCESS_KEY }}
twitter_access_secret: ${{ secrets.TWITTER_ACCESS_SECRET }}
location_query: tsukuba
name_format: "明日: {}"
icon_sep: "/"
forecast_day: 1
実行ログはテスト同様Actionsタブから確認できます。
おわりに
GitHub Actionsの自作アクションの作成とテスト、公開や定期実行の手順がひとところにあるわかりやすい記事がなかなかなかったので、備忘録も兼ねて書こうとずっと思ってたんですけど、今回Adventカレンダーが良い契機となりました。
良いお年を〜
Discussion