🐐

GitHub Wiki が更新されたときに通知する

19 min read

概要

GitHub Wiki が更新されたときに通知する仕組みを GitHub Actions で実装します。

イベント

誰かが Wiki ページを作成または更新すると gollum イベントがトリガーされます。
ペイロードpages.*.action で作成と更新のどちらか判断できるようです。

ページ作成
created
{
  "pages": [
    {
      "action": "created",
      "html_url": "https://github.com/SnowCait/action-sandbox/wiki/Home",
      "page_name": "Home",
      "sha": "ac87b4a2c5e669deb67968f494889bfe94ede473",
      "summary": null,
      "title": "Home"
    }
  ],
  "repository": {
    "archive_url": "https://api.github.com/repos/SnowCait/action-sandbox/{archive_format}{/ref}",
    "archived": false,
    "assignees_url": "https://api.github.com/repos/SnowCait/action-sandbox/assignees{/user}",
    "blobs_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/blobs{/sha}",
    "branches_url": "https://api.github.com/repos/SnowCait/action-sandbox/branches{/branch}",
    "clone_url": "https://github.com/SnowCait/action-sandbox.git",
    "collaborators_url": "https://api.github.com/repos/SnowCait/action-sandbox/collaborators{/collaborator}",
    "comments_url": "https://api.github.com/repos/SnowCait/action-sandbox/comments{/number}",
    "commits_url": "https://api.github.com/repos/SnowCait/action-sandbox/commits{/sha}",
    "compare_url": "https://api.github.com/repos/SnowCait/action-sandbox/compare/{base}...{head}",
    "contents_url": "https://api.github.com/repos/SnowCait/action-sandbox/contents/{+path}",
    "contributors_url": "https://api.github.com/repos/SnowCait/action-sandbox/contributors",
    "created_at": "2019-09-06T21:09:25Z",
    "default_branch": "master",
    "deployments_url": "https://api.github.com/repos/SnowCait/action-sandbox/deployments",
    "description": null,
    "disabled": false,
    "downloads_url": "https://api.github.com/repos/SnowCait/action-sandbox/downloads",
    "events_url": "https://api.github.com/repos/SnowCait/action-sandbox/events",
    "fork": false,
    "forks": 0,
    "forks_count": 0,
    "forks_url": "https://api.github.com/repos/SnowCait/action-sandbox/forks",
    "full_name": "SnowCait/action-sandbox",
    "git_commits_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/commits{/sha}",
    "git_refs_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/refs{/sha}",
    "git_tags_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/tags{/sha}",
    "git_url": "git://github.com/SnowCait/action-sandbox.git",
    "has_downloads": true,
    "has_issues": true,
    "has_pages": true,
    "has_projects": true,
    "has_wiki": true,
    "homepage": null,
    "hooks_url": "https://api.github.com/repos/SnowCait/action-sandbox/hooks",
    "html_url": "https://github.com/SnowCait/action-sandbox",
    "id": 206874426,
    "issue_comment_url": "https://api.github.com/repos/SnowCait/action-sandbox/issues/comments{/number}",
    "issue_events_url": "https://api.github.com/repos/SnowCait/action-sandbox/issues/events{/number}",
    "issues_url": "https://api.github.com/repos/SnowCait/action-sandbox/issues{/number}",
    "keys_url": "https://api.github.com/repos/SnowCait/action-sandbox/keys{/key_id}",
    "labels_url": "https://api.github.com/repos/SnowCait/action-sandbox/labels{/name}",
    "language": "PHP",
    "languages_url": "https://api.github.com/repos/SnowCait/action-sandbox/languages",
    "license": null,
    "merges_url": "https://api.github.com/repos/SnowCait/action-sandbox/merges",
    "milestones_url": "https://api.github.com/repos/SnowCait/action-sandbox/milestones{/number}",
    "mirror_url": null,
    "name": "action-sandbox",
    "node_id": "MDEwOlJlcG9zaXRvcnkyMDY4NzQ0MjY=",
    "notifications_url": "https://api.github.com/repos/SnowCait/action-sandbox/notifications{?since,all,participating}",
    "open_issues": 8,
    "open_issues_count": 8,
    "owner": {
      "avatar_url": "https://avatars.githubusercontent.com/u/1297512?v=4",
      "events_url": "https://api.github.com/users/SnowCait/events{/privacy}",
      "followers_url": "https://api.github.com/users/SnowCait/followers",
      "following_url": "https://api.github.com/users/SnowCait/following{/other_user}",
      "gists_url": "https://api.github.com/users/SnowCait/gists{/gist_id}",
      "gravatar_id": "",
      "html_url": "https://github.com/SnowCait",
      "id": 1297512,
      "login": "SnowCait",
      "node_id": "MDQ6VXNlcjEyOTc1MTI=",
      "organizations_url": "https://api.github.com/users/SnowCait/orgs",
      "received_events_url": "https://api.github.com/users/SnowCait/received_events",
      "repos_url": "https://api.github.com/users/SnowCait/repos",
      "site_admin": false,
      "starred_url": "https://api.github.com/users/SnowCait/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/SnowCait/subscriptions",
      "type": "User",
      "url": "https://api.github.com/users/SnowCait"
    },
    "private": false,
    "pulls_url": "https://api.github.com/repos/SnowCait/action-sandbox/pulls{/number}",
    "pushed_at": "2021-03-15T15:16:11Z",
    "releases_url": "https://api.github.com/repos/SnowCait/action-sandbox/releases{/id}",
    "size": 3168,
    "ssh_url": "git@github.com:SnowCait/action-sandbox.git",
    "stargazers_count": 0,
    "stargazers_url": "https://api.github.com/repos/SnowCait/action-sandbox/stargazers",
    "statuses_url": "https://api.github.com/repos/SnowCait/action-sandbox/statuses/{sha}",
    "subscribers_url": "https://api.github.com/repos/SnowCait/action-sandbox/subscribers",
    "subscription_url": "https://api.github.com/repos/SnowCait/action-sandbox/subscription",
    "svn_url": "https://github.com/SnowCait/action-sandbox",
    "tags_url": "https://api.github.com/repos/SnowCait/action-sandbox/tags",
    "teams_url": "https://api.github.com/repos/SnowCait/action-sandbox/teams",
    "trees_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/trees{/sha}",
    "updated_at": "2021-03-15T15:16:12Z",
    "url": "https://api.github.com/repos/SnowCait/action-sandbox",
    "watchers": 0,
    "watchers_count": 0
  },
  "sender": {
    "avatar_url": "https://avatars.githubusercontent.com/u/1297512?v=4",
    "events_url": "https://api.github.com/users/SnowCait/events{/privacy}",
    "followers_url": "https://api.github.com/users/SnowCait/followers",
    "following_url": "https://api.github.com/users/SnowCait/following{/other_user}",
    "gists_url": "https://api.github.com/users/SnowCait/gists{/gist_id}",
    "gravatar_id": "",
    "html_url": "https://github.com/SnowCait",
    "id": 1297512,
    "login": "SnowCait",
    "node_id": "MDQ6VXNlcjEyOTc1MTI=",
    "organizations_url": "https://api.github.com/users/SnowCait/orgs",
    "received_events_url": "https://api.github.com/users/SnowCait/received_events",
    "repos_url": "https://api.github.com/users/SnowCait/repos",
    "site_admin": false,
    "starred_url": "https://api.github.com/users/SnowCait/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/SnowCait/subscriptions",
    "type": "User",
    "url": "https://api.github.com/users/SnowCait"
  }
}
ページ更新
edited
{
  "pages": [
    {
      "action": "edited",
      "html_url": "https://github.com/SnowCait/action-sandbox/wiki/Page-Title-%E3%83%9A%E3%83%BC%E3%82%B8",
      "page_name": "Page-Title-ページ",
      "sha": "6198e55cc1dd2f0a938a77cda345b88116792e86",
      "summary": null,
      "title": "Page Title ページ"
    }
  ],
  "repository": {
    "archive_url": "https://api.github.com/repos/SnowCait/action-sandbox/{archive_format}{/ref}",
    "archived": false,
    "assignees_url": "https://api.github.com/repos/SnowCait/action-sandbox/assignees{/user}",
    "blobs_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/blobs{/sha}",
    "branches_url": "https://api.github.com/repos/SnowCait/action-sandbox/branches{/branch}",
    "clone_url": "https://github.com/SnowCait/action-sandbox.git",
    "collaborators_url": "https://api.github.com/repos/SnowCait/action-sandbox/collaborators{/collaborator}",
    "comments_url": "https://api.github.com/repos/SnowCait/action-sandbox/comments{/number}",
    "commits_url": "https://api.github.com/repos/SnowCait/action-sandbox/commits{/sha}",
    "compare_url": "https://api.github.com/repos/SnowCait/action-sandbox/compare/{base}...{head}",
    "contents_url": "https://api.github.com/repos/SnowCait/action-sandbox/contents/{+path}",
    "contributors_url": "https://api.github.com/repos/SnowCait/action-sandbox/contributors",
    "created_at": "2019-09-06T21:09:25Z",
    "default_branch": "master",
    "deployments_url": "https://api.github.com/repos/SnowCait/action-sandbox/deployments",
    "description": null,
    "disabled": false,
    "downloads_url": "https://api.github.com/repos/SnowCait/action-sandbox/downloads",
    "events_url": "https://api.github.com/repos/SnowCait/action-sandbox/events",
    "fork": false,
    "forks": 0,
    "forks_count": 0,
    "forks_url": "https://api.github.com/repos/SnowCait/action-sandbox/forks",
    "full_name": "SnowCait/action-sandbox",
    "git_commits_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/commits{/sha}",
    "git_refs_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/refs{/sha}",
    "git_tags_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/tags{/sha}",
    "git_url": "git://github.com/SnowCait/action-sandbox.git",
    "has_downloads": true,
    "has_issues": true,
    "has_pages": true,
    "has_projects": true,
    "has_wiki": true,
    "homepage": null,
    "hooks_url": "https://api.github.com/repos/SnowCait/action-sandbox/hooks",
    "html_url": "https://github.com/SnowCait/action-sandbox",
    "id": 206874426,
    "issue_comment_url": "https://api.github.com/repos/SnowCait/action-sandbox/issues/comments{/number}",
    "issue_events_url": "https://api.github.com/repos/SnowCait/action-sandbox/issues/events{/number}",
    "issues_url": "https://api.github.com/repos/SnowCait/action-sandbox/issues{/number}",
    "keys_url": "https://api.github.com/repos/SnowCait/action-sandbox/keys{/key_id}",
    "labels_url": "https://api.github.com/repos/SnowCait/action-sandbox/labels{/name}",
    "language": "PHP",
    "languages_url": "https://api.github.com/repos/SnowCait/action-sandbox/languages",
    "license": null,
    "merges_url": "https://api.github.com/repos/SnowCait/action-sandbox/merges",
    "milestones_url": "https://api.github.com/repos/SnowCait/action-sandbox/milestones{/number}",
    "mirror_url": null,
    "name": "action-sandbox",
    "node_id": "MDEwOlJlcG9zaXRvcnkyMDY4NzQ0MjY=",
    "notifications_url": "https://api.github.com/repos/SnowCait/action-sandbox/notifications{?since,all,participating}",
    "open_issues": 8,
    "open_issues_count": 8,
    "owner": {
      "avatar_url": "https://avatars.githubusercontent.com/u/1297512?v=4",
      "events_url": "https://api.github.com/users/SnowCait/events{/privacy}",
      "followers_url": "https://api.github.com/users/SnowCait/followers",
      "following_url": "https://api.github.com/users/SnowCait/following{/other_user}",
      "gists_url": "https://api.github.com/users/SnowCait/gists{/gist_id}",
      "gravatar_id": "",
      "html_url": "https://github.com/SnowCait",
      "id": 1297512,
      "login": "SnowCait",
      "node_id": "MDQ6VXNlcjEyOTc1MTI=",
      "organizations_url": "https://api.github.com/users/SnowCait/orgs",
      "received_events_url": "https://api.github.com/users/SnowCait/received_events",
      "repos_url": "https://api.github.com/users/SnowCait/repos",
      "site_admin": false,
      "starred_url": "https://api.github.com/users/SnowCait/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/SnowCait/subscriptions",
      "type": "User",
      "url": "https://api.github.com/users/SnowCait"
    },
    "private": false,
    "pulls_url": "https://api.github.com/repos/SnowCait/action-sandbox/pulls{/number}",
    "pushed_at": "2021-03-15T16:21:49Z",
    "releases_url": "https://api.github.com/repos/SnowCait/action-sandbox/releases{/id}",
    "size": 3173,
    "ssh_url": "git@github.com:SnowCait/action-sandbox.git",
    "stargazers_count": 0,
    "stargazers_url": "https://api.github.com/repos/SnowCait/action-sandbox/stargazers",
    "statuses_url": "https://api.github.com/repos/SnowCait/action-sandbox/statuses/{sha}",
    "subscribers_url": "https://api.github.com/repos/SnowCait/action-sandbox/subscribers",
    "subscription_url": "https://api.github.com/repos/SnowCait/action-sandbox/subscription",
    "svn_url": "https://github.com/SnowCait/action-sandbox",
    "tags_url": "https://api.github.com/repos/SnowCait/action-sandbox/tags",
    "teams_url": "https://api.github.com/repos/SnowCait/action-sandbox/teams",
    "trees_url": "https://api.github.com/repos/SnowCait/action-sandbox/git/trees{/sha}",
    "updated_at": "2021-03-15T16:21:43Z",
    "url": "https://api.github.com/repos/SnowCait/action-sandbox",
    "watchers": 0,
    "watchers_count": 0
  },
  "sender": {
    "avatar_url": "https://avatars.githubusercontent.com/u/1297512?v=4",
    "events_url": "https://api.github.com/users/SnowCait/events{/privacy}",
    "followers_url": "https://api.github.com/users/SnowCait/followers",
    "following_url": "https://api.github.com/users/SnowCait/following{/other_user}",
    "gists_url": "https://api.github.com/users/SnowCait/gists{/gist_id}",
    "gravatar_id": "",
    "html_url": "https://github.com/SnowCait",
    "id": 1297512,
    "login": "SnowCait",
    "node_id": "MDQ6VXNlcjEyOTc1MTI=",
    "organizations_url": "https://api.github.com/users/SnowCait/orgs",
    "received_events_url": "https://api.github.com/users/SnowCait/received_events",
    "repos_url": "https://api.github.com/users/SnowCait/repos",
    "site_admin": false,
    "starred_url": "https://api.github.com/users/SnowCait/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/SnowCait/subscriptions",
    "type": "User",
    "url": "https://api.github.com/users/SnowCait"
  }
}

