WordPress plugin that auto-researches topics from Reddit, generates SEO-optimized articles via OpenRouter LLMs, runs them through a chief editor agent, and publishes on a daily schedule. Includes: - Full generation pipeline (collect → analyze → score → generate → review → publish) - Cost tracking and budget enforcement - Admin UI: settings, review queue, metrics, activity log - CI/CD pipeline (GitHub Actions → WordPress REST deploy) - Unit test suite (PHPUnit + Brain Monkey) - Structured logging with configurable verbosity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
160 lines
6.1 KiB
YAML
Executable File
160 lines
6.1 KiB
YAML
Executable File
# AutoBlogger CI/CD Pipeline
|
|
#
|
|
# Triggers on every push to main. Runs PHP lint and coding standards checks,
|
|
# packages the plugin into a clean zip (excluding dev files), and deploys it
|
|
# to the live WordPress site via the deploy-receiver mu-plugin REST endpoint.
|
|
#
|
|
# Required GitHub Secrets:
|
|
# DEPLOY_URL — https://peptiderepo.com/wp-json/autoblogger-deploy/v1/deploy
|
|
# DEPLOY_KEY — The token matching AUTOBLOGGER_DEPLOY_KEY in wp-config.php
|
|
#
|
|
# @see .github/mu-plugins/autoblogger-deploy-receiver.php — Server-side endpoint.
|
|
# @see scripts/deploy.sh — Manual deploy script.
|
|
|
|
name: Deploy AutoBlogger
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch: # Allow manual trigger from GitHub UI
|
|
|
|
concurrency:
|
|
group: deploy-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# Stage 1: Lint & Standards
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
lint:
|
|
name: PHP Lint & PHPCS
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.1'
|
|
tools: cs2pr, phpcs
|
|
coverage: none
|
|
|
|
- name: PHP syntax check
|
|
run: |
|
|
find . -name '*.php' -not -path './vendor/*' -not -path './tests/*' \
|
|
-exec php -l {} \; 2>&1 | grep -v "No syntax errors" | head -50
|
|
# Fail if any file has syntax errors
|
|
find . -name '*.php' -not -path './vendor/*' -not -path './tests/*' \
|
|
-exec php -l {} \; 2>&1 | grep -q "Parse error" && exit 1 || true
|
|
|
|
- name: Install WordPress Coding Standards
|
|
run: |
|
|
composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
|
|
composer global require --dev wp-coding-standards/wpcs:"^3.0" \
|
|
phpcsstandards/phpcsextra:"^1.0" \
|
|
phpcsstandards/phpcsutils:"^1.0"
|
|
|
|
- name: Run PHPCS (warnings only, non-blocking)
|
|
run: |
|
|
phpcs --standard=WordPress --extensions=php \
|
|
--ignore=vendor,tests,node_modules \
|
|
--report=checkstyle \
|
|
--warning-severity=0 \
|
|
. | cs2pr || true
|
|
# Non-blocking for now — we want visibility without breaking deploys
|
|
# while we clean up existing code. Remove "|| true" once clean.
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# Stage 2: Unit Tests
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
test:
|
|
name: PHPUnit Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.1'
|
|
extensions: openssl, json, mbstring
|
|
coverage: none
|
|
|
|
- name: Install Composer dependencies
|
|
run: composer install --no-interaction --prefer-dist
|
|
|
|
- name: Run PHPUnit
|
|
run: vendor/bin/phpunit --testdox
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# Stage 3: Package & Deploy
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
deploy:
|
|
name: Package & Deploy to Production
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, test]
|
|
if: github.ref == 'refs/heads/main'
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Read plugin version
|
|
id: version
|
|
run: |
|
|
VERSION=$(grep -oP "Version:\s*\K[0-9]+\.[0-9]+\.[0-9]+" autoblogger.php)
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
echo "Plugin version: $VERSION"
|
|
|
|
- name: Build plugin zip
|
|
run: |
|
|
# Create a clean build directory
|
|
mkdir -p build/autoblogger
|
|
|
|
# Copy only production files (exclude dev/CI artifacts)
|
|
rsync -av --exclude-from='.distignore' ./ build/autoblogger/
|
|
|
|
# Create the zip
|
|
cd build
|
|
zip -r "autoblogger-${{ steps.version.outputs.version }}.zip" autoblogger/
|
|
ls -lh "autoblogger-${{ steps.version.outputs.version }}.zip"
|
|
|
|
- name: Deploy to WordPress
|
|
env:
|
|
DEPLOY_URL: ${{ secrets.DEPLOY_URL }}
|
|
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
|
run: |
|
|
VERSION="${{ steps.version.outputs.version }}"
|
|
ZIP_PATH="build/autoblogger-${VERSION}.zip"
|
|
|
|
echo "Deploying AutoBlogger v${VERSION} to production..."
|
|
|
|
RESPONSE=$(curl -sS -w "\n%{http_code}" \
|
|
-X POST "${DEPLOY_URL}" \
|
|
-H "X-Deploy-Key: ${DEPLOY_KEY}" \
|
|
-F "plugin=@${ZIP_PATH}" \
|
|
--max-time 120)
|
|
|
|
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
|
BODY=$(echo "$RESPONSE" | head -n -1)
|
|
|
|
echo "HTTP ${HTTP_CODE}: ${BODY}"
|
|
|
|
if [ "$HTTP_CODE" -ne 200 ]; then
|
|
echo "::error::Deployment failed with HTTP ${HTTP_CODE}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Deployment successful!"
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: autoblogger-${{ steps.version.outputs.version }}
|
|
path: build/autoblogger-${{ steps.version.outputs.version }}.zip
|
|
retention-days: 30
|