0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Asana の全エンドポイントを CLI から叩けるようにした — asana-api コマンドは jq / CSV 出力にも対応

0
Last updated at Posted at 2026-04-25

Asana のタスクに CI からコメントを残したり、特定プロジェクトのタスクを CSV で抜き出したり — こうしたちょっとした操作を、Python スクリプトを書かずにシェル 1 行で済ませたい場面はそれなりにあります。

# CI 完了通知を Asana タスクへコメント投稿
asana-api stories create-story-for-task --task "$TASK_GID" \
  --body '{"data":{"text":"デプロイ完了"}}'

# 特定プロジェクトのタスクを CSV で取り出す
asana-api tasks get-tasks --project "$PID" --all-items --output csv

そのために、公式の python-asana SDK を薄くラップして、Asana の全エンドポイントをコマンドラインから叩ける CLI ツールを作って公開しました。

つくったもの

pip install asana-api-cli
# あるいは独立した CLI として入れたい場合
pipx install asana-api-cli

インストールすると asana-api コマンドが使えるようになります。

export ASANA_ACCESS_TOKEN="1/12345..."          # 必須
export ASANA_DEFAULT_WORKSPACE="12345678"       # 任意(指定すると workspace 引数を省略できる)

# ワークスペース一覧
asana-api workspaces get-workspaces

# プロジェクト一覧
asana-api projects get-projects-for-workspace

# タスク一覧(全ページ自動取得)
asana-api tasks get-tasks --project <PROJECT_GID> --all-items

# 確認用に先頭 5 件だけ
asana-api tasks get-tasks --project <PROJECT_GID> --max-items 5

# タスクを作成(body は JSON 文字列)
asana-api tasks create-task \
  --body '{"data":{"name":"new task","projects":["<PID>"]}}'

# table / csv で出力したり、jq でクエリしたり
asana-api tasks get-tasks --project <PID> --output table
asana-api tasks get-tasks --project <PID> --query '.data' --output csv

アクセストークンは Asana Developer Console で発行できます。

特徴

Asana のほぼ全 API をカバー

世の中には Asana を CLI から叩けるツールがいくつかありますが、多くはよく使われる一部の機能(タスク作成・一覧など)しか実装していません。

asana-api公式 SDK の *Api クラスを走査して、そのメソッドを呼び出すサブコマンドを事前に生成 しています。生成済みのコードはパッケージに組み込まれて PyPI にリリースされます。

その結果、SDK が提供している API は基本的にすべて呼び出せます。実際、現時点で 46 個のサブコマンドグループがあります。

access-requests        custom-types          memberships              project-templates
allocations            events                organization-exports    rates
attachments            exports               portfolio-memberships   reactions
audit-log-api          goal-relationships    portfolios              roles
batch-api              goals                 project-briefs          rules
budgets                jobs                  project-memberships     sections
custom-field-settings                        project-statuses        ...
custom-fields                                                        workspaces

SDK のバージョンが上がったときは、こちらでコード生成を回し直し、新しいバージョンとして PyPI にリリースする運用にしています。利用者側は pip install -U asana-api-cli するだけで新しいエンドポイントが使えるようになります。

リスト取得が便利

Asana の一覧系 API は 1 リクエストで最大 100 件しか返しません。asana-api ではオプションを付けるだけで、自動でページをまたいで指定件数を取得できます。

  • --max-items N — N 件まで取得(確認用に先頭の数件だけ欲しいときに便利)
  • --all-items — 全ページを取得して 1 つの JSON にまとめて出力

SDK を直接使う場合は自分でループを書いて件数を制御する必要がありますが、CLI なら 1 行で済み、結果がまとまった JSON で返ってくるので --query (jq) や --output csv にそのまま流せます。

# 1 ページ分だけ(最大 100 件)
asana-api tasks get-tasks --project <PID>

# 確認用に先頭 5 件だけ
asana-api tasks get-tasks --project <PID> --max-items 5

# 全ページを取得
asana-api tasks get-tasks --project <PID> --all-items

--query (jq) と --output で結果を整形

レスポンスには --query で jq 式をそのまま渡せます。--outputjson / table / csv / text から選択でき、欲しい形のまま他のツールに流せます。

# タスク名と担当者だけを抜き出して CSV に
asana-api tasks get-tasks --project <PID> --all-items \
  --query '.data | map({name, assignee: .assignee.name})' \
  --output csv