title がページ作成時に入力したタイトルそのまま、 page_name が URL に適用される変換後文字列になります。(例えばページ更新のペイロードにあるように - になります。 /title の時点で に置換されました。)

残念ながらページ削除はトリガーされません。
そもそも GitHub 上に削除する UI が無いのでクローンした上でローカルからプッシュしてみたのですがトリガーされませんでした。(作成や更新はトリガーされました)

ワークフロー

通知先はどこでも良いのですが Slack が一般的でしょうか。
(Slack のアクションはたくさんありますがどれを使うのが良いのでしょうね…)

今回は Incoming WebHookcurl から叩こうと思います。
WebHook URL を発行し、 Settings > Secrets に SLACK_WEBHOOK で登録しておきます。

${{ }} は先に展開されるので title など自由入力可能なものは env を経由しましょう。
コマンドを含む場合シェルスクリプトに直接書いているとコマンドが実行されてしまいます。

.github/workflows/wiki.yml
name: Wiki

on:
  gollum

jobs:
  notify:
    runs-on: ubuntu-latest

    steps:
      - name: Slack
        run: |
          curl -X POST -H 'Content-type: application/json' \
            --data "{\"text\": \"Wiki ${ACTION}: ${TITLE}\n${URL}\"}" \
            ${WEBHOOK_URL}
        env:
          ACTION: ${{ github.event.pages[0].action }}
          TITLE: ${{ github.event.pages[0].title }}
          URL: ${{ github.event.pages[0].html_url }}
          WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
