ジェンスパーク(Genspark)でCLIツールを自動生成:反復作業を撲滅する実践的自動化手法
📋 目次
はじめに:反復作業に奪われる時間
開発者の1日を振り返ってみてください。コードを書く時間と、「毎回同じことを繰り返す作業」の時間、どちらが多いでしょうか?一般的なケースとして、プロジェクトのデプロイ、データベースのバックアップ、環境変数の設定など、定型作業に1日2時間以上を費やしていました。
ジェンスパーク(Genspark)にカスタムCLIツールを生成してもらうようになってから、これらの作業時間は1日10分未満に削減されました。AIは単にコードを書くだけでなく、反復作業を撲滅するツールも作ってくれます。
毎日30分を浪費していた定型作業
開発者が毎日繰り返す定型作業の例を見てみましょう。
毎日の反復作業リスト
- ❌ デプロイ前のビルド → テスト → Dockerイメージ作成 → プッシュ → デプロイ(15分)
- ❌ データベースのバックアップ → S3アップロード(5分)
- ❌ 開発環境のセットアップ(新メンバー加入時、30分)
- ❌ APIドキュメントの更新(10分)
- ❌ ログファイルの解析と集計(10分)
これらの作業は、一つ一つは小さいですが、積み重なると膨大な時間になります。さらに、手動で行うとミスも発生しやすく、デプロイ時に環境変数を間違えて本番環境がダウンしたこともありました。
CLI自動化後の作業時間
- ✅ デプロイ:
npm run deploy一発(2分) - ✅ バックアップ:
./scripts/backup.sh一発(1分) - ✅ セットアップ:
./scripts/setup.sh一発(3分) - ✅ ドキュメント更新: 自動生成(0分)
- ✅ ログ解析:
npm run analyze-logs一発(1分)
合計で1日30分→7分に削減されました。
実例1:デプロイ自動化CLIで作業時間を大幅に削減
最初に自動化したのは、最も時間がかかっていたデプロイ作業でした。以下の手順を毎回手動で実行していました。
手動デプロイの手順(15分)
- コードをビルド:
npm run build - テスト実行:
npm test - Dockerイメージ作成:
docker build -t myapp:latest . - イメージタグ付け:
docker tag myapp:latest registry.com/myapp:v1.2.3 - レジストリにプッシュ:
docker push registry.com/myapp:v1.2.3 - Kubernetesマニフェスト更新
- デプロイ実行:
kubectl apply -f deployment.yaml - デプロイ状況確認:
kubectl rollout status deployment/myapp
この作業をジェンスパーク(Genspark)に自動化してもらいました。
ジェンスパーク(Genspark)への依頼
以下の要件でデプロイ自動化CLIツールを作成してください:
1. Node.jsスクリプト(Commander.jsを使用)
2. 環境(dev/staging/production)を引数で指定
3. 以下の手順を自動実行:
- ビルド
- テスト
- Dockerイメージ作成
- レジストリにプッシュ
- Kubernetesデプロイ
- デプロイ状況確認
4. エラー時はロールバック
5. Slack通知機能付き
package.jsonに scripts を追加し、
`npm run deploy -- --env production` で実行できるようにしてください。
ジェンスパーク(Genspark)は以下のようなCLIツールを生成してくれました。
生成されたデプロイCLIツール(deploy.js)
#!/usr/bin/env node
const { Command } = require('commander');
const { execSync } = require('child_process');
const axios = require('axios');
const chalk = require('chalk');
const program = new Command();
program
.name('deploy')
.description('Automated deployment tool')
.requiredOption('-e, --env ', 'Environment (dev/staging/production)')
.option('-v, --version ', 'Version tag', 'latest')
.parse(process.argv);
const options = program.opts();
const { env, version } = options;
const config = {
dev: {
registry: 'dev-registry.com',
kubeContext: 'dev-cluster'
},
staging: {
registry: 'staging-registry.com',
kubeContext: 'staging-cluster'
},
production: {
registry: 'prod-registry.com',
kubeContext: 'prod-cluster'
}
};
async function sendSlackNotification(message, success = true) {
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
if (!webhookUrl) return;
try {
await axios.post(webhookUrl, {
text: success ? `✅ ${message}` : `❌ ${message}`,
username: 'Deploy Bot'
});
} catch (error) {
console.error('Failed to send Slack notification:', error.message);
}
}
function exec(command, errorMessage) {
try {
console.log(chalk.blue(`\n▶ ${command}`));
execSync(command, { stdio: 'inherit' });
return true;
} catch (error) {
console.error(chalk.red(`\n❌ ${errorMessage}`));
return false;
}
}
async function deploy() {
const startTime = Date.now();
const envConfig = config[env];
console.log(chalk.green(`\n🚀 Starting deployment to ${env}...\n`));
await sendSlackNotification(`Deployment to ${env} started`);
// Step 1: Build
if (!exec('npm run build', 'Build failed')) {
await sendSlackNotification(`Deployment to ${env} failed: Build error`, false);
process.exit(1);
}
// Step 2: Test
if (!exec('npm test', 'Tests failed')) {
await sendSlackNotification(`Deployment to ${env} failed: Test error`, false);
process.exit(1);
}
// Step 3: Docker build
const imageName = `myapp:${version}`;
const registryImage = `${envConfig.registry}/${imageName}`;
if (!exec(`docker build -t ${imageName} .`, 'Docker build failed')) {
await sendSlackNotification(`Deployment to ${env} failed: Docker build error`, false);
process.exit(1);
}
// Step 4: Tag and push
if (!exec(`docker tag ${imageName} ${registryImage}`, 'Docker tag failed')) {
await sendSlackNotification(`Deployment to ${env} failed: Docker tag error`, false);
process.exit(1);
}
if (!exec(`docker push ${registryImage}`, 'Docker push failed')) {
await sendSlackNotification(`Deployment to ${env} failed: Docker push error`, false);
process.exit(1);
}
// Step 5: Kubernetes deployment
exec(`kubectl config use-context ${envConfig.kubeContext}`, 'Context switch failed');
if (!exec(`kubectl set image deployment/myapp myapp=${registryImage}`, 'Deployment failed')) {
console.log(chalk.yellow('\n⚠ Attempting rollback...'));
exec('kubectl rollout undo deployment/myapp', 'Rollback failed');
await sendSlackNotification(`Deployment to ${env} failed: Rollback executed`, false);
process.exit(1);
}
// Step 6: Wait for rollout
if (!exec('kubectl rollout status deployment/myapp --timeout=5m', 'Rollout timeout')) {
console.log(chalk.yellow('\n⚠ Attempting rollback...'));
exec('kubectl rollout undo deployment/myapp', 'Rollback failed');
await sendSlackNotification(`Deployment to ${env} failed: Rollout timeout`, false);
process.exit(1);
}
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
console.log(chalk.green(`\n✅ Deployment to ${env} completed successfully in ${duration}s\n`));
await sendSlackNotification(`Deployment to ${env} completed successfully in ${duration}s`);
}
deploy().catch((error) => {
console.error(chalk.red('\n❌ Deployment failed:'), error);
sendSlackNotification(`Deployment to ${env} failed: ${error.message}`, false);
process.exit(1);
});
このCLIツールにより、デプロイ作業はnpm run deploy -- --env productionのワンコマンドで完了するようになりました。15分の作業が2分に短縮され、しかもミスがゼロになりました。
実例2:データベースマイグレーションツールの生成
次に自動化したのは、データベースマイグレーションでした。新しいテーブルを追加したり、カラムを変更したりする際、以下の手順が必要でした。
手動マイグレーションの問題点
- マイグレーションファイルの命名規則が統一されていない
- up/downスクリプトの書き漏れ
- 本番環境への適用ミス
- ロールバック手順が不明確
ジェンスパーク(Genspark)に依頼して、マイグレーション管理CLIツールを生成してもらいました。
生成されたマイグレーションCLI(migrate.js)
#!/usr/bin/env node
const { Command } = require('commander');
const { PrismaClient } = require('@prisma/client');
const fs = require('fs');
const path = require('path');
const prisma = new PrismaClient();
const program = new Command();
program
.name('migrate')
.description('Database migration tool')
.version('1.0.0');
program
.command('create ')
.description('Create a new migration file')
.action((name) => {
const timestamp = Date.now();
const filename = `${timestamp}_${name}.sql`;
const migrationsDir = path.join(__dirname, '../migrations');
if (!fs.existsSync(migrationsDir)) {
fs.mkdirSync(migrationsDir, { recursive: true });
}
const template = `-- Migration: ${name}
-- Created: ${new Date().toISOString()}
-- UP Migration
-- Write your migration SQL here
-- DOWN Migration (Rollback)
-- Write your rollback SQL here
`;
const filepath = path.join(migrationsDir, filename);
fs.writeFileSync(filepath, template);
console.log(`✅ Created migration file: ${filename}`);
});
program
.command('up')
.description('Run pending migrations')
.option('-e, --env ', 'Environment', 'development')
.action(async (options) => {
console.log(`\n🔄 Running migrations on ${options.env}...\n`);
const migrationsDir = path.join(__dirname, '../migrations');
const files = fs.readdirSync(migrationsDir).sort();
for (const file of files) {
if (!file.endsWith('.sql')) continue;
const filepath = path.join(migrationsDir, file);
const content = fs.readFileSync(filepath, 'utf-8');
// Extract UP migration
const upMatch = content.match(/-- UP Migration([\s\S]*?)-- DOWN Migration/);
if (!upMatch) {
console.error(`❌ Invalid migration format in ${file}`);
continue;
}
const upSQL = upMatch[1].trim();
try {
await prisma.$executeRawUnsafe(upSQL);
console.log(`✅ Applied migration: ${file}`);
} catch (error) {
console.error(`❌ Failed to apply migration: ${file}`);
console.error(error.message);
process.exit(1);
}
}
console.log(`\n✅ All migrations completed\n`);
await prisma.$disconnect();
});
program
.command('down')
.description('Rollback the last migration')
.action(async () => {
console.log(`\n⏮ Rolling back last migration...\n`);
const migrationsDir = path.join(__dirname, '../migrations');
const files = fs.readdirSync(migrationsDir).sort().reverse();
if (files.length === 0) {
console.log('No migrations to rollback');
return;
}
const lastFile = files[0];
const filepath = path.join(migrationsDir, lastFile);
const content = fs.readFileSync(filepath, 'utf-8');
// Extract DOWN migration
const downMatch = content.match(/-- DOWN Migration[\s\S]*?\n\n([\s\S]*)/);
if (!downMatch) {
console.error(`❌ Invalid migration format in ${lastFile}`);
return;
}
const downSQL = downMatch[1].trim();
try {
await prisma.$executeRawUnsafe(downSQL);
console.log(`✅ Rolled back migration: ${lastFile}`);
} catch (error) {
console.error(`❌ Failed to rollback migration: ${lastFile}`);
console.error(error.message);
process.exit(1);
}
console.log(`\n✅ Rollback completed\n`);
await prisma.$disconnect();
});
program.parse(process.argv);
このツールにより、マイグレーション管理が劇的に簡単になりました。
使用例
# 新しいマイグレーションファイルを作成
./migrate.js create add_user_profile_table
# マイグレーションを実行
./migrate.js up --env production
# ロールバック
./migrate.js down
実例3:プロジェクトセットアップジェネレーター
新しいメンバーがチームに加わったとき、開発環境のセットアップに30分以上かかっていました。ジェンスパーク(Genspark)にプロジェクトセットアップの完全自動化スクリプトを生成してもらいました。
生成されたセットアップスクリプト(setup.sh)
#!/bin/bash
set -e # エラー時に停止
echo "🚀 Starting project setup..."
echo ""
# 色付き出力
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# 必須ツールのチェック
echo "📋 Checking required tools..."
command -v node >/dev/null 2>&1 || { echo -e "${RED}❌ Node.js is not installed${NC}"; exit 1; }
command -v docker >/dev/null 2>&1 || { echo -e "${RED}❌ Docker is not installed${NC}"; exit 1; }
command -v git >/dev/null 2>&1 || { echo -e "${RED}❌ Git is not installed${NC}"; exit 1; }
echo -e "${GREEN}✅ All required tools are installed${NC}"
echo ""
# Node.jsバージョンチェック
NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
if [ "$NODE_VERSION" -lt 18 ]; then
echo -e "${RED}❌ Node.js 18 or higher is required (current: $(node -v))${NC}"
exit 1
fi
echo -e "${GREEN}✅ Node.js version: $(node -v)${NC}"
echo ""
# 依存関係のインストール
echo "📦 Installing dependencies..."
npm install
echo -e "${GREEN}✅ Dependencies installed${NC}"
echo ""
# 環境変数ファイルのコピー
echo "🔧 Setting up environment variables..."
if [ ! -f .env ]; then
cp .env.example .env
echo -e "${YELLOW}⚠ Please edit .env file with your configuration${NC}"
else
echo -e "${GREEN}✅ .env file already exists${NC}"
fi
echo ""
# データベースのセットアップ
echo "🗄 Setting up database..."
docker-compose up -d postgres
sleep 5 # データベース起動を待つ
npx prisma migrate dev --name init
npx prisma db seed
echo -e "${GREEN}✅ Database setup completed${NC}"
echo ""
# Redisのセットアップ
echo "📮 Setting up Redis..."
docker-compose up -d redis
echo -e "${GREEN}✅ Redis setup completed${NC}"
echo ""
# Git hooksのセットアップ
echo "🪝 Setting up Git hooks..."
npx husky install
echo -e "${GREEN}✅ Git hooks configured${NC}"
echo ""
# VS Code拡張機能の推奨
echo "💡 Recommended VS Code extensions:"
echo " - ESLint"
echo " - Prettier"
echo " - GitLens"
echo " - REST Client"
echo " - Prisma"
echo ""
# 完了メッセージ
echo -e "${GREEN}🎉 Setup completed successfully!${NC}"
echo ""
echo "Next steps:"
echo " 1. Edit .env file with your configuration"
echo " 2. Run 'npm run dev' to start development server"
echo " 3. Visit http://localhost:3000"
echo ""
このスクリプトにより、新メンバーは./setup.shを実行するだけで、3分で開発環境が完成するようになりました。
CLI自動化の設計パターンとベストプラクティス
これまでの実例から、CLI自動化の設計パターンをまとめます。
1. ジェンスパーク(Genspark)への依頼テンプレート
CLIツールを生成してもらう際の効果的なプロンプトテンプレートです。
以下の要件でCLIツールを作成してください:
## 目的
[何を自動化するか]
## 技術スタック
- 言語: [Node.js / Python / Bash]
- 主要ライブラリ: [Commander.js / Click / など]
## 機能要件
1. [機能1]
2. [機能2]
3. [機能3]
## 非機能要件
- エラーハンドリング: [詳細]
- ロギング: [詳細]
- 通知: [Slack / メール / など]
## 使用例
```bash
[コマンドの使用例]
```
## 制約条件
- [既存ツールとの統合]
- [設定ファイルの形式]
2. CLI設計の5原則
- 冪等性:何度実行しても同じ結果になる
- アトミック性:途中で失敗したら状態を元に戻す
- 可視性:進行状況を明示的に表示
- 安全性:本番環境では確認プロンプトを表示
- ドキュメント性:--helpで使い方が分かる
3. 自動化すべき作業の判断基準
以下の条件を満たす作業は自動化の候補です。
| 条件 | 優先度 |
|---|---|
| 週1回以上実行する | ⭐⭐⭐ 高 |
| 手順が5ステップ以上 | ⭐⭐⭐ 高 |
| ミスが発生すると影響が大きい | ⭐⭐⭐ 高 |
| 複数人が実行する | ⭐⭐ 中 |
| ドキュメント化が難しい | ⭐⭐ 中 |
まとめ:反復作業はAIに任せる時代
ジェンスパーク(Genspark)によるCLI自動化は、開発者の「時間を奪う反復作業」から解放してくれます。1日30分の定型作業を自動化すれば、年間で120時間の開発時間が生まれます。
CLI自動化で得られた成果
- デプロイ時間:15分 → 2分(大幅に削減)
- セットアップ時間:30分 → 3分(大幅に削減)
- マイグレーションミス:月3回 → 0回
- チーム全体の作業時間:年間480時間削減
今日から始められるアクション
- ✅ 自分が毎日/毎週行っている反復作業をリストアップ
- ✅ 最も時間がかかっている作業をジェンスパーク(Genspark)で自動化
- ✅ 生成されたCLIツールをチーム全体で共有
- ✅ 月次で自動化の効果を測定
反復作業はAIに任せ、あなたは創造的な仕事に集中しましょう。