第11章:高度な機能活用

学習目標

この章を読み終える頃には、GitHubの高度な機能を理解し、より効率的で協力的な開発環境を構築できるようになります。GitHub Packages、GitHub Codespaces、GitHub CLI、Webhooksなどの先進的な機能を活用し、開発チームの生産性向上とワークフローの自動化を実現する方法を身につけます。


11.1 GitHub Packages

ポートフォリオの重要性

パッケージ管理の概念と価値

パッケージ管理とは: ソフトウェアの依存関係やライブラリを効率的に管理・配布する仕組み

日常生活での類推:

図書館システム

  • 本(パッケージ)を分類・管理
  • 利用者が必要な本を簡単に見つけられる
  • 新刊の追加や更新を効率的に行う
  • 貸出履歴や利用統計を管理

コンビニの商品管理

  • 商品(パッケージ)をカテゴリ別に整理
  • バーコード(バージョン)で個別管理
  • 自動発注システム(依存関係解決)
  • 在庫管理と配送最適化

GitHub Packagesの特徴

主要な機能:

統合されたエコシステム

  • GitHubリポジトリとの密な連携
  • シームレスなCI/CDパイプライン
  • 統一されたアクセス制御
  • セキュリティスキャン機能

マルチ言語サポート

  • npm(Node.js)
  • Maven(Java)
  • NuGet(.NET)
  • RubyGems(Ruby)
  • Docker Container Registry
  • Apache Maven(Java)
  • Gradle(Java/Kotlin)

npm パッケージの公開

プロジェクト準備:

// package.json
{
  "name": "@yourusername/my-awesome-library",
  "version": "1.0.0",
  "description": "A sample library for GitHub Packages",
  "main": "index.js",
  "scripts": {
    "test": "jest",
    "build": "webpack --mode production",
    "prepublishOnly": "npm run build && npm test"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/yourusername/my-awesome-library.git"
  },
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/"
  },
  "author": "Your Name <your.email@example.com>",
  "license": "MIT",
  "dependencies": {
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "jest": "^29.0.0",
    "webpack": "^5.0.0"
  }
}

ライブラリのコード例:

// index.js
const _ = require('lodash');

/**
 * 配列から重複を除去して返す
 * @param {Array} array - 処理対象の配列
 * @returns {Array} - 重複が除去された配列
 */
function uniqueArray(array) {
  if (!Array.isArray(array)) {
    throw new Error('Input must be an array');
  }
  return _.uniq(array);
}

/**
 * オブジェクトの深いマージを行う
 * @param {Object} target - マージ先オブジェクト
 * @param {Object} source - マージ元オブジェクト
 * @returns {Object} - マージされたオブジェクト
 */
function deepMerge(target, source) {
  return _.merge(target, source);
}

/**
 * 配列を指定されたサイズに分割する
 * @param {Array} array - 分割対象の配列
 * @param {number} size - チャンクサイズ
 * @returns {Array} - 分割された配列の配列
 */
function chunkArray(array, size) {
  if (!Array.isArray(array)) {
    throw new Error('First argument must be an array');
  }
  if (typeof size !== 'number' || size <= 0) {
    throw new Error('Size must be a positive number');
  }
  return _.chunk(array, size);
}

module.exports = {
  uniqueArray,
  deepMerge,
  chunkArray
};

認証設定:

# GitHub Package Registry への認証
npm login --scope=@yourusername --registry=https://npm.pkg.github.com

# または .npmrc ファイルでの設定
echo "@yourusername:registry=https://npm.pkg.github.com" >> ~/.npmrc
echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> ~/.npmrc

パッケージの公開:

# パッケージの公開
npm publish

# 特定のバージョンタグでの公開
npm publish --tag beta

# 公開範囲の指定
npm publish --access public

GitHub Actions を使った自動公開:

# .github/workflows/publish.yml
name: Publish Package

on:
  release:
    types: [created]

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        registry-url: 'https://npm.pkg.github.com'
        scope: '@yourusername'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test
    
    - name: Build package
      run: npm run build
    
    - name: Publish to GitHub Packages
      run: npm publish
      env:
        NODE_AUTH_TOKEN: $

Docker イメージの管理

Dockerfile の作成:

# Dockerfile
FROM node:18-alpine

# 作業ディレクトリの設定
WORKDIR /app

# パッケージファイルのコピー
COPY package*.json ./

# 依存関係のインストール
RUN npm ci --only=production

# アプリケーションコードのコピー
COPY . .

