ファイルベースのQiitaクライアントqiitactlを作った話

Qiitaの投稿を[jekyll](https://jekyllrb.com/)や[Hugo](https://gohugo.io/)みたいにマークダウンファイルベースで投稿を管理できるコマンドラインツールをGoで書いた。QiitaとQiita:Teamの自分の投稿を新規作成・取得・更新・削除でき、その他にも幾つかのユーティリティコマンドがある。

## モチベーション

日頃使ってるツールで書きたい。

## 使い方

### インストール

#### バイナリをダウンロードする場合

1. [Latest Release · minodisk/qiitactl](https://github.com/minodisk/qiitactl/releases/latest)から使っているOS用のバイナリをダウンロードする。
2. パスを通す。

#### OSXでHomebrewを使っている場合

```bash:terminal
brew tap minodisk/qiitactl
brew install qiitactl
```

#### `go get`でインストールする場合

```bash:terminal
go get github.com/minodisk/qiitactl
```

### 準備

1. [https://qiita.com/settings/applications](https://qiita.com/settings/applications)の「個人用アクセストークン」からアクセストークンを作る。
2. 作ったアクセストークンを環境変数`QIITA_ACCESS_TOKEN`に設定する。
  - 環境変数を汚したくない場合は、`qiitactl`を実行するディレクトリに`.env`というファイルを作って`QIITA_ACCESS_TOKEN=XXXXXXXXXXX`と書き込んでも良い。

### 取得

まずは記事を取得する作業ディレクトリを作る。

```bash:terminal
mkdir qiita-posts
cd qiita-posts
```

記事一覧を取得する。

```bash:terminal
qiitactl fetch posts
```

`tree -N`するとこんな感じ。

```bash:terminal
.
├── mine
│   ├── 2012
│   │   ├── 06
│   │   │   └── 21
│   │   │       └── Destructuring Assignment.md
│   │   └── 07
│   │       └── 29
│   │           └── nginxで特定ディレクトリをBasic認証から除外する方法.md
:   :
│   └── 2016
│       ├── 01
│       │   ├── 14
│       │   │   └── 開発におけるDocker導入のメリット.md
│       │   └── 25
│       │       └── Kobito for Windows をOSXやLinux用にリビルドするためのDockerfileを書いた.md
│       └── 02
│           ├── 15
│           │   └── Kubernetesのポッドが起動しない原因と対策.md
│           └── 16
│               └── ファイルベースのQiitaクライアントqiitactl.md
└── <qiita-team-name>
    ├── 2015
    │   ├── 01
    │   │   ├── 07
    │   │   │   └── KPT 2015-01-07.md
    :   :   :
```

投稿日ベースのディレクトリとタイトルベースのファイル名で記事が出力される。Qiitaに投稿した記事は`mine`ディレクトリをルートディレクトリとしてマークダウンファイルが出力され[^mine-dir]、Qiita:Teamに投稿した記事はチームIDベースのディレクトリをルートディレクトリとしてマークダウンファイルが出力される。

[^mine-dir]: `mine`というユーザーは存在せず、Qiitaのルーティングではホームの自分の投稿に飛ばされるのでこの名前でディレクトリを作ることにしている。[https://qiita.com/mine](https://qiita.com/mine)

試しに`cat`してみると、`投稿のメタデータのYAML+投稿のタイトル+投稿の本文`というフォーマットになっている。

```markdown:terminal
<!--
id: 5ffd20588b995523756f
url: http://qiita.com/minodisk/items/5ffd20588b995523756f
created_at: 2016-01-14T15:20:25+09:00
updated_at: 2016-01-14T23:08:27+09:00
private: false
coediting: false
tags:
- docker
- GoogleContainerEngine
- tutum
team: null
-->

# 開発におけるDocker導入のメリット

DockerのPros/Consとか今更感ある。他の仮想化技術との比較記事はよく目にするが、開発にどのようなメリット・デメリットがあるのかあまり周知されていないようなので自分なりの感想を書いておく。
...
```

### 更新

取得したファイルを更新してみる。
普段使っているエディタでファイルを編集したら、`update post`でポストを更新しよう。

```bash:terminal
qiitactl update post mine/YYYY/MM/DD/更新する投稿.md
```

### 新規作成

まずは`generate file`コマンドでファイルを作る[^generate-file]。

[^generate-file]: 勿論、自分でファイルを作ってメタデータを書いても良いし、すでにローカルに取得したファイルをコピペしても良い。コピペした場合は、メタデータの`id: XXXXXXXXXXXX`を`id: ""`と変更しておこう。そのままで`create post`しても失敗するし、`update post`するとコピペ元の記事が上書きされてしまう。やっぱり怖いので素直に`generate file`するのをお勧めする。

```bash:terminal
qiitactl generate file "新しい投稿"
```

今日の日付のディレクトリに新しいマークダウンファイルが生成されているので、普段使っているエディタでファイルを編集する。
編集が終わったら`create post`で投稿を作成しよう。

```bash:terminal
qiitactl create post mine/YYYY/MM/DD/新しい投稿.md
```

## ローカルのファイルをどのように管理するか

gitで管理して[Bitbucket](https://bitbucket.org/)とかに上げておくのをお勧めする。

- gitの利点そのまま
  - 履歴
  - 差分
  - ロールバック
- 下書き書き放題[^draft]

[^draft]: [Qiita API v2](https://qiita.com/api/v2/docs)では下書きの取得はできないしQiita上の下書きにも上限があるが、プライベートリポジトリのホストサービスを使うと下書きのファイルを作り放題で多環境からの編集が可能になる。

## 技術的な話

クロスプラットフォームな〜とかバイナリ一つで〜みたいな語られ尽くしたGoでCLIを作る良さみたいなやつを一通り感じられた。

### サブコマンドの命名

サブコマンドは[kubectl](https://cloud.google.com/container-engine/docs/kubectl/)に似せていて、`qiitactl <動詞> <目的語>`みたいな感じになっている。この自然言語のような語順のサブコマンドは使い始めた当初は違和感があったけど、今は迷わずコマンドを打てて好き。

### 迷ったこと

#### ファイル名

ファイル名をどのような仕様にするか迷った。タイトルに使われているASCII以外の文字を排除したりタイトルをエンコードするとぱっと見で何の記事かわからないことになったので、タイトル中のファイル名に使えない数文字をハイフンに置換してあとはそのままのファイル名にした。OSの力を信じている。
使っているOSで何かあったらプルリク下さい。

#### フォーマット

メタデータはYAMLで入れると決めていた。問題はそれをラップする記法を[CommonMarkのHTMLコメント方式](http://spec.commonmark.org/0.23/#example-134)の`<!--...-->`にするのか[jekyllのFront Matter方式](http://jekyllrb.com/docs/frontmatter/)の`---...---`にするのかだった。Front Matter方式を採用しているツールが非常に多いので最後まで揺れたが、可能な限りマークダウンの範疇のフォーマットにしたかったのでCommonMarkのHTMLコメント方式を採用した。[^cdata]

[^cdata]: `<![CDATA[...]]>`？あったなそういうの。[CommonMarkにも存在する](http://spec.commonmark.org/0.23/#example-137)し、用途にあっていそうだけどツール側の対応が少なそうなので見送っている。

### やるべきか迷っていること

`jekyll server`や`hugo server`みたいなライブプレビューするためのサーバを立ち上げるサブコマンドの追加。
せっかくマークダウンがローカルにあるわけなのでマークダウンのプレビューツールでみれば良いし、ツールの役割を小さくしたい気持ちがある。一方でQiita専用のツールなのでスタイルまでほげほげしてあげると実際の投稿前に確認できて良いしこのツール一つでなんとかなるという万能感あって良い気もする。

### やりたいこと

- ファイルをアップロードする何かの追加。
- ファイル書き込みの並行処理。

## リポジトリ

[minodisk/qiitactl: Command line interface to manage the posts in Qiita.](https://github.com/minodisk/qiitactl)
バグ報告・プルリクエストなどお待ちしております。