1. はじめに
qiita-cliというQiitaの記事をGithub上で管理投稿できるライブラリが公式から用意されています。
ブラウザから投稿すると投稿時にポストするかのモーダルが出てくれますが、qiita-cliからは対応してないみたいなので自動でポストするように改変してみます。
バージョンの追従が非常にめんどくさくなるのでオススメはしません。
ここからは企業様のレポジトリをforkして改変していくので一応ライセンス表記
qiita-cli
は、Apache License 2.0の下でライセンスされています。詳細については、LICENSEファイルを参照してください。
2. 環境
・すでにqiita-cliのセットアップが完了しているローカルレポジトリ
・Node.js 18.18.0 以上 (↑がセットアップできているなら入っているはず)
3. Twitter API
事前にこちらの記事の手順で各種認証情報を取得しておきます。
必要な情報はこちらの画面の「API Key and Secret」と「Access Token and Secret」です。
4. qiita-cli
forkしてくる
公式のレポジトリからfrokしました。
適当にdevというブランチを切りここで作業していきます。
Xにポストする処理
どこに作ってもいいんですがsrc/lib/
以下にXにポストするための処理を用意しておきます。
先ほど用意したTwitterAPIの認証情報をここで環境変数から入れます。
import { TwitterApi } from "twitter-api-v2";
export const tweet = async (args: string[]) => {
// 環境変数が設定されているか確認
const apiKey = process.env.TWITTER_API_KEY;
const apiSecret = process.env.TWITTER_API_SECRET;
const accessToken = process.env.TWITTER_ACCESS_TOKEN;
const accessSecret = process.env.TWITTER_ACCESS_SECRET;
if (!apiKey || !apiSecret || !accessToken || !accessSecret) {
console.log("Twitter API keys are not set. Skipping tweet.");
return;
}
// 環境変数が揃っている場合のみ、Twitter APIクライアントを初期化
const client = new TwitterApi({
appKey: apiKey,
appSecret: apiSecret,
accessToken: accessToken,
accessSecret: accessSecret,
});
const message = args.join(" ");
try {
const tweetResponse = await client.v2.tweet(message);
console.log("Successfully tweeted:", tweetResponse.data);
} catch (err) {
console.error("Failed to send tweet:", err);
}
};
qiita-api
内部的にはqiita-apiを呼び出しているみたいでこちらをラップしているディレクトリが./qiita-api
以下にあります。
こちらのPOST /api/v2/items
を使って投稿しているみたいです。
このAPIで投稿時のURLがレスポンスに入っているみたいなんですが、qiita-cliでは受け取っているオブジェクトにフィールドが含まれていないので追加します。
この際、null許容で追加しないと予め用意されているテストでエラーが出たので?
をつけています。
export interface Item {
body: string;
id: string;
private: boolean;
tags: {
name: string;
}[];
title: string;
organization_url_name: string | null;
coediting: boolean;
created_at: string;
updated_at: string;
slide: boolean;
url?: string; // urlをnull許容で追加
}
投稿する時にポストする
src/commands/publish.ts
が投稿するときのロジックっぽいのでこちらに先ほどのポストする処理を追加します。
長いので既存の処理は省略します。
// ---- 省略
import { tweet } from "../lib/tweet"; // インポート
// ---- 省略
const promises = targetItems.map(async (item) => {
let responseItem: Item;
if (item.id) {
responseItem = await qiitaApi.patchItem({
rawBody: item.rawBody,
tags: item.tags,
title: item.title,
uuid: item.id,
isPrivate: item.secret,
organizationUrlName: item.organizationUrlName,
slide: item.slide,
});
console.log(`Updated: ${item.name} -> ${item.id}`);
} else {
responseItem = await qiitaApi.postItem({
rawBody: item.rawBody,
tags: item.tags,
title: item.title,
isPrivate: item.secret,
organizationUrlName: item.organizationUrlName,
slide: item.slide,
});
await fileSystemRepo.updateItemUuid(item.name, responseItem.id);
// ---- ここを追加 Xにポストする処理を追加
const tweetMessage = `記事を投稿しました!\n\n${responseItem.title}\n${responseItem.url}\n#Qiita`;
try {
console.log(`private is : ${responseItem.private}`);
if(!responseItem.private){
await tweet([tweetMessage]);
}
} catch (err) {
console.error("Failed to post on Twitter:", err);
}
console.log(`Posted: ${item.name} -> ${responseItem.id}`);
// ---- 追加ここまで
}
await fileSystemRepo.saveItem(responseItem, false, true);
});
// ---- 省略
};
限定記事の場合、ツイートされないようにしています。(限定記事書かないけど)
if(!responseItem.private){
await tweet([tweetMessage]);
}
Github Actionの設定をしないならこれでqiita-cliの改変は終わりです。
Github Action
git push
時に投稿とポストをしたい場合はこちらも改変していきます。
npm install -g
している部分を今作成している自分のレポジトリにしてローカルインストールにおきます。
また、qiita
コマンドの実行をnpxで行うようにしておきます。
name: "Publish articles to Qiita"
description: "Publish articles to Qiita using qiita-cli"
author: "Qiita Inc."
inputs:
root:
required: false
default: "."
description: "Root directory path"
qiita-token:
required: true
description: "Qiita API token"
runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: "20.16.0"
- name: Install qiita-cli
# ここを自分のレポジトリにする
run: npm install github:Pokeyama/qiita-cli#dev
shell: bash
- name: Publish articles
# npxで実行するようにしておく
run: npx qiita publish --all --root ${{ inputs.root }}
env:
QIITA_TOKEN: ${{ inputs.qiita-token }}
shell: bash
- name: Commit and push diff # Not executed recursively even if `push` is triggered. See https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
run: |
git add ${{ inputs.root }}/public/*
if ! git diff --staged --exit-code --quiet; then
git config --global user.name 'github-actions[bot]'
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
git commit -m 'Updated by qiita-cli'
git push
fi
shell: bash
ここがうまくいかなかった。
なんでかグローバルインストールだとqiitaコマンドが使えなくて苦戦。
色々あってこの形になりました。
ありがとうM平さん。
5. qiita-cliをインストールしているレポジトリ
ここからはqiita-cliを使用している記事管理レポジトリを少し改変していきます。
元のqiita-cliをアンインストールして、先ほど改変したレポジトリからnpm install
します。
npm uninstall @qiita/qiita-cli
npm install github:Pokeyama/qiita-cli#dev --save-dev
.envに認証情報を書く
ルートディレクトリに.envファイルを作成して以下の対応する変数に最初用意したTwitterAPIの認証情報を書いておきます。
.gitignore
に追加するの忘れずに。
TWITTER_API_KEY=xxxxxxxxxxx
TWITTER_API_SECRET=xxxxxxxxxxx
TWITTER_ACCESS_TOKEN=xxxxxxxxxxx
TWITTER_ACCESS_SECRET=xxxxxxxxxxx
Github Actionを使わないならこの時点で自動ポストができているはずです。
npx qiita publish {記事名}
Github Action
git push
時にも投稿したい場合こちらも追記します。
Github上のSettings > Secrets and variacles > Actions
に.env
に入れた時と同じTwitterAPIの認証情報を入れます。
ymlもTwitterAPIの認証情報を受け取るように編集します。
# Please set 'QIITA_TOKEN' secret to your repository
name: Publish articles
on:
push:
branches:
- main
- master
workflow_dispatch:
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
publish_articles:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: Pokeyama/qiita-cli/actions/publish@dev
with:
qiita-token: ${{ secrets.QIITA_TOKEN }}
root: "."
# TwitterAPI認証情報を受け取れるようにしておく
env:
TWITTER_API_KEY: ${{ secrets.TWITTER_API_KEY }}
TWITTER_API_SECRET: ${{ secrets.TWITTER_API_SECRET }}
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
TWITTER_ACCESS_SECRET: ${{ secrets.TWITTER_ACCESS_SECRET }}
以上でgit pull
時にも投稿されるようになります。
まとめ
NodeもTypeScriptも素人なんでおかしいところがあるかもしれないです。
特にqiita-cli側のnpm install時にうまくコマンドをうまく利用できなかった理由が今でもわかってないです。
元のレポジトリを弄っちゃっているので、今後はqiita-cliのバージョンに追従するのが大変だなあという印象です。
XのAPIの規約がコロコロ変わるから公式では実装難しいんだろうなって作ってて思いました。