# ポート3000を公開
EXPOSE 3000

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# アプリケーションの実行
CMD ["npm", "start"]

マルチステージビルド:

# マルチステージビルドの例
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 本番用ステージ
FROM node:18-alpine AS production

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# ビルド成果物のコピー
COPY --from=builder /app/dist ./dist

# 非rootユーザーの作成
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

EXPOSE 3000
CMD ["npm", "start"]

GitHub Container Registry への公開:

# .github/workflows/docker.yml
name: Build and Push Docker Image

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: $

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
    
    - name: Log in to Container Registry
      uses: docker/login-action@v3
      with:
        registry: $
        username: $
        password: $
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: $/$
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern=
          type=semver,pattern=.
    
    - name: Build and push Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: $
        labels: $

11.2 GitHub Codespaces

プロフィール最適化

クラウド開発環境の概念

従来の開発環境の課題:

  • 新しいプロジェクトでの環境構築の複雑さ
  • チーム間での環境差異
  • 開発マシンのスペック制限
  • 設定の同期とバックアップの困難

Codespaces の利点:

  • ブラウザからのフルIDEアクセス
  • 標準化された開発環境
  • 高性能クラウドコンピューティング
  • 即座のプロジェクト開始
  • チーム間での環境統一

リポジトリショーケース戦略

Codespaces の設定と利用

devcontainer.json の設定:

// .devcontainer/devcontainer.json
{
  "name": "Node.js & TypeScript Development",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:18",
  
  // Features (追加ツールの自動インストール)
  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/aws-cli:1": {}
  },
  
  // VS Code 拡張機能の自動インストール
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-vscode.vscode-typescript-next",
        "bradlc.vscode-tailwindcss",
        "esbenp.prettier-vscode",
        "ms-vscode.vscode-json",
        "ms-vscode.hexeditor",
        "GitHub.vscode-pull-request-github"
      ],
      "settings": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode",
        "terminal.integrated.defaultProfile.linux": "bash"
      }
    }
  },
  
  // ポートフォワーディング
  "forwardPorts": [3000, 8080, 5432],
  "portsAttributes": {
    "3000": {
      "label": "Application Server",
      "onAutoForward": "notify"
    },
    "5432": {
      "label": "PostgreSQL",
      "onAutoForward": "silent"
    }
  },
  
  // 作成後のセットアップスクリプト
  "postCreateCommand": "npm install && npm run setup",
  
  // 起動時のコマンド
  "postStartCommand": "npm run dev &",
  
  // ライフサイクル用コマンド
  "postAttachCommand": {
    "server": "npm run dev"
  },
  
  // マウントポイント
  "mounts": [
    "source=${localWorkspaceFolder}/.devcontainer/data,target=/workspace/data,type=bind"
  ],
  
  // 環境変数
  "containerEnv": {
    "NODE_ENV": "development",
    "DEBUG": "app:*"
  },
  
  // Docker Compose を使用する場合
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace"
}

カスタムDockerfileの使用:

# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/typescript-node:18

