リリースノート、テストレポート、請求書、ドキュメント——これらをCI/CDパイプラインで自動生成できれば、手作業のミスをなくし、レビューのたびに最新のPDFが手元に揃います。
この記事では、FUNBREW PDFのAPIをGitHub Actionsから呼び出して、PDF生成を完全に自動化する方法を解説します。単純なHTML→PDF変換から、スケジュール実行による定期レポート生成まで、実践的なワークフロー例を豊富なコードとともに紹介します。
API自体の基本的な使い方はクイックスタートガイドを参照してください。
CI/CDでPDFを自動生成するユースケース
GitHub Actionsでのデプロイフローにプルできるユースケースは多岐にわたります。
| ユースケース | トリガー | 出力 |
|---|---|---|
| リリースノート | タグのプッシュ | GitHub Release添付PDF |
| PRチェンジログ | PR作成・更新 | アーティファクトPDF |
| 週次レポート | cron(毎週月曜) | Slackに送信 |
| 請求書生成 | PR承認後 | ストレージ保存 |
| APIドキュメント | mainへのマージ | デプロイ成果物 |
| テスト結果サマリ | テスト完了後 | ダウンロード可能PDF |
CI/CDに限らず、PDF生成全般のユースケースはユースケース一覧も参考にしてください。
準備:APIキーのSecrets管理
GitHub SecretsへのAPIキー登録
FUNBREW PDFのAPIキーは、絶対にコードやワークフローファイルに直接書かないでください。GitHub Secretsに登録して、ワークフロー内で環境変数として参照します。
# GitHub CLIでシークレットを登録(ローカルから実行)
gh secret set FUNBREW_API_KEY --body "sk-your-api-key-here"
# または、リポジトリのSettings > Secrets and variables > Actions から手動で登録
ワークフローでのSecrets参照
jobs:
generate-pdf:
runs-on: ubuntu-latest
steps:
- name: Generate PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
# $FUNBREW_API_KEY が安全に展開される
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-html \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Hello</h1>", "engine": "quality", "format": "A4"}' \
--output output.pdf
${{ secrets.FUNBREW_API_KEY }} はログに出力されることなく、ステップの環境変数として安全に渡されます。APIキーのセキュリティについてはセキュリティガイドで詳しく解説しています。
Organization Secretsと環境変数の使い分け
複数リポジトリで同じAPIキーを共有する場合、Organization Secretsが便利です。
# Organization Secretsを使う場合も、参照方法は同じ
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
環境(development / staging / production)ごとに異なるAPIキーを使いたい場合は、GitHub Environmentsを使います。
jobs:
generate-pdf:
runs-on: ubuntu-latest
environment: production # この環境のSecretsが参照される
steps:
- name: Generate PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
# 本番環境用のAPIキーが使われる
HTML→PDFワークフロー実装例
基本:curlでHTML→PDF変換
最もシンプルな構成です。HTMLを直接ワークフロー内で組み立て、APIに送信します。
# .github/workflows/generate-html-pdf.yml
name: HTML to PDF
on:
push:
branches: [main]
paths:
- 'templates/**'
- 'reports/**'
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate PDF from HTML file
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
# HTMLファイルをJSONにエスケープしてAPIに送信
HTML_CONTENT=$(cat templates/report.html | jq -Rs .)
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-html \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"html\": $HTML_CONTENT, \"engine\": \"quality\", \"format\": \"A4\"}" \
--output report.pdf
echo "PDF size: $(wc -c < report.pdf) bytes"
- name: Upload PDF artifact
uses: actions/upload-artifact@v4
with:
name: report-pdf
path: report.pdf
retention-days: 30
Node.jsスクリプトで動的HTML生成
データを取得してHTMLを動的に組み立て、PDFに変換するパターンです。より複雑なテンプレートに向いています。
# .github/workflows/dynamic-pdf.yml
name: Dynamic PDF Generation
on:
workflow_dispatch:
inputs:
report_type:
description: 'レポートの種類'
required: true
default: 'monthly'
type: choice
options:
- monthly
- quarterly
- annual
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Generate dynamic PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
REPORT_TYPE: ${{ inputs.report_type }}
run: node scripts/generate-report.js
// scripts/generate-report.js
const fs = require('fs');
async function generateReport() {
const reportType = process.env.REPORT_TYPE || 'monthly';
const apiKey = process.env.FUNBREW_API_KEY;
if (!apiKey) {
throw new Error('FUNBREW_API_KEY is not set');
}
// レポートデータを組み立て(実際はDBやAPIから取得)
const data = {
title: `${reportType.charAt(0).toUpperCase() + reportType.slice(1)} Report`,
generatedAt: new Date().toISOString(),
metrics: {
totalRequests: 12500,
successRate: 99.7,
avgResponseTime: 1.2,
},
};
const html = `
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<style>
body {
font-family: 'Noto Sans JP', 'Helvetica Neue', sans-serif;
padding: 40px;
color: #1a1a1a;
}
h1 { color: #2563eb; border-bottom: 2px solid #e5e7eb; padding-bottom: 12px; }
.metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 32px; }
.metric-card {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 20px;
text-align: center;
}
.metric-value { font-size: 2rem; font-weight: bold; color: #2563eb; }
.metric-label { font-size: 0.875rem; color: #64748b; margin-top: 4px; }
.footer { margin-top: 48px; font-size: 0.75rem; color: #94a3b8; }
</style>
</head>
<body>
<h1>${data.title}</h1>
<p>生成日時: ${data.generatedAt}</p>
<div class="metrics">
<div class="metric-card">
<div class="metric-value">${data.metrics.totalRequests.toLocaleString()}</div>
<div class="metric-label">総リクエスト数</div>
</div>
<div class="metric-card">
<div class="metric-value">${data.metrics.successRate}%</div>
<div class="metric-label">成功率</div>
</div>
<div class="metric-card">
<div class="metric-value">${data.metrics.avgResponseTime}s</div>
<div class="metric-label">平均レスポンス時間</div>
</div>
</div>
<div class="footer">Generated by GitHub Actions + FUNBREW PDF API</div>
</body>
</html>
`;
console.log('Calling FUNBREW PDF API...');
const response = await fetch('https://api.pdf.funbrew.cloud/v1/pdf/from-html', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html,
engine: 'quality',
format: 'A4',
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API error ${response.status}: ${errorText}`);
}
const pdfBuffer = Buffer.from(await response.arrayBuffer());
const outputPath = `report-${reportType}-${Date.now()}.pdf`;
fs.writeFileSync(outputPath, pdfBuffer);
console.log(`PDF generated: ${outputPath} (${pdfBuffer.length} bytes)`);
}
generateReport().catch((err) => {
console.error('Error:', err.message);
process.exit(1);
});
HTMLテンプレートの設計についてはテンプレートエンジンガイドを参照してください。
Markdown→PDFワークフロー実装例
PRのチェンジログをPDFに変換
PRに含まれるコミットメッセージやCHANGELOGをMarkdown→PDFに変換してアーティファクトとして保存する例です。
# .github/workflows/pr-changelog-pdf.yml
name: PR Changelog PDF
on:
pull_request:
types: [opened, synchronize]
jobs:
generate-changelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 全履歴を取得(git logに必要)
- name: Build changelog markdown
run: |
BRANCH="${{ github.head_ref }}"
BASE="${{ github.base_ref }}"
echo "# PR Changelog" > changelog.md
echo "" >> changelog.md
echo "**Branch:** \`${BRANCH}\` → \`${BASE}\`" >> changelog.md
echo "**PR:** #${{ github.event.pull_request.number }}" >> changelog.md
echo "**Author:** ${{ github.event.pull_request.user.login }}" >> changelog.md
echo "**Date:** $(date -u '+%Y-%m-%d %H:%M UTC')" >> changelog.md
echo "" >> changelog.md
echo "## Commits" >> changelog.md
echo "" >> changelog.md
# コミット一覧を追記
git log --oneline origin/${BASE}..HEAD --pretty=format:"- %h %s (%an)" >> changelog.md
echo "" >> changelog.md
echo "## Files Changed" >> changelog.md
echo "" >> changelog.md
# 変更ファイル一覧を追記
git diff --name-only origin/${BASE}..HEAD | while read file; do
echo "- \`$file\`" >> changelog.md
done
echo "Generated changelog.md:"
cat changelog.md
- name: Convert Markdown to PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
MARKDOWN_CONTENT=$(cat changelog.md | jq -Rs .)
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-markdown \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"markdown\": $MARKDOWN_CONTENT, \"theme\": \"github\", \"format\": \"A4\"}" \
--output changelog.pdf
echo "PDF generated: $(wc -c < changelog.pdf) bytes"
- name: Upload changelog PDF
uses: actions/upload-artifact@v4
with:
name: pr-changelog-pdf
path: changelog.pdf
retention-days: 7
ドキュメントをPDFに変換してリリースに添付
タグをプッシュしてリリースを作成するとき、MarkdownのドキュメントをPDFに変換してGitHub Releasesに自動添付します。
# .github/workflows/release-pdf.yml
name: Release with PDF Documentation
on:
push:
tags:
- 'v*'
permissions:
contents: write # GitHub Releasesへの書き込みに必要
jobs:
create-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate release notes PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
TAG="${{ github.ref_name }}"
# CHANGELOG.mdから該当バージョンのセクションを抽出
# (実際のフォーマットに合わせて調整)
awk "/^## \[${TAG}\]/,/^## \[/" CHANGELOG.md | head -n -1 > release-notes.md
if [ ! -s release-notes.md ]; then
echo "# Release ${TAG}" > release-notes.md
echo "" >> release-notes.md
echo "Released: $(date -u '+%Y-%m-%d')" >> release-notes.md
fi
MARKDOWN_CONTENT=$(cat release-notes.md | jq -Rs .)
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-markdown \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"markdown\": $MARKDOWN_CONTENT, \"theme\": \"github\", \"format\": \"A4\"}" \
--output "release-notes-${TAG}.pdf"
- name: Generate API reference PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
TAG="${{ github.ref_name }}"
MARKDOWN_CONTENT=$(cat docs/api-reference.md | jq -Rs .)
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-markdown \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"markdown\": $MARKDOWN_CONTENT, \"theme\": \"github\", \"format\": \"A4\"}" \
--output "api-reference-${TAG}.pdf"
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
TAG="${{ github.ref_name }}"
gh release create "${TAG}" \
--title "Release ${TAG}" \
--notes-file release-notes.md \
"release-notes-${TAG}.pdf#Release Notes (PDF)" \
"api-reference-${TAG}.pdf#API Reference (PDF)"
Markdown→PDF変換のオプション(テーマ、フォント、余白など)はMarkdown to PDF APIガイドを参照してください。
アーティファクトとしてのPDF保存
actions/upload-artifact の詳細設定
- name: Upload PDF artifacts
uses: actions/upload-artifact@v4
with:
name: generated-pdfs-${{ github.run_number }}
path: |
*.pdf
reports/*.pdf
retention-days: 90 # 保存期間(デフォルト90日、最大400日)
compression-level: 0 # PDFは既に圧縮済みのため0が効率的
if-no-files-found: error # PDFが生成されなかった場合はエラー
複数のPDFをまとめてアーカイブ
# .github/workflows/batch-pdf.yml
name: Batch PDF Generation
on:
workflow_dispatch:
jobs:
generate:
runs-on: ubuntu-latest
strategy:
matrix:
template: [invoice, report, certificate]
max-parallel: 3
steps:
- uses: actions/checkout@v4
- name: Generate ${{ matrix.template }} PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
TEMPLATE="${{ matrix.template }}"
HTML_CONTENT=$(cat "templates/${TEMPLATE}.html" | jq -Rs .)
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-html \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"html\": $HTML_CONTENT, \"engine\": \"quality\", \"format\": \"A4\"}" \
--output "${TEMPLATE}.pdf"
- name: Upload ${{ matrix.template }} PDF
uses: actions/upload-artifact@v4
with:
name: pdf-${{ matrix.template }}
path: ${{ matrix.template }}.pdf
retention-days: 30
# すべてのPDFをひとつのアーティファクトに統合
merge-artifacts:
needs: generate
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: pdf-*
merge-multiple: true
path: all-pdfs/
- uses: actions/upload-artifact@v4
with:
name: all-pdfs
path: all-pdfs/
バッチ処理でのPDF大量生成についてはバッチ処理ガイドも参考にしてください。
スケジュール実行(cron)の設定
定期レポートをSlackに送信
毎週月曜の朝、週次レポートを自動生成してSlackに送信する例です。Slackとの連携をさらに深めたい場合は、スラッシュコマンドでPDFをオンデマンド生成できるSlack Bot実装ガイドも参照してください。
# .github/workflows/weekly-report.yml
name: Weekly PDF Report
on:
schedule:
# 毎週月曜 09:00 JST(= 00:00 UTC)
- cron: '0 0 * * MON'
workflow_dispatch: # 手動実行も可能
jobs:
weekly-report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Generate weekly report
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
DATA_API_KEY: ${{ secrets.DATA_API_KEY }}
run: |
node scripts/weekly-report.js
- name: Send PDF to Slack
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
run: |
# Slackにファイルをアップロード
curl -X POST https://slack.com/api/files.getUploadURLExternal \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"filename\": \"weekly-report-$(date +%Y-%m-%d).pdf\",
\"length\": $(wc -c < weekly-report.pdf)
}" | tee upload-url.json
UPLOAD_URL=$(cat upload-url.json | jq -r '.upload_url')
FILE_ID=$(cat upload-url.json | jq -r '.file_id')
curl -X POST "$UPLOAD_URL" \
-H "Content-Type: application/octet-stream" \
--data-binary @weekly-report.pdf
curl -X POST https://slack.com/api/files.completeUploadExternal \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"files\": [{\"id\": \"$FILE_ID\"}],
\"channel_id\": \"C0123456789\",
\"initial_comment\": \"週次レポートが生成されました($(date +%Y-%m-%d))\"
}"
月次請求書の自動生成
月末に請求書を自動生成し、ストレージに保存する例です。
# .github/workflows/monthly-invoices.yml
name: Monthly Invoice Generation
on:
schedule:
# 毎月末日 18:00 JST(= 09:00 UTC)
- cron: '0 9 28-31 * *'
workflow_dispatch:
jobs:
check-last-day:
runs-on: ubuntu-latest
outputs:
is_last_day: ${{ steps.check.outputs.is_last_day }}
steps:
- id: check
run: |
# 月の最終日かどうか確認
TODAY=$(date +%d)
LAST_DAY=$(date -d "$(date +%Y-%m-01) +1 month -1 day" +%d 2>/dev/null || \
date -v+1m -v1d -v-1d +%d) # macOS互換
if [ "$TODAY" = "$LAST_DAY" ]; then
echo "is_last_day=true" >> $GITHUB_OUTPUT
else
echo "is_last_day=false" >> $GITHUB_OUTPUT
fi
generate-invoices:
needs: check-last-day
if: needs.check-last-day.outputs.is_last_day == 'true' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Generate monthly invoices
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
DB_CONNECTION_STRING: ${{ secrets.DB_CONNECTION_STRING }}
run: node scripts/generate-monthly-invoices.js
- name: Upload to storage
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 sync ./invoices/ s3://your-bucket/invoices/$(date +%Y/%m)/ \
--content-type application/pdf
// scripts/generate-monthly-invoices.js
const fs = require('fs');
const path = require('path');
async function generateInvoice(customer) {
const html = `
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<style>
body { font-family: 'Noto Sans JP', sans-serif; padding: 40px; }
.header { display: flex; justify-content: space-between; align-items: start; }
.company-name { font-size: 1.5rem; font-weight: bold; color: #2563eb; }
h1 { font-size: 2rem; color: #1a1a1a; }
table { width: 100%; border-collapse: collapse; margin-top: 24px; }
th { background: #f1f5f9; text-align: left; padding: 10px 12px; }
td { padding: 10px 12px; border-bottom: 1px solid #e2e8f0; }
.total { font-weight: bold; font-size: 1.1rem; }
.footer { margin-top: 48px; font-size: 0.875rem; color: #64748b; }
</style>
</head>
<body>
<div class="header">
<div>
<div class="company-name">Your Company</div>
<p>〒000-0000 東京都...<br>Tel: 03-XXXX-XXXX</p>
</div>
<div>
<h1>請求書</h1>
<p>No. INV-${customer.id}-${new Date().getFullYear()}${String(new Date().getMonth() + 1).padStart(2, '0')}</p>
</div>
</div>
<p><strong>請求先:</strong> ${customer.name} 御中</p>
<p><strong>請求日:</strong> ${new Date().toLocaleDateString('ja-JP')}</p>
<p><strong>お支払い期限:</strong> ${new Date(Date.now() + 30 * 86400000).toLocaleDateString('ja-JP')}</p>
<table>
<thead>
<tr><th>品目</th><th>数量</th><th>単価</th><th>金額</th></tr>
</thead>
<tbody>
${customer.items.map(item => `
<tr>
<td>${item.name}</td>
<td>${item.quantity}</td>
<td>¥${item.unitPrice.toLocaleString()}</td>
<td>¥${(item.quantity * item.unitPrice).toLocaleString()}</td>
</tr>
`).join('')}
</tbody>
<tfoot>
<tr class="total">
<td colspan="3">合計(税込)</td>
<td>¥${customer.total.toLocaleString()}</td>
</tr>
</tfoot>
</table>
<div class="footer">
<p>お振込先: ○○銀行 △△支店 普通 XXXXXXX</p>
</div>
</body>
</html>
`;
const response = await fetch('https://api.pdf.funbrew.cloud/v1/pdf/from-html', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FUNBREW_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ html, engine: 'quality', format: 'A4' }),
});
if (!response.ok) {
throw new Error(`API error ${response.status} for customer ${customer.id}`);
}
return Buffer.from(await response.arrayBuffer());
}
async function main() {
// 実際はDBから取得
const customers = [
{
id: 'C001',
name: '株式会社サンプル',
total: 110000,
items: [
{ name: 'FUNBREW PDF Pro プラン', quantity: 1, unitPrice: 100000 },
],
},
];
fs.mkdirSync('./invoices', { recursive: true });
for (const customer of customers) {
console.log(`Generating invoice for ${customer.name}...`);
const pdf = await generateInvoice(customer);
const filename = `invoice-${customer.id}-${Date.now()}.pdf`;
fs.writeFileSync(path.join('./invoices', filename), pdf);
console.log(` Saved: ${filename} (${pdf.length} bytes)`);
}
console.log('All invoices generated.');
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
請求書PDFの自動化については請求書PDF自動化ガイドでさらに詳しく解説しています。
実践的なTips
Tips 1: PDFの生成成功を検証する
- name: Validate PDF output
run: |
# PDFのサイズが最低1KB以上あることを確認
PDF_SIZE=$(wc -c < output.pdf)
echo "PDF size: ${PDF_SIZE} bytes"
if [ "$PDF_SIZE" -lt 1024 ]; then
echo "ERROR: PDF is too small. Generation may have failed."
exit 1
fi
# PDFのマジックバイトを確認(%PDF で始まる)
if ! xxd output.pdf | head -1 | grep -q "2550 4446"; then
echo "ERROR: Output is not a valid PDF file."
exit 1
fi
echo "PDF validation passed."
Tips 2: 並列生成でワークフローを高速化
jobs:
generate-pdfs:
runs-on: ubuntu-latest
strategy:
matrix:
document:
- { name: "report", template: "monthly-report", engine: "quality" }
- { name: "invoice", template: "standard-invoice", engine: "quality" }
- { name: "summary", template: "exec-summary", engine: "fast" }
max-parallel: 3 # 同時に最大3つ並列実行
steps:
- uses: actions/checkout@v4
- name: Generate ${{ matrix.document.name }} PDF
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
HTML=$(cat "templates/${{ matrix.document.template }}.html" | jq -Rs .)
curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-html \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"html\": $HTML, \"engine\": \"${{ matrix.document.engine }}\", \"format\": \"A4\"}" \
--output "${{ matrix.document.name }}.pdf"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.document.name }}-pdf
path: ${{ matrix.document.name }}.pdf
Tips 3: エラー時にSlack通知を送る
- name: Notify Slack on failure
if: failure()
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
run: |
curl -X POST "$SLACK_WEBHOOK" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"PDF生成ワークフローが失敗しました\",
\"blocks\": [
{
\"type\": \"section\",
\"text\": {
\"type\": \"mrkdwn\",
\"text\": \"*PDF Generation Failed*\n*Repository:* ${{ github.repository }}\n*Workflow:* ${{ github.workflow }}\n*Run:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|#${{ github.run_number }}>\"
}
}
]
}"
Tips 4: ワークフローの再試行ロジック
API呼び出しが一時的なネットワークエラーで失敗した場合に自動リトライする例です。
# retry.sh
#!/bin/bash
set -euo pipefail
MAX_RETRIES=3
RETRY_DELAY=5
generate_pdf() {
local attempt=1
while [ $attempt -le $MAX_RETRIES ]; do
echo "Attempt ${attempt}/${MAX_RETRIES}..."
if curl -X POST https://api.pdf.funbrew.cloud/v1/pdf/from-html \
-H "Authorization: Bearer $FUNBREW_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"html\": \"$1\", \"engine\": \"quality\", \"format\": \"A4\"}" \
--output output.pdf \
--fail \
--silent \
--show-error; then
echo "PDF generated successfully on attempt ${attempt}."
return 0
fi
echo "Attempt ${attempt} failed."
if [ $attempt -lt $MAX_RETRIES ]; then
echo "Retrying in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
RETRY_DELAY=$((RETRY_DELAY * 2)) # 指数バックオフ
fi
attempt=$((attempt + 1))
done
echo "All ${MAX_RETRIES} attempts failed."
return 1
}
generate_pdf "<h1>Hello World</h1>"
エラーハンドリングのパターンについてはエラーハンドリングガイドを参照してください。
Tips 5: キャッシュを活用してNode.js依存を高速化
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # package-lock.json のハッシュでキャッシュ
- run: npm ci # npm install より再現性が高い
Tips 6: ジョブのタイムアウトを設定する
PDF生成が無限に待機しないよう、ジョブとステップの両方にタイムアウトを設定します。
jobs:
generate:
runs-on: ubuntu-latest
timeout-minutes: 15 # ジョブ全体のタイムアウト
steps:
- name: Generate large PDF
timeout-minutes: 5 # このステップのタイムアウト
env:
FUNBREW_API_KEY: ${{ secrets.FUNBREW_API_KEY }}
run: |
curl --max-time 120 \ # curlのタイムアウト(秒)
-X POST https://api.pdf.funbrew.cloud/v1/pdf/from-html \
...
本番ワークフローのチェックリスト
ワークフローを本番環境に適用する前に確認しましょう。
- APIキーを
FUNBREW_API_KEYシークレットに登録している - コードやワークフローファイルにAPIキーをハードコードしていない
-
permissionsを最小限に絞っている(contents: writeが本当に必要かどうか) - ジョブとステップ両方にタイムアウトを設定している
- PDF生成後にファイルサイズの検証を行っている
- 失敗時に適切なエラーメッセージとSlack通知を設定している
-
retention-daysを用途に応じて設定している(テスト用は短く、重要な成果物は長く) - cronトリガーを使う場合、UTCとJSTの時差を考慮している
本番環境での運用全般は本番環境ガイドを参照してください。
まとめ
GitHub ActionsとFUNBREW PDF APIの組み合わせで、PDF生成を完全にCI/CDパイプラインへ組み込めます。
- Secrets管理: APIキーはGitHub Secretsに登録し、
${{ secrets.FUNBREW_API_KEY }}で参照 - HTML→PDF: curlかNode.jsスクリプトで動的にHTMLを生成してAPI呼び出し
- Markdown→PDF: git logやCHANGELOG.mdをPDFに変換してリリースに添付
- アーティファクト:
actions/upload-artifact@v4で保存期間と圧縮を制御 - cron: UTC基準でスケジュールを設定し、週次・月次レポートを自動生成
- 並列実行: matrixとmax-parallelで複数PDFを同時生成
まずは無料アカウントを作成して、PlaygroundでAPIの動作を確認してみてください。
関連リンク
- FUNBREW PDF APIドキュメント — エンドポイント仕様とオプション全覧
- 言語別クイックスタート — Node.js/Python/PHPの基本コード例
- Markdown→PDF APIガイド — MarkdownをHTMLに変換してPDF生成する方法
- PDF APIエラーハンドリング — CI/CDでのリトライ戦略と失敗対処
- Webhook連携ガイド — PDF生成完了後のPush通知連携
- Slack Bot実装ガイド — スラッシュコマンドでSlackからPDFをオンデマンド生成
- PDF API本番運用チェックリスト — 本番環境のセキュリティ・モニタリング
- PDF APIセキュリティガイド — APIキー管理とアクセス制御のベストプラクティス
- PDF一括生成(バッチ処理)ガイド — 複数PDFの並列生成
- AWS Lambdaサーバーレスガイド — Lambda + GitHub Actionsの組み合わせ活用
- レポートPDF生成ガイド — 定期レポートの自動化
- ユースケース一覧 — CI/CD活用が多いビジネスシナリオ