旧方式
.github/workflows/wiki.yml
      - name: Slack
        run: |
          json="{
            'channel': '#sandbox',
            'username': 'bot',
            'text': 'Wiki ${ACTION}: ${TITLE}\n${HTML_URL}',
            'icon_emoji': ':ghost:'
          }"
          curl -X POST --data-urlencode "payload=${json}" ${WEBHOOK_URL}
        env:
          ACTION: ${{ github.event.pages[0].action }}
          TITLE: ${{ github.event.pages[0].title }}
          HTML_URL: ${{ github.event.pages[0].html_url }}
          WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

新方式では URL を発行するときにチャンネル等を決めるので channel, username, icon_emoji は使えなくなっています。

Wiki なので基本的には 1 ファイルずつ編集されると思いますが、ローカルで編集してコミットした場合は pages に複数の情報が入ってきます。
もしそちらも対応する場合はスクリプトで書くことになりそうです。

更新差分

Wiki のページ上部にある * revisions というリンクから更新差分を見ることもできますが、せっかくなので GitHub Actions で比較用リンクまで生成してみます。

.github/workflows/wiki.yml
      - uses: actions/checkout@v2
        with:
          repository: ${{ github.event.repository.full_name }}.wiki
          ref: ${{ github.event.pages[0].sha }}
          fetch-depth: 2
      - name: Slack
        run: |
          url=${HTML_URL}/_compare/$(git rev-parse HEAD^)...$(git rev-parse HEAD)
          curl -X POST -H 'Content-type: application/json' \
            --data "{\"text\": \"Wiki ${ACTION}: ${TITLE}\n${url}\"}" \
            ${WEBHOOK_URL}
        env:
          ACTION: ${{ github.event.pages[0].action }}
          TITLE: ${{ github.event.pages[0].title }}
          HTML_URL: ${{ github.event.pages[0].html_url }}
          WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

URL の /_compare/$(git rev-parse HEAD^)...$(git rev-parse HEAD) の部分が追加分です。
fetch-depth で 1 つ前のコミットまで取得して git rev-parse で更新前後の SHA をそれぞれ取得しています。

Discussion

ログインするとコメントできます