# 追加のツールをインストール
RUN apt-get update && apt-get install -y \
    postgresql-client \
    redis-tools \
    jq \
    && rm -rf /var/lib/apt/lists/*

# 開発用のグローバルパッケージ
RUN npm install -g \
    @nestjs/cli \
    typescript \
    ts-node \
    nodemon \
    eslint \
    prettier

# Python開発環境(必要に応じて)
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip3 install requests flask pandas

# ユーザー設定
USER vscode

# シェル設定のカスタマイズ
RUN echo 'alias ll="ls -la"' >> ~/.bashrc
RUN echo 'alias gs="git status"' >> ~/.bashrc
RUN echo 'alias gp="git push"' >> ~/.bashrc

Docker Compose統合:

# .devcontainer/docker-compose.yml
version: '3.8'

services:
  app:
    build: 
      context: .
      dockerfile: Dockerfile
    volumes:
      - ../..:/workspaces:cached
    command: sleep infinity
    network_mode: service:db
    depends_on:
      - db
      - redis
  
  db:
    image: postgres:15
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: devdb
    ports:
      - "5432:5432"
  
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    ports:
      - "6379:6379"

volumes:
  postgres-data:

チーム開発での活用

プリビルトCodspaces:

# .github/workflows/codespaces-prebuilds.yml
name: Create Codespaces Prebuild

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  prebuild:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Build application
      run: npm run build
    
    - name: Create prebuild
      uses: github/create-codespace-prebuild@v1
      with:
        devcontainer_path: .devcontainer/devcontainer.json

チーム設定の標準化:

// .devcontainer/devcontainer.json
{
  "name": "Team Development Environment",
  
  // 共通の開発ツールチェーン
  "features": {
    "ghcr.io/devcontainers/features/node:1": {
      "version": "18"
    },
    "ghcr.io/devcontainers/features/docker-in-docker:2": {},
    "ghcr.io/devcontainers/features/terraform:1": {}
  },
  
  // チーム標準の拡張機能
  "customizations": {
    "vscode": {
      "extensions": [
        // コード品質
        "esbenp.prettier-vscode",
        "ms-vscode.vscode-eslint",
        "bradlc.vscode-tailwindcss",
        
        // チーム協働
        "ms-vsliveshare.vsliveshare",
        "GitHub.vscode-pull-request-github",
        
        // 開発効率
        "ms-vscode.vscode-json",
        "redhat.vscode-yaml",
        "ms-vscode.hexeditor"
      ],
      
      // 統一されたエディタ設定
      "settings": {
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
          "source.fixAll.eslint": true
        },
        "files.associations": {
          "*.env*": "dotenv"
        }
      }
    }
  },
  
  // プロジェクト固有のセットアップ
  "postCreateCommand": "bash .devcontainer/setup.sh"
}

11.3 GitHub CLI

GitHub CLI の基本機能

インストールと認証:

# macOS (Homebrew)
brew install gh

# Windows (Winget)
winget install --id GitHub.cli

# Ubuntu/Debian
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install gh

# 認証
gh auth login

# 認証状態の確認
gh auth status

リポジトリ操作の自動化

リポジトリ管理:

# リポジトリの作成
gh repo create my-new-project --public --description "My awesome project"

# プライベートリポジトリの作成(README付き)
gh repo create my-private-project --private --add-readme

# テンプレートからリポジトリ作成
gh repo create my-next-app --template vercel/next.js --public

# フォーク
gh repo fork octocat/Hello-World

# クローン(フォークも同時に作成)
gh repo clone octocat/Hello-World --fork

# リポジトリ情報の表示
gh repo view owner/repo

# リポジトリの削除
gh repo delete owner/repo --confirm

Issue管理:

# Issue一覧の表示
gh issue list

# フィルタリング
gh issue list --state open --assignee @me --label bug

# Issue作成
gh issue create --title "Bug: Login form not working" --body "Description of the bug..."

# テンプレートを使ったIssue作成
gh issue create --template bug_report.md

# Issue詳細表示
gh issue view 123

# Issue編集
gh issue edit 123 --add-label "priority:high" --add-assignee @octocat

# Issueクローズ
gh issue close 123

# Issue検索
gh issue list --search "is:open label:bug author:@me"

プルリクエスト操作:

# プルリクエスト作成
gh pr create --title "Add user authentication" --body "Implements login/logout functionality"

# 下書きPRの作成
gh pr create --draft --title "WIP: Add user authentication"

# PRの一覧表示
gh pr list

# 特定PRの詳細表示
gh pr view 456

# PRをローカルにチェックアウト
gh pr checkout 456

# PRのマージ
gh pr merge 456 --merge  # または --squash, --rebase

# PRのレビュー
gh pr review 456 --approve --body "LGTM!"
gh pr review 456 --request-changes --body "Please fix the tests"

# PRの状態確認
gh pr status

ワークフローの自動化

GitHub Actions操作:

# ワークフロー一覧
gh workflow list

# ワークフロー実行
gh workflow run ci.yml

# 変数付きでの実行
gh workflow run deploy.yml --field environment=production

# 実行履歴の確認
gh run list --workflow=ci.yml

# 実行詳細の表示
gh run view 123456789

# ログの表示
gh run view 123456789 --log

# 失敗したジョブの再実行
gh run rerun 123456789 --failed

# アーティファクトのダウンロード
gh run download 123456789

バルク操作のスクリプト例:

#!/bin/bash
# bulk-operations.sh - 複数リポジトリでの一括操作

# 組織内の全リポジトリでIssueテンプレートを更新
for repo in $(gh repo list myorg --limit 100 --json name --jq '.[].name'); do
  echo "Updating issue templates for $repo"
  gh repo clone "myorg/$repo" temp-repo
  cd temp-repo
  
  # テンプレートファイルのコピー
  cp ../templates/.github/ISSUE_TEMPLATE/* .github/ISSUE_TEMPLATE/
  
  # コミットとプッシュ
  git add .github/ISSUE_TEMPLATE/
  git commit -m "Update issue templates"
  git push
  
  cd ..
  rm -rf temp-repo
done

# 複数リポジトリでセキュリティアップデート
repos=("repo1" "repo2" "repo3")
for repo in "${repos[@]}"; do
  echo "Checking security updates for $repo"
  gh repo clone "myorg/$repo" temp-repo
  cd temp-repo
  
  # npm auditによる脆弱性チェック
  if npm audit --audit-level=moderate; then
    echo "No security issues found in $repo"
  else
    echo "Security issues found in $repo, creating issue..."
    gh issue create --title "Security vulnerabilities found" \
      --body "npm audit found security vulnerabilities. Please run \`npm audit fix\`" \
      --label "security,priority:high"
  fi
  
  cd ..
  rm -rf temp-repo
done

カスタマイズと拡張

エイリアスの設定:

# よく使うコマンドのエイリアス
gh alias set prc 'pr create --draft'
gh alias set prm 'pr merge --squash --delete-branch'
gh alias set issues 'issue list --assignee @me'

# 複雑なコマンドのエイリアス
gh alias set my-prs 'pr list --author @me --state open'
gh alias set review-needed 'pr list --search "is:open review:required"'

# エイリアス一覧の確認
gh alias list

設定ファイルのカスタマイズ:

# ~/.config/gh/config.yml
version: 1
git_protocol: ssh
editor: code --wait
prompt: enabled
pager: less
aliases:
  co: pr checkout
  prc: pr create --draft
  prm: pr merge --squash --delete-branch
  issues: issue list --assignee @me

GitHub CLI拡張機能:

# 拡張機能の検索とインストール
gh extension list
gh extension install dlvhdr/gh-dash
gh extension install mislav/gh-branch

# 拡張機能の使用
gh dash  # インタラクティブなダッシュボード
gh branch  # ブランチ管理の拡張

# 自作拡張機能の作成
gh extension create my-extension

11.4 Webhooks と自動化

Webhooks の基本概念

Webhooks とは: GitHubで特定のイベントが発生した際に、外部のサーバーに自動的にHTTPリクエストを送信する仕組み

主要なイベントタイプ:

  • push: コードのプッシュ
  • pull_request: プルリクエストの作成・更新
  • issues: Issue の作成・更新・クローズ
  • release: リリースの作成・公開
  • fork: リポジトリのフォーク
  • star: スターの追加・削除

Webhook サーバーの実装

Node.js/Express での実装例:

// webhook-server.js
const express = require('express');
const crypto = require('crypto');
const app = express();

// ミドルウェア設定
app.use(express.json());

// Webhook署名の検証
function verifySignature(req, res, next) {
  const signature = req.headers['x-hub-signature-256'];
  const payload = JSON.stringify(req.body);
  const secret = process.env.WEBHOOK_SECRET;
  
  if (!signature || !secret) {
    return res.status(401).send('Unauthorized');
  }
  
  const expectedSignature = 'sha256=' + 
    crypto.createHmac('sha256', secret)
          .update(payload)
          .digest('hex');
  
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
    return res.status(401).send('Unauthorized');
  }
  
  next();
}

// Push イベントの処理
app.post('/webhook/push', verifySignature, async (req, res) => {
  const { repository, commits, pusher } = req.body;
  
  console.log(`Push to ${repository.full_name} by ${pusher.name}`);
  console.log(`${commits.length} commits pushed`);
  
  // 自動デプロイメントのトリガー
  if (repository.default_branch === req.body.ref.replace('refs/heads/', '')) {
    try {
      await triggerDeployment(repository.full_name);
      console.log('Deployment triggered successfully');
    } catch (error) {
      console.error('Deployment failed:', error);
    }
  }
  
  res.status(200).send('OK');
});

// Pull Request イベントの処理
app.post('/webhook/pr', verifySignature, async (req, res) => {
  const { action, pull_request, repository } = req.body;
  
  console.log(`PR ${action}: ${pull_request.title}`);
  
  switch (action) {
    case 'opened':
      await handlePROpened(pull_request, repository);
      break;
    case 'closed':
      if (pull_request.merged) {
        await handlePRMerged(pull_request, repository);
      }
      break;
    case 'synchronize':
      await handlePRUpdated(pull_request, repository);
      break;
  }
  
  res.status(200).send('OK');
});

// Issue イベントの処理
app.post('/webhook/issues', verifySignature, async (req, res) => {
  const { action, issue, repository } = req.body;
  
  if (action === 'opened') {
    // 新しいIssueに自動ラベル付け
    await autoLabelIssue(issue, repository);
    
    // 担当者の自動割当
    await autoAssignIssue(issue, repository);
    
    // Slack通知
    await sendSlackNotification({
      text: `New issue created: ${issue.title}`,
      url: issue.html_url,
      repository: repository.full_name
    });
  }
  
  res.status(200).send('OK');
});

// 自動デプロイメント機能
async function triggerDeployment(repoName) {
  const deployScript = './deploy.sh';
  const { exec } = require('child_process');
  
  return new Promise((resolve, reject) => {
    exec(`${deployScript} ${repoName}`, (error, stdout, stderr) => {
      if (error) {
        reject(error);
      } else {
        resolve(stdout);
      }
    });
  });
}

// Issue の自動ラベル付け
async function autoLabelIssue(issue, repository) {
  const { Octokit } = require('@octokit/rest');
  const octokit = new Octokit({
    auth: process.env.GITHUB_TOKEN
  });
  
  const labels = [];
  const title = issue.title.toLowerCase();
  const body = issue.body.toLowerCase();
  
  // タイトルと本文から自動でラベルを判定
  if (title.includes('bug') || body.includes('error')) {
    labels.push('bug');
  }
  if (title.includes('feature') || body.includes('enhancement')) {
    labels.push('enhancement');
  }
  if (title.includes('doc') || body.includes('documentation')) {
    labels.push('documentation');
  }
  
  if (labels.length > 0) {
    await octokit.rest.issues.addLabels({
      owner: repository.owner.login,
      repo: repository.name,
      issue_number: issue.number,
      labels: labels
    });
  }
}

// Slack通知
async function sendSlackNotification(data) {
  const webhookUrl = process.env.SLACK_WEBHOOK_URL;
  if (!webhookUrl) return;
  
  const payload = {
    text: data.text,
    attachments: [{
      color: 'good',
      fields: [
        {
          title: 'Repository',
          value: data.repository,
          short: true
        },
        {
          title: 'Link',
          value: `<${data.url}|View on GitHub>`,
          short: true
        }
      ]
    }]
  };
  
  try {
    await fetch(webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    });
  } catch (error) {
    console.error('Failed to send Slack notification:', error);
  }
}

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Webhook server running on port ${PORT}`);
});

高度な自動化例

CI/CD パイプライン統合:

// advanced-webhook-handlers.js

// マルチ環境デプロイメント
async function handleMultiStageDeployment(pullRequest, repository) {
  const environments = ['development', 'staging', 'production'];
  
  for (const env of environments) {
    if (env === 'production' && !pullRequest.merged) {
      continue; // 本番環境はマージ後のみ
    }
    
    try {
      const deploymentId = await createDeployment(repository, pullRequest, env);
      await executeDeployment(deploymentId, env);
      await updateDeploymentStatus(deploymentId, 'success');
    } catch (error) {
      await updateDeploymentStatus(deploymentId, 'failure');
      throw error;
    }
  }
}

// セキュリティスキャンの自動実行
async function handleSecurityScan(repository, commits) {
  const changedFiles = commits.flatMap(commit => 
    [...commit.added, ...commit.modified]
  );
  
  // 依存関係ファイルが変更された場合
  const dependencyFiles = ['package.json', 'requirements.txt', 'go.mod'];
  const hasDependencyChanges = changedFiles.some(file => 
    dependencyFiles.some(depFile => file.includes(depFile))
  );
  
  if (hasDependencyChanges) {
    await triggerSecurityScan(repository);
  }
}

// パフォーマンス テストの自動実行
async function handlePerformanceTest(pullRequest, repository) {
  const performanceLabels = ['performance', 'optimization'];
  const hasPerformanceLabel = pullRequest.labels.some(label => 
    performanceLabels.includes(label.name)
  );
  
  if (hasPerformanceLabel) {
    const testResults = await runPerformanceTests(repository, pullRequest.head.sha);
    await commentPerformanceResults(pullRequest, testResults);
  }
}

// 自動コードレビュー
async function handleAutomatedCodeReview(pullRequest, repository) {
  const { Octokit } = require('@octokit/rest');
  const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
  
  // ファイル差分の取得
  const { data: files } = await octokit.rest.pulls.listFiles({
    owner: repository.owner.login,
    repo: repository.name,
    pull_number: pullRequest.number
  });
  
  const reviewComments = [];
  
  for (const file of files) {
    // 大きなファイルの警告
    if (file.changes > 500) {
      reviewComments.push({
        path: file.filename,
        line: 1,
        body: '⚠️ This file has over 500 changes. Consider breaking it into smaller PRs.'
      });
    }
    
    // セキュリティパターンのチェック
    if (file.patch && file.patch.includes('password')) {
      reviewComments.push({
        path: file.filename,
        line: findLineNumber(file.patch, 'password'),
        body: '🔒 Potential security issue: hardcoded password detected.'
      });
    }
  }
  
  if (reviewComments.length > 0) {
    await octokit.rest.pulls.createReview({
      owner: repository.owner.login,
      repo: repository.name,
      pull_number: pullRequest.number,
      event: 'REQUEST_CHANGES',
      body: 'Automated code review found some issues that need attention.',
      comments: reviewComments
    });
  }
}

外部サービス統合:

// external-integrations.js

// Jira統合
async function syncWithJira(issue, action) {
  if (!process.env.JIRA_API_TOKEN) return;
  
  const jiraTicketMatch = issue.body.match(/JIRA-(\d+)/);
  if (!jiraTicketMatch) return;
  
  const jiraTicketId = jiraTicketMatch[1];
  const jiraApi = new JiraApi({
    protocol: 'https',
    host: process.env.JIRA_HOST,
    username: process.env.JIRA_USERNAME,
    password: process.env.JIRA_API_TOKEN,
    apiVersion: '2',
    strictSSL: true
  });
  
  try {
    await jiraApi.addComment(jiraTicketId, `GitHub Issue ${action}: ${issue.html_url}`);
    
    if (action === 'closed') {
      await jiraApi.transitionIssue(jiraTicketId, {
        transition: { id: '31' } // 'Done' 状態へ
      });
    }
  } catch (error) {
    console.error('Jira sync failed:', error);
  }
}

// データベース同期
async function syncToDatabase(event, data) {
  const db = require('./db');
  
  const record = {
    event_type: event,
    repository: data.repository.full_name,
    actor: data.sender.login,
    created_at: new Date(),
    payload: JSON.stringify(data)
  };
  
  await db.events.create(record);
  
  // 統計情報の更新
  await updateRepositoryStats(data.repository.full_name);
}

// メール通知システム
async function sendEmailNotification(event, data) {
  const sgMail = require('@sendgrid/mail');
  sgMail.setApiKey(process.env.SENDGRID_API_KEY);
  
  const msg = {
    to: getNotificationRecipients(data.repository.full_name),
    from: 'noreply@example.com',
    subject: `GitHub ${event}: ${data.repository.name}`,
    html: generateEmailTemplate(event, data)
  };
  
  try {
    await sgMail.send(msg);
  } catch (error) {
    console.error('Email notification failed:', error);
  }
}

まとめ

この章では、GitHubの高度な機能を活用した効率的な開発環境について学びました:

GitHub Packages

  • パッケージ管理の統合エコシステム
  • npm・Docker・Maven等のマルチ言語サポート
  • 自動公開とバージョン管理
  • セキュリティスキャンとアクセス制御

GitHub Codespaces

  • クラウドベースの統一開発環境
  • devcontainer.jsonによる環境設定
  • チーム開発での環境標準化
  • プリビルドによる高速起動

GitHub CLI

  • コマンドラインからの効率的なGitHub操作
  • リポジトリ・Issue・PR管理の自動化
  • バルク操作とスクリプティング
  • カスタムエイリアスと拡張機能

Webhooks と自動化

  • イベント駆動型の自動化システム
  • 外部サービスとの統合
  • CI/CDパイプラインの高度化
  • セキュリティとパフォーマンスの自動チェック

開発プロセスの変革効果

  • 手作業の大幅削減
  • 品質向上の自動化
  • チーム生産性の向上
  • 継続的な改善サイクル

次の章では、トラブルシューティングについて学び、GitHubの使用中に発生する可能性のある問題の解決方法を身につけます。

キャリア開発活用

理解度確認: □ GitHub Packagesでパッケージを公開・管理できる
□ GitHub Codespacesで統一された開発環境を構築できる
□ GitHub CLIで効率的なコマンドライン操作を実行できる
□ Webhooksを使って外部システムとの連携を実装できる
□ 自動化によって開発プロセスを最適化できる