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?

(検証中)GitHub Webhookを使った操作自動ロールバックシステムの構築手順のメモ

Last updated at Posted at 2025-02-27

※以下はClaude 3.7 Sonnetで聞いてみただけの記事なので未検証です。
これから検証するためのメモです。これを見て試して失敗しても責任は負いかねますので
ご了承ください。

このガイドでは、GitHubで何らかの操作(例:イシューの作成)が行われたときに自動的にそれを検知し、その操作を取り消す(ロールバック)するシステムをAWS Lambda、API Gateway、GitHub Webhookを使って構築する方法を詳しく説明します。

目次

  1. GitHub個人アクセストークンの作成
  2. Lambda関数の作成
  3. API Gatewayの設定
  4. GitHub Webhookの設定
  5. テスト方法
  6. トラブルシューティング

1. GitHub個人アクセストークンの作成

GitHub APIを呼び出すには、アクセストークンが必要です。

  1. GitHubにログイン: あなたのGitHubアカウントにログインします
  2. 設定ページに移動: 右上のプロフィールアイコンをクリックし、「Settings」を選択
  3. 開発者設定に移動: 左側のメニューの下部にある「Developer settings」をクリック
  4. 個人アクセストークンを選択: 「Personal access tokens」→「Tokens (classic)」をクリック
  5. 新しいトークンを生成: 「Generate new token」→「Generate new token (classic)」をクリック
  6. トークンの設定:
    • Token name: GitHubWebhookRollbackなど分かりやすい名前
    • Expiration: 有効期限(まずは30日程度に設定)
    • Select scopes: 最低限以下の権限が必要
      • repo (リポジトリへのフルアクセス権)
    • 「Generate token」ボタンをクリック
  7. トークンをコピー: 生成されたトークンをコピーして安全な場所に保存(この画面を閉じると二度とトークン全体を見ることができません)

2. Lambda関数の作成

  1. AWSコンソールにログイン: AWSマネジメントコンソールにログインします

  2. Lambda画面に移動: サービス一覧から「Lambda」を選択

  3. 関数の作成:

    • 「関数の作成」ボタンをクリック
    • 「一から作成」を選択
    • 関数名: GitHubWebhookHandler
    • ランタイム: Node.js 20.x
    • アーキテクチャ: x86_64
    • 「関数の作成」ボタンをクリック
  4. Lambda関数のコードを記述:

    • 表示されるコードエディタに以下のコードを入力:
const https = require('https');

// 環境変数からGitHubのアクセストークンを取得
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;

exports.handler = async (event) => {
    try {
        // リクエストボディをパース
        const webhookPayload = JSON.parse(event.body);
        console.log('Received webhook payload:', JSON.stringify(webhookPayload));
        
        // イベントタイプを確認
        const githubEvent = event.headers['X-GitHub-Event'] || event.headers['x-github-event'];
        console.log('GitHub Event:', githubEvent);
        
        // リポジトリ情報とアクション情報を取得
        const repo = webhookPayload.repository.full_name;
        const action = webhookPayload.action;
        console.log(`Repository: ${repo}, Action: ${action}`);
        
        // 適切なロールバックアクションを実行
        let result;
        if (githubEvent === 'issues' && action === 'opened') {
            // イシューが作成された場合、そのイシューを閉じる
            const issueNumber = webhookPayload.issue.number;
            result = await closeIssue(repo, issueNumber);
            console.log(`Closed issue #${issueNumber}`);
        } else {
            console.log(`No rollback action defined for event '${githubEvent}' with action '${action}'`);
            result = { message: 'No rollback action performed' };
        }
        
        // 成功レスポンスを返す
        return {
            statusCode: 200,
            body: JSON.stringify({
                message: 'Webhook processed successfully',
                result: result
            })
        };
    } catch (error) {
        // エラーログ
        console.error('Error processing webhook:', error);
        
        // エラーレスポンスを返す
        return {
            statusCode: 500,
            body: JSON.stringify({
                message: 'Error processing webhook',
                error: error.message
            })
        };
    }
};

