GitHub IssuesとPull RequestsをAsanaタスクに自動連携する仕組みを作った話
はじめに
エンジニアチームでは、タスク管理ツールとGitHubの二重管理に悩まされることはありませんか?
私たちのチームでは、プロジェクト管理にAsanaを使用していますが、実際の開発作業はGitHub上で行われます。この結果、以下のような課題が発生していました:
- GitHub Issueを作成したら、Asanaにも同じタスクを手動で作成する必要がある
- IssueをクローズしたらAsanaタスクも手動で完了にする必要がある
- コメントやステータスの更新を両方のツールで行う必要がある
- どちらかの更新を忘れて、情報の不整合が発生する
n8nなどの自動化ツールもありますが、GitHub Actionsで連携したいと考えました!
この記事では、これらの課題を解決するために実装した、GitHub IssuesとPull RequestsをAsanaタスクと自動連携する仕組みについて紹介していこうと思います!
実装した機能の概要
1. GitHub Issues → Asana タスク自動連携
以下の自動化を実現しました!
Issue作成時
- Asanaプロジェクトに新しいタスクを自動作成
- タスク名に
[リポジトリ名]
のプレフィックスを付けて識別しやすく - タスクの説明にGitHub IssueのURLを含める
- 指定したセクション(例:
frontend
)に自動配置
Issue状態変化時
- クローズ時: 対応するAsanaタスクを自動で完了状態にする
- 再オープン時: Asanaタスクを未完了状態に戻す
- コメント追加時: Asanaタスクにコメントとして自動追加
2. Pull Request → Asana タスク連携
Pull RequestとAsanaタスクの連携は、Asanaの公式GitHub連携機能を使用して実現しています!
※こちらの設定については、Asanaの公式から提供されている情報を参照してください!
仕組み
AsanaタスクのGitHubフィールドにPull RequestのURLを追加することで、以下の情報が自動的に表示されます:
- Pull Requestのステータス(Open/Closed/Merged)
- レビュー状況
- ビルドステータス
- 変更行数
使用方法
- Asanaタスクを開く
- GitHubフィールドを見つける(公式連携を有効にすると表示される)
-
Pull RequestのURLをコピー
https://github.com/your-repo/pull/123
- GitHubフィールドにURLを貼り付ける
すると、Asanaタスク内に自動的にPull Requestの詳細情報がウィジェットとして表示され、リアルタイムでステータスが更新されます!Pull Requestがマージされると、Asana側でもステータスが自動的に「Closed」に変わります。
技術的な実装詳細
システム構成
GitHub Event → GitHub Actions → Node.js Script → Asana API → Asanaタスク
1. Node.jsによるAsana API連携スクリプト
scripts/asana-integration.js
の主要な実装です!
// Asana API にHTTPリクエストを送信する関数
function makeAsanaRequest(method, path, data = null) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'app.asana.com',
port: 443,
path: `/api/1.0${path}`,
method: method,
headers: {
'Authorization': `Bearer ${ASANA_PAT}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
try {
const parsedData = JSON.parse(responseData);
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(parsedData);
} else {
reject(new Error(`Asana API Error: ${res.statusCode}`));
}
} catch (error) {
reject(new Error(`JSON Parse Error: ${error.message}`));
}
});
});
req.on('error', reject);
if (data) {
req.write(JSON.stringify(data));
}
req.end();
});
}
GitHub Issueからのタスク作成
async function createAsanaTask(issue) {
const taskData = {
data: {
name: `[${repositoryName}] ${issue.title}`,
notes: `Repository: ${repositoryName}
Issue #${issue.number}
${issue.body || ''}
GitHub Issue: ${issue.html_url}`,
projects: [ASANA_PROJECT_ID],
workspace: ASANA_WORKSPACE_ID,
external: {
gid: `github_issue_${repositoryName}_${issue.number}`,
data: issue.html_url
}
}
};
try {
const result = await makeAsanaRequest('POST', '/tasks', taskData);
console.log(`✅ Asanaタスクを作成しました: ${result.data.gid}`);
return result.data;
} catch (error) {
console.error('❌ Asanaタスク作成エラー:', error.message);
throw error;
}
}
セクション管理機能
タスクを特定のセクションに自動配置する機能も実装しました:
async function moveTaskToSection(taskId, sectionId) {
try {
const result = await makeAsanaRequest('POST', `/sections/${sectionId}/addTask`, {
data: { task: taskId }
});
console.log(`✅ タスクをセクションに移動しました`);
return result.data;
} catch (error) {
console.error('❌ タスク移動エラー:', error.message);
throw error;
}
}
2. GitHub Actions ワークフロー
.github/workflows/github-issues-to-asana.yml
:
name: GitHub Issues to Asana Tasks
on:
issues:
types: [opened, closed, reopened]
issue_comment:
types: [created]
jobs:
sync-issues-to-asana:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Sync Issue to Asana with Section Management
env:
ASANA_PAT: ${{ secrets.ASANA_PAT }}
ASANA_WORKSPACE_ID: ${{ secrets.ASANA_WORKSPACE_ID }}
ASANA_PROJECT_ID: ${{ secrets.ASANA_PROJECT_ID }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ASANA_SECTION_FRONTEND: "frontend" # リポジトリごとにセクション管理する場合はシークレットで管理することを推奨
run: node scripts/asana-integration.js
continue-on-error: true
セットアップ手順
Issues連携のセットアップ
1. Asana Personal Access Token の取得
- Asana Developer Console にアクセス
- Personal Access Token を作成
- 必要な権限を付与(タスクの読み書き、プロジェクトへのアクセス)
2. Workspace ID と Project ID の取得
# Workspace 一覧取得
curl -H "Authorization: Bearer <ASANA_PAT>" \
https://app.asana.com/api/1.0/workspaces
# プロジェクト一覧取得
curl -H "Authorization: Bearer <ASANA_PAT>" \
https://app.asana.com/api/1.0/workspaces/<WORKSPACE_ID>/projects
3. GitHub Secrets の設定
GitHubリポジトリの Settings > Secrets and variables > Actions に以下を追加:
-
ASANA_PAT
: Asana Personal Access Token -
ASANA_WORKSPACE_ID
: AsanaのワークスペースID -
ASANA_PROJECT_ID
: AsanaのプロジェクトID
4. ファイルの配置
-
scripts/asana-integration.js
を配置 -
.github/workflows/github-issues-to-asana.yml
を配置 - リポジトリにプッシュ
Pull Request連携のセットアップ(公式GitHub連携)
1. Asanaプロジェクトで公式連携を有効化
- Asanaプロジェクトを開く
- 右上の「カスタマイズ」をクリック
- 「アプリ」セクションで「+アプリを追加」を選択
- 「GitHub」を検索して選択
- 「+プロジェクトに追加」をクリック
- GitHubアカウントの認証を行う
2. 連携の確認
連携が成功すると:
- AsanaタスクにGitHubフィールドが追加される
- Pull RequestのURLを貼り付けるだけで自動的に情報が表示される
- Pull Requestのステータス変更がリアルタイムで反映される
注意事項
- この連携はプロジェクト単位で設定する必要がある
- GitHub Enterprise Serverはサポートされていない
- 組織のGitHubリポジトリの場合、適切な権限が必要
工夫した点
1. 複数リポジトリ対応
複数のリポジトリから同じAsanaプロジェクトにタスクを作成できるよう、以下の工夫をしました:
- タスク名に
[リポジトリ名]
のプレフィックスを付与 - タスクの説明にリポジトリ名とIssue番号を含める
- 検索時にリポジトリ名でフィルタリング可能
const taskData = {
data: {
name: `[${repositoryName}] ${issue.title}`,
notes: `Repository: ${repositoryName}\nIssue #${issue.number}\n...`
}
};
2. エラーハンドリング
GitHub Actionsの実行を止めないよう、continue-on-error: true
を設定:
- name: Sync Issue to Asana
run: node scripts/asana-integration.js
continue-on-error: true # エラーが発生してもワークフローを継続
3. デバッグしやすいログ出力
各処理の状態が分かりやすいよう、絵文字付きのログを出力:
console.log(`🚀 GitHub Event: ${eventName}`);
console.log(`✅ Asanaタスクを作成しました: ${result.data.gid}`);
console.log(`❌ Asanaタスク作成エラー: ${error.message}`);
運用してみて分かった効果
-
タスク管理の二重作業が完全に解消された
- 開発者はGitHub Issueを作成するだけでOK
- PMはAsanaでタスクの進捗を確認できる
-
情報の不整合がなくなった
- ステータスが自動同期されるため、常に最新の状態が反映される
- コメントも自動同期されるため、議論の経緯が両方のツールで確認できる
-
チーム全体の生産性が向上
- 手動でのタスク作成・更新作業がなくなり、開発に集中できる
- PMとエンジニアのコミュニケーションがスムーズに
課題と今後の改善点
現在の課題
1. GitHubユーザーとAsanaユーザーの同期問題
最も大きな課題は、GitHubとAsanaのユーザーアカウントが独立しているため、以下の情報を自動同期できないことです:
- assigneeの反映不可: GitHub IssueのassigneeをAsanaタスクの担当者として自動設定できない
- コメント投稿者の識別: GitHubのユーザー名はAsanaに反映されるが、Asanaユーザーとしては認識されない
この問題により、タスクの担当者は手動で設定する必要があり、完全な自動化には至っていません。
解決案の検討
解決案としては以下を検討しており、時間があれば実装する予定です!
- ユーザーマッピングテーブルの作成(GitHub username ↔ Asana user ID)
- チームメンバーのメールアドレスを使った自動マッチング
- Asana APIでユーザー検索を行い、名前ベースでマッチング
その他の改善点
1. 双方向同期の実装
- 現在はGitHub → Asanaの一方向のみ
- Asanaでの変更をGitHubに反映する仕組みも検討中
2. カスタムフィールドへの対応
- Asanaのカスタムフィールド(優先度、期限など)への自動設定
- GitHub LabelsとAsanaタグの連携
3. より柔軟なセクション管理
- Issueのラベルに基づいた動的なセクション配置
- プロジェクトのフェーズに応じた自動移動
まとめ
GitHub IssuesとAsanaタスクの自動連携により、タスク管理の二重作業を完全に解消することができました!
GitHub ActionsとNode.jsを使用することで、比較的シンプルな実装で大きな効果を得ることができます!
同様の課題を抱えているチームの参考になれば幸いです。実装についての質問やフィードバックがありましたら、ぜひコメントでお知らせください!
Discussion