--help が SDK の docstring から自動生成される

サブコマンドの --help は SDK の docstring から生成しています。
そのため「このエンドポイントはどんな引数が要るんだっけ?」と毎回ドキュメントを調べる必要がなく、--help を見れば必須引数・任意引数が分かります。

asana-api tasks --help
asana-api tasks get-tasks --help
asana-api tasks create-task --help

シェル補完に対応

Python のコマンドラインライブラリ click の機能を利用してシェル補完にも対応しています。bash の場合は ~/.bashrc に以下を追記するだけです(zsh / fish も同様)。

eval "$(_ASANA_API_COMPLETE=bash_source asana-api)"

サブコマンドやオプションが TAB で補完できるようになります。

タスクへのコメント投稿(CI 連携の例)

冒頭で挙げた stories create-story-for-task の補足です。タスク GID は Asana のブラウザ版でタスクを開いたときの URL から拾えます(https://app.asana.com/.../task/<TASK_GID>/...<TASK_GID> 部分)。

CI 完了時や障害通知時にタスクへ自動でコメントを残す、といった連携もシェルスクリプトで数行で書けます。コメント本文を動的に組み立てるなら jq -nc で JSON を安全に作るのが楽です。

# CI のジョブ末尾で実行する例
asana-api stories create-story-for-task \
  --task "$ASANA_TASK_GID" \
  --body "$(jq -nc --arg t "デプロイ完了: $GIT_COMMIT" '{data:{text:$t}}')"

なぜ作ったか

一番の動機は、実際のシステムに SDK を組み込む前に、コマンドラインから API の挙動をひと通り確認できるようにしたかったことです。

SDK をいきなりアプリケーションに組み込んでしまうと、レスポンスの構造が想定と違っていたり、必須パラメータが不足していたりしたときに、コードを書き直して再実行するサイクルを何度も回すことになります。CLI から同じ SDK 経由で叩いて、引数・レスポンス・エラーの形を先に確認しておけば、組み込み時の試行錯誤を大幅に減らせます。

加えて、Asana を業務で使っていると、API をシェルから直接叩きたい場面もそれなりに出てきます。

  • 業務日報
    • テキストファイルに記述した日報をテンプレートに流し込んで Asana に投稿
  • システム連携(障害通知など)
    • 監視システムからの障害通知を Asana のタスクとして自動起票する
    • 既存タスクのステータスを外部システムから書き換える

しかしその都度 Python スクリプトを書くのは大げさで、かといって既存の CLI ツールでは目的の API がカバーされていないことも多々ありました。

そこで「SDK をラップして呼び出すコマンドを生成してしまえば、API の網羅性は SDK と同じになる」という発想でこのツールを作りました。呼び出しコードを自動生成する形にしておけば、SDK のバージョンアップにも追従しやすくなります。

アーキテクチャ概要

中身は非常にシンプルで、python-asana SDK の *Api クラスを走査し、そのメソッドを呼び出す click のサブコマンドを事前に生成しているだけです。生成済みのコードはリポジトリに含めてそのまま PyPI にリリースしているため、ユーザー環境で SDK の解析処理は走りません。

ライブラリとしての利用

CLI が主目的ですが、AsanaSession を経由して SDK を呼ぶこともできます。

from asana_api_cli import AsanaSession
import asana

session = AsanaSession(token="1/12345...", paginate=True)
tasks_api = asana.TasksApi(session.client)
for task in tasks_api.get_tasks({"project": "123"}):
    print(task)

とはいえ、Python から使うなら asana SDK を直接使うのが普通だと思うので、おまけ程度の機能です。

まとめ

  • pip install asana-api-cliasana-api コマンドが入る
  • SDK を薄くラップしているので、Asana のほぼ全 API がコマンドラインから叩ける
  • --max-items / --all-items で自動ページ送り、--query (jq) / --output (json/table/csv/text) で実用的な使い勝手
  • SDK のバージョンが上がったら、こちらでコード生成を回し直して新バージョンをリリース。利用者は pip install -U で追従できる

Asana の API を「ちょっと触ってみたい」「シェルから一発で叩きたい」と思っていた方の参考になれば嬉しいです。

不具合報告や「このオプションが欲しい」といった要望は GitHub Issues / PR で歓迎します。記事へのコメントや LGTM もモチベーションになるので、参考になったらぜひ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?