← ブログに戻る

FUNDING.ymlを置いてもSponsorボタンは出ない: 42リポジトリを棚卸しした

昨日、OSSのリポジトリを3つ公開しました。支援導線も整えたつもりでした。アカウント共通のFUNDING.ymlは継承されているし、APIを叩けばfundingLinksも返ってくる。ところがリポジトリのページを開くと、Sponsorボタンがどこにもありません。

APIは「ある」と言い、ページは「ない」と言う。原因を追ったらGitHubの仕様が二層構造になっていて、しかも片方の層はCLIでリポジトリを作る人だけが踏む作りでした。勢いで自分のpublicリポジトリ42個を全部棚卸ししたので、その記録を残します。

Sponsorボタンは二層構造

ボタンの表示には、独立した2つの設定が両方揃っている必要があります。

役割設定場所
FUNDING.yml何を表示するか(リンク先のリスト).github/FUNDING.yml
Sponsorshipsフラグ表示するかどうかrepo Settings → Features のチェックボックス

FUNDING.ymlは、.githubという名前のリポジトリを作ってそこに1枚置くと、アカウント内の全publicリポジトリのデフォルトになります。私はここに GitHub Sponsors と Ko-fi を書いていて、これは新しいリポジトリにも自動で効いていました。

問題はもう1つの層です。Web UIからFUNDING.ymlを作ると、フラグも一緒にオンになります。しかしgh repo createやgit pushでリポジトリを作ると、フラグはfalseのままです。つまりブラウザで設定した人は存在にすら気づかず、CLIで量産する人だけが静かに踏みます。

さらにこのフラグ、REST APIには存在しません。GraphQLのhasSponsorshipsEnabledだけです。gh repo editのオプションを探しても出てこないのはこのためで、有効化はこう書きます。

id=$(gh api graphql -f query='{ repository(owner: "you", name: "repo") { id } }' \
  --jq '.data.repository.id')

gh api graphql -f query='
mutation($id: ID!) {
  updateRepository(input: {repositoryId: $id, hasSponsorshipsEnabled: true}) {
    repository { name hasSponsorshipsEnabled }
  }
}' -f id="$id"

「APIが返す」と「表示されている」は別物

冒頭の誤認はこれでした。GraphQLでfundingLinksを引くとSponsorsとKo-fiの2件がきれいに返ってきたので、表示されていると判断した。実際にはそれはFUNDING.ymlが継承されている証明であって、ボタンが出ている証明ではありません。

検証は実ページに聞くのが確実です。

curl -s "https://github.com/you/repo" | grep -c "Sponsor this project"
# 1 なら右サイドバーに表示されている

42リポジトリを棚卸しした結果

同じ漏れが他にもあるはずだと思い、publicリポジトリ42個を全部調べました。

状態repo数対応
ボタンが出ていた12(うち3つは同日の朝に直したばかり)
現役の自作repoでフラグ漏れ9GraphQLで有効化
archived18対象外
fork3対象外

ボタンが出ていた12個は、3つが当日の朝、9つが前日に、どちらも手作業で直した分でした。つまり自然にボタンが出ていたリポジトリは、42個中0個です。棚卸しにはもう1つ収穫があって、過去に個別設置したFUNDING.ymlが9リポジトリに残っており、そのうち8つは古い内容(Sponsorsのみ)でした。個別ファイルはアカウントデフォルトを上書きするので、この8リポジトリではKo-fiリンクが欠けたままだった。個別ファイルは全部削除して、.githubの1枚に寄せました。

FUNDING.ymlをリポジトリごとにコピーして回るのは、二重管理の始まりです。後からデフォルトを更新しても、古い個別ファイルが勝ち続けます。

自分のアカウントを監査するスクリプトはこれだけです。

OWNER=you
gh repo list "$OWNER" --visibility public --limit 200 --json name --jq '.[].name' |
while read -r name; do
  flag=$(gh api graphql -f query="{ repository(owner: \"$OWNER\", name: \"$name\") \
    { hasSponsorshipsEnabled } }" --jq '.data.repository.hasSponsorshipsEnabled')
  echo "$flag  $name"
done | sort

falseの行が、ボタンの出ていないリポジトリです。

触らないと決めたもの

全部trueにすれば終わり、とはしませんでした。

archivedの18個は、そもそもread-onlyなのでmutationが通りません。unarchiveすれば変えられますが、10年前のAndroidサンプルにまで支援を募る執念は私にはありませんでした。

forkの3個は意図的に見送りました。調べてみると、fork由来のFUNDING.ymlにはfork元作者の支援設定が入っています。手元の例では、あるターミナルアプリのforkにconnectbot作者のGitHub Sponsorsが設定されていました。これを消して自分のボタンを立てると、他人の作品で自分への支援を募る形になります。fork元の設定はそのまま温存が筋だと思います。

受け皿は無料、機会損失は静かに積もる

収益の話を正直に書くと、私のSponsorsにはまだ語れる数字がありません。ただ、受け皿が無ければゼロが確定します。GitHub Sponsorsは個人からの支援にプラットフォーム手数料がかからず、併記しているKo-fiも寄付のプラットフォーム手数料は0%なので、置いておくコストは設定の5分だけです。個人開発でOSSを出すなら、リポジトリを作った瞬間に済ませておく類いの作業です。

最後に白状すると、私はこの罠を前日にも別のリポジトリで踏んでいて、対処法のメモまで残していました。それでも翌日、新しい3リポジトリで同じ漏れをやった。記憶は当てにならないので、リポジトリ公開手順のチェックリストにフラグ有効化と実ページ検証を組み込みました。この記事も、そのチェックリストの延長です。