// GitHubのイシューを閉じる関数
async function closeIssue(repo, issueNumber) {
    const options = {
        hostname: 'api.github.com',
        path: `/repos/${repo}/issues/${issueNumber}`,
        method: 'PATCH',
        headers: {
            'User-Agent': 'AWS-Lambda',
            'Content-Type': 'application/json',
            'Authorization': `token ${GITHUB_TOKEN}`,
            'Accept': 'application/vnd.github.v3+json'
        }
    };
    
    const data = JSON.stringify({
        state: 'closed'
    });
    
    return new Promise((resolve, reject) => {
        const req = https.request(options, (res) => {
            let responseBody = '';
            
            res.on('data', (chunk) => {
                responseBody += chunk;
            });
            
            res.on('end', () => {
                if (res.statusCode >= 200 && res.statusCode < 300) {
                    resolve(JSON.parse(responseBody));
                } else {
                    reject(new Error(`GitHub API responded with status code ${res.statusCode}: ${responseBody}`));
                }
            });
        });
        
        req.on('error', (error) => {
            reject(error);
        });
        
        req.write(data);
        req.end();
    });
}
  1. 環境変数の設定:

    • Lambda関数の「設定」タブをクリック
    • 「環境変数」セクションを選択し、「編集」ボタンをクリック
    • 新しい環境変数を追加:
      • キー: GITHUB_TOKEN
      • 値: 先ほど生成したGitHubアクセストークン
    • 「保存」ボタンをクリック
  2. タイムアウトの設定:

    • Lambda関数の「設定」タブで、「一般設定」セクションの「編集」ボタンをクリック
    • タイムアウトを10秒に設定(デフォルトの3秒だと足りない場合があります)
    • 「保存」ボタンをクリック
  3. コードのデプロイ

    • 「コード」タブから「Deploy」ボタンをクリック

3. API Gatewayの設定

  1. API Gatewayコンソールに移動: AWSコンソールのサービス一覧から「API Gateway」を選択

  2. APIの作成:

    • 「APIを作成」ボタンをクリック
    • 「REST API」を選択し、「構築」ボタンをクリック
    • 「REST API」が選択されていることを確認
    • API名: GitHubWebhookAPI
    • 「APIの作成」ボタンをクリック
  3. リソースの作成:

    • 「リソースの作成」ボタンをクリック
    • リソース名: webhook
    • リソースパス: /webhook
    • 「CORS(Cross-Origin Resource Sharing)の有効化」はチェックしない
    • 「リソースの作成」ボタンをクリック
  4. メソッドの作成:

    • 新しく作成した /webhook リソースを選択
    • 「メソッドの作成」ボタンをクリック
    • ドロップダウンから「POST」を選択し、チェックマークをクリック
    • 統合タイプ: 「Lambda関数」
    • Lambda関数: 先ほど作成した GitHubWebhookHandler を入力(入力中に候補が表示されます)
    • 「メソッドを作成」ボタンをクリック
    • 「Lambda関数に権限を追加することを確認します」というポップアップが表示されたら「OK」をクリック
  5. メソッドレスポンスの設定:

    • 「メソッドレスポンス」をクリック
    • 「レスポンス 200」を編集
    • 「ヘッダーの追加」をクリック
    • 「Access-Control-Allow-Origin」と入力し、「保存」ボタンをクリック
  6. 統合レスポンスの設定:

    • 「統合レスポンス」をクリック
    • 「デフォルト-レスポンス」を編集
    • 「ヘッダーマッピング」セクションで「Access-Control-Allow-Origin」の値に「'*'」と入力(シングルクォートを含む)
    • 「保存」ボタンをクリック
  7. APIのデプロイ:

    • 「APIをデプロイ」を選択
    • デプロイされるステージ: 「新しいステージ」
    • ステージ名: prod
    • 「デプロイ」ボタンをクリック
  8. エンドポイントURLの取得:

    • デプロイされたAPIの情報が表示される画面で、「URLを呼び出す」に記載されたURLをメモ
    • このURLは次のステップのGitHub Webhook設定で使用します
    • 例: https://abcd1234.execute-api.us-east-1.amazonaws.com/prod/webhook
      ※webhookを末尾に足す

4. GitHub Webhookの設定

  1. 対象GitHubリポジトリに移動: WebhookでイベントをキャッチしたいGitHubリポジトリのページに移動
  2. 設定ページに移動: リポジトリページの上部メニューから「Settings」タブをクリック
  3. Webhookセクションに移動: 左側のメニューから「Webhooks」を選択
  4. 新しいWebhookを追加:
    • 「Add webhook」ボタンをクリック
    • Payload URL: API GatewayのエンドポイントURL(/webhookまで含む)を入力
    • Content type: application/json を選択
    • Secret: 空のままでも良いですが、セキュリティを強化したい場合は秘密のトークンを入力し、Lambda関数でも対応する必要があります
    • どのイベントでWebhookを起動するか: Let me select individual events を選択
    • 「Issues」にチェックを入れる(イシュー作成イベントをキャッチする場合)
    • 「Active」にチェックが入っていることを確認
    • 「Add webhook」ボタンをクリック

5. テスト方法

  1. イシューを作成:

    • GitHubリポジトリページに移動
    • 「Issues」タブをクリック
    • 「New issue」ボタンをクリック
    • タイトルと説明を入力して「Create」ボタンをクリック
  2. 結果の確認:

    • イシューが作成された後、すぐに閉じられる(ロールバックされる)はずです
    • イシューリストに戻ると、作成したイシューが「Closed」状態になっていることが確認できます
  3. Lambdaログの確認:

    • AWSコンソールのLambda関数ページに移動
    • 「モニタリング」タブをクリック
    • 「ログ」をクリック(CloudWatchログに移動します)
    • 最新のログストリームをクリックして、処理の詳細を確認
  4. GitHub Webhookの配信履歴確認:

    • リポジトリの「Settings」→「Webhooks」に移動
    • 設定したWebhookをクリック
    • 「Recent Deliveries」セクションでWebhookの配信履歴と結果を確認できます

6. トラブルシューティング

Webhook呼び出しが成功しない場合:

  1. API GatewayのCORSを確認: 統合レスポンスで正しくCORSヘッダーが設定されているか確認
  2. Lambda関数の権限を確認: API GatewayからLambda関数を呼び出す権限が付与されているか確認
  3. GitHubのWebhook設定を確認: ペイロードURLやコンテンツタイプが正しく設定されているか確認
  4. Lambdaのログを確認: CloudWatchログでエラーメッセージを確認
  5. GitHub APIの権限を確認: 個人アクセストークンに十分な権限が付与されているか確認

イシューが閉じられない場合:

  1. GitHubトークンの有効性を確認: トークンが有効であることを確認(期限切れでないか)
  2. Lambda関数のタイムアウトを確認: 処理が完了する前にタイムアウトしていないか確認
  3. Webhookペイロードの構造を確認: Lambda関数内でWebhookペイロードが正しくパースされているか確認

拡張方法

このシステムは、イシューのクローズ(取り消し)だけでなく、さまざまなGitHubイベントに対応できるよう拡張できます:

  1. プルリクエストの自動クローズ: 特定の条件下でプルリクエストを自動的に閉じる
  2. コメントの自動追加: イシューやプルリクエストに自動的にコメントを追加
  3. 特定のラベルの追加/削除: 条件に基づいてラベルを追加または削除
  4. 承認者の自動割り当て: プルリクエストに特定の承認者を自動的に割り当て

Lambda関数のコードを修正することで、これらの機能を実装できます。

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?