cockscomblog?

cockscomb on hatena blog

GitHubの新しいプロジェクトを使ってみている

新しいものが好きなので、GitHubの新しいプロジェクトで仕事をしている。まだベータ版だが、少し前に会社のアカウントで有効になったので、所属するチームで大喜びで使い始めた。

もともとしばらくAsanaを使っていて、Asanaはタスクに依存関係がつけられたりして気に入っている。とはいえ仕事の大部分はGitHub上のリポジトリで行うのだから、GitHub上で完結するなら試してみたいわけである。

スプリント

ということでとりあえず仕掛かりのIssueなどをプロジェクトに入れていたのだけど、なんかまだしっくりきていなかった。ドキュメントにはベストプラクティスとかもあるけど、そんなにおもしろいことは書いていない。Single source of truth志向なのはいいと思う。

しっくりこなかったことの一つは、スプリントの表現がうまくいかない感じがしたからだった。Single source of truthということでリポジトリマイルストーンを使う感じかと思ったが、しかし扱っているリポジトリは残念ながら複数あって、それぞれにマイルストーンを設定してまわりたくはない。

と思っていたら今日になっていいのが出た。

このiteration field typeというのが最高。これで何もかも上手くいった。

GitHubの新しいプロジェクトは、今まさにバリバリ開発している感じでおもしろい。

自動化

プロジェクトにIssueとかPull Requestを追加するところは、けっこう面倒に感じる。ということで自動化を試す。

Automating projects (beta) - GitHub Docs

複数のチームに関連する特別なリポジトリで、特定のラベルがついたIssueを、自分のチームのプロジェクトに追加する、というのをやってみた。次のようなGitHub Actionsを設定した。

name: Projects
on:
  issues:
    types:
      - labeled
jobs:
  projects:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/github-script@v5
        with:
          github-token: ${{ secrets.GITHUB_TOKEN_FOR_PROJECTS }}
          script: |
            const script = require('./.github/workflows/lib/projects.js');
            await script({ github, context, core }, {
              '特定のラベル': 1,
            });

「特定のラベル」がつけられたIssueを「#1」のプロジェクトに追加する、というマッピングが書いてある。シークレットからPersonal Access Tokenをもらって使っている。このトークンの権限は、プロジェクトを操作するために org:write が必要であるほか、Issueの情報を取得するために repo:read も必要だった。

.github/workflows/lib/projects.js は次の通り。

module.exports = async ({ github, context, core }, projectMapping) => {
  const headers = {
    'GraphQL-Features': 'projects_next_graphql',
  };

  const projectNumber = projectMapping[context.payload.label.name];
  if (projectNumber === undefined) {
    return;
  }

  const project = await github.graphql(
    `query($organization: String!, $projectNumber: Int!) {
      organization(login: $organization) {
        projectNext(number: $projectNumber) {
          id
        }
      }
    }`,
    {
      headers,
      organization: context.repo.owner,
      projectNumber,
    }
  );
  const projectId = project.organization.projectNext.id;

  const item = await github.graphql(
    `mutation($projectId: ID!, $contentId: ID!) {
      addProjectNextItem(input: { projectId: $projectId, contentId: $contentId }) {
        projectNextItem {
          id
        }
      }
    }`,
    {
      headers,
      projectId,
      contentId: context.payload.issue.node_id,
    }
  );
  core.exportVariable('itemId', item.addProjectNextItem.projectNextItem.id);
};

ドキュメントでは gh コマンドを使っているが、値を引き回すのが面倒なので、actions/github-script@v5 を使ってJavaScriptで書いた。スクリプトを別なファイルに置いているのはエディタで書きやすいから。でも別なファイルに分けると actions/checkout@v2 が必要になって、もったいない気もしている……。

actions/github-script@v5 を使うとOctokitが使えるのだけど、ヘッダの扱いがよくわからず、Octokitのコードを読む羽目になった。

ラベルが外されたらプロジェクトから取り除くのもやりたかったのだけど、プロジェクト内のアイテムから該当のものを探すのが簡単でなかったので、いったん諦めた。

ということで

いろいろタイミングが合ったので、GitHubの新しいプロジェクトを使ってみている。まだ開発中という感じだけど、その分だけ将来に期待できていいと思う。