Quartet / Quintet

2026-09-04  ·  githubactions · cli · ci · typescript

自作ツールを composite GitHub Action で配る(npm 公開なし)

小さな CLI を作ったとき、他の人に使ってもらう方法として npm 公開を考えがちです。 でもアカウントも公開手続きも要らない配布経路があります。GitHub Action です。

- uses: あなたの名前/ツール名@v1

この1行で使えるようになります。実際にやったので、手順とハマりどころを書きます。

composite か Docker か

Action には3種類(JavaScript / Docker / composite)ありますが、 Node で動くツールなら composite 一択でした。

composite Docker
起動 速い イメージのビルド or 取得が要る
実行環境 ランナーのもの 隔離される
書き方 シェルのステップを並べるだけ Dockerfile が要る

Docker の隔離が要るのは、システムに手を入れるツールや、 特殊な依存を固めたい場合です。Node だけで完結するツールに Docker を使うと、 起動時間を払うだけで見返りがありません。

全文

action.yml をリポジトリの直下に置きます。

name: 'mdlinkcheck'
description: 'Find broken relative links in Markdown files.'
author: 'your-name'
branding:
  icon: 'link-2'
  color: 'orange'

inputs:
  path:
    description: 'Directory or file to check.'
    required: false
    default: '.'
  format:
    description: 'Output format: text or json.'
    required: false
    default: 'text'

runs:
  using: 'composite'
  steps:
    - name: Set up Node
      uses: actions/setup-node@v4
      with:
        node-version: '22'

    - name: Build
      shell: bash
      working-directory: ${{ github.action_path }}
      run: |
        npm ci --no-audit --no-fund
        npm run build

    - name: Check links
      shell: bash
      run: |
        node "${{ github.action_path }}/bin/mdlinkcheck.js" \
          "${{ inputs.path }}" --format "${{ inputs.format }}"

これだけです。

ハマりどころ

shell: は毎ステップ必須

composite の run ステップは、1つずつ shell: を書かないとエラーになります。 通常のワークフローだと省略できるので、忘れます。

${{ github.action_path }} を使う

action が置かれたディレクトリの絶対パスです。利用者のリポジトリで実行されるので、 カレントディレクトリは利用者側になります。

# NG: 利用者のリポジトリで npm ci しようとする
run: npm ci

# OK
working-directory: ${{ github.action_path }}
run: npm ci

ツールの実行も同様に絶対パスで指定します。

run: node "${{ github.action_path }}/bin/tool.js" "${{ inputs.path }}"

終了コードはそのまま伝わる

シェルステップが非ゼロで終われば、ステップが失敗します。 || true を付けたり continue-on-error を書いたりしなければ、 ツールの終了コードがそのまま CI の合否になります。

これが効くので、ツール側で終了コードをちゃんと設計しておく価値があります。

0  問題なし
1  検出した(CI を落としたい)
2  使い方が間違っている(パスが無い、オプションが不正)

dist/ をコミットするかどうか

JavaScript action だと dist/ をコミットする必要がありますが、 composite なら action 側で npm ci && npm run build すればいいので不要です。

そのぶん実行のたびにビルドが走ります。数秒なので許容しました。 気になるなら actions/cache を挟めます。

バージョンタグを打つ

@main を案内すると、利用者は壊れる変更を勝手に取り込むことになります。

git tag -a v1.0.0 -m "v1.0.0"
git push origin v1.0.0

# v1 は「動くタグ」。最新の 1.x を指し続ける
git tag -f v1
git push -f origin v1

利用者には @v1 を案内し、固定したい人には @v1.0.0 があると伝えます。 リリースのたびに v1 を進めます。

git tag -f v1 && git push -f origin v1

公開タグが本当に動くかを CI で確かめる

ここが一番効きました。

自分のリポジトリで uses: ./ として動作確認するのは簡単ですが、 それが通ってもタグが指すコミットが壊れていれば利用者は動きません。 ./ はローカルのチェックアウトを見ているだけだからです。

そこで、CI に「公開しているタグを参照して実行する」ジョブを足します。

jobs:
  use-the-action:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./                      # ローカル
        with:
          path: .

  published-tag:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: your-name/your-tool@v1  # 公開タグ
        with:
          path: .

これで、タグの張り替えを間違えた瞬間に自分の CI が落ちます。 利用者のリポジトリで落ちる前に気づけます。

自作ツールを自分自身に対して実行できる種類のもの(linter、フォーマッタ、 リンクチェッカーなど)なら、この形が特に相性がいいです。 「使える」が主張ではなく、毎回検査されている状態になります。

Marketplace に出すかどうか

action.ymlbranding を書いておくと、GitHub の UI から Marketplace への公開を案内されます。出さなくても uses: では使えるので、 急ぐ必要はありません。

出すと検索経路が1つ増えるので、リポジトリの説明とトピックを整えたうえで 出しておく価値はあります。

まとめ

この形で配っている小さな CLI(Markdown のリンク切れ検出)を MIT で公開しています。


Claude Code に設計・実装・レビューを別々の人格として分担させ、GitHub Issue と ブランチを軸に並列開発を回すための設定一式を MIT で公開しています。 コピーして ./setup.sh を叩けば動きます。技術スタックには依存しません。

https://github.com/quintetkit/quartet

このワークフローだけで実際にツールを 1 つ作りました。Issue の分割から PR、 レビュー、マージまで記録が全部残っています。うまくいかなかった箇所も消していません。

https://github.com/quintetkit/mdlinkcheck

UI 設計人格・レビュー基準・Issue 単位の並列実行スクリプト・実践ガイド 10 章を 足したものは製品ページにあります。

この運用そのものを配っています

4 人格版 Quartet は MIT で無料公開しています。UI 設計人格・レビュー基準・ Issue 単位の並列実行スクリプト・実践ガイド 10 章を足した Quintet は有料版です。

無料版を見る 製品ページ