JavaScript や TypeScript で作られたアクションは割とよく見るのですが、 Python で作られた Actions は見ないので(そもそも Python で書く必要がない?)今回は Python を使って Action コードを作ってみたいと思います。
動作環境
Actions は Docker コンテナのアクションまたは JavaScript アクションの2種類あります。Python で書くために今回は Docker コンテナのアクションを採用します。 Docker コンテナで Python が実行できるようにベースイメージには Python を設定します。
ディレクトリ構成
Python コードは src ディレクトリ配下に置き Docker のCOPY
コマンドでコンテナ内にコピーさせます。action.yml
は GitHub Actions のメタデータファイルです。
https://docs.github.com/ja/actions/creating-actions/creating-a-docker-container-action#creating-an-action-metadata-file
.
├── Dockerfile
├── action.yml
├── entrypoint.sh
└── src
├── main.py
├── qiita.py
├── requirements.txt
└── slack.py
name: 'Slack Notify'
description: 'You can notify slack of GitHub Actions.'
runs:
using: 'docker'
image: 'Dockerfile'
モジュール
slackに通知するためのコードで sdk を使用できるようにするために、slack-sdk
モジュールをインストールします。
slack-sdk==3.5.1
ビュー数の取得
Qiita 記事のビュー数を取得するコードを書いていきます。ビュー数を取得するためには個別記事を取得する必要があります。そのためにまずは記事一覧取得APIを実行して一覧を取得し、取得したデータから個別記事のIDを抜き出して個別記事取得APIを叩きビュー数を取得します。qiita api のトークンは環境変数設定して取得できるようにします。
import urllib.request
import json
import os
def sendRequest(url):
req = urllib.request.Request(url)
req.headers = {
'Authorization': 'Bearer ' + os.environ['TOKEN']
}
with urllib.request.urlopen(req) as response:
decode = json.loads(response.read().decode('utf-8'))
return decode
def getIds(url):
decode = sendRequest(url)
ids = []
for s in range(len(decode)):
ids.append(decode[s]['id'])
return ids
def getViews(ids):
originUrl = 'https://qiita.com/api/v2/items/'
views = []
for s in range(len(ids)):
url = originUrl + ids[s]
decode = sendRequest(url)
views.append({
"title": decode['title'],
"views": decode['page_views_count']
})
return views
def views():
url = 'https://qiita.com/api/v2/users/kiyo27/items?page=1&per_page=20'
ids = getIds(url)
return getViews(ids)
slack に通知
slack から sdk が提供されているのでそれを使用します。webhook url は環境変数に設定しておきます。
import os
from slack_sdk.webhook import WebhookClient
def notify(views):
url = os.environ['WEBHOOK']
webhook = WebhookClient(url)
blocks = []
for s in range(len(views)):
title = views[s]['title']
viewCount = views[s]['views']
text = title + "\n:star::star::star::star: "
text = text + str(viewCount) + "views"
blocks.append({
"type": "section",
"text": {
"type": "mrkdwn",
"text": text
}
})
response = webhook.send(text="fallback", blocks=blocks)
コンテナ作成
ベースイメージに python を設定して、qiita の view 数を取得するコードと slack に通知するコードをCOPY
コマンドコンテナ内に取り込みます。コンテナ起動時に実行されるブートコードとしてentrypoint.sh
を設定しておきます。
FROM python:3.9.5-slim-buster
COPY src /usr/app
COPY entrypoint.sh /entrypoint.sh
RUN pip install -r /usr/app/requirements.txt \
&& chmod +x /*.sh
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh
の中身。main.py
を実行しています。
#!/usr/bin/env bash
python /usr/app/main.py
main.py
の中身。コマンドラインから実行されたとき、 run メソッドを呼び出します。 run メソッドでは qiita の個別記事の view 数を取得し、取得結果を slack に通知するロジックにしています。
import qiita
import slack
def run():
views = qiita.views()
slack.notify(views)
if __name__ == "__main__":
run()
Actions で実行
作成したアクションを実行するために、 Actions の workflow を作成します。uses
に先ほど作成したアクションを指定します。サンプルアクションはこちらで GitHub に上がっています。 Qiita API トークンと Slack Webhook URL はコード内では環境変数から取得しているので、 workflow 構文でenv
を使用して環境変数を設定しています。環境変数として設定する値は、GitHub の シークレットを利用して設定しておきます。設定の仕方は下のリンクから確認できます。あとはこの workflow ファイルを GitHub にプッシュすればアクションが実行されて slack に qiita の 個別記事ごとの views 数が記載された状態で通知がきます。
on: [push]
jobs:
slack_notify:
runs-on: ubuntu-latest
name: A job to send a message to slack
steps:
- name: Slack notification
id: slack
uses: kiyo27/action-slack-notify@main
env:
TOKEN: ${{ secrets.TOKEN }}
WEBHOOK: ${{ secrets.WEBHOOK }}