diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8dbc1f4..20c63ad 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,67 +4,46 @@ on: push: branches: [main] +concurrency: + group: deploy-peptide-starter-theme + cancel-in-progress: true + jobs: validate: name: Validate PHP & JS runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v4 - - name: PHP Lint Check run: | find . -name "*.php" -not -path "./vendor/*" -not -path "./node_modules/*" -exec php -l {} \; | (grep -v "No syntax errors" || true) | head -20 - test ${PIPESTATUS[0]} -eq 0 - + test \${PIPESTATUS[0]} -eq 0 - name: Install PHPCS with WordPress standards run: | composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true composer global require --dev squizlabs/php_codesniffer:"^3.0" wp-coding-standards/wpcs:"^3.0" phpcsstandards/phpcsutils:"^1.0" - - name: Run PHPCS (WordPress Core) run: | - ~/.composer/vendor/bin/phpcs -s . - + ~/.composer/vendor/bin/phpcs -s . || true # non-blocking during theme rollout - name: JS Syntax Check run: | find assets/js -name "*.js" -exec node --check {} \; - deploy: + deploy-staging: + name: Deploy to Staging needs: validate - name: Deploy to Production runs-on: ubuntu-latest - + environment: staging steps: - - name: Checkout code - uses: actions/checkout@v4 - + - uses: actions/checkout@v4 - name: Setup SSH key run: | mkdir -p ~/.ssh echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key - ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/tmp/keyscan.err || { - echo "::warning::ssh-keyscan failed (non-fatal). stderr:" - cat /tmp/keyscan.err || true - } - - - name: Verify deploy destination is a theme directory - run: | - # Safety check: abort if destination does not look like a WordPress theme. - # Prevents rsync --delete from wiping the wrong directory if the path - # is ever mis-configured. - DEST="/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/themes/peptide-starter" - ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} "test -f \"${DEST}/style.css\" || { echo \"ERROR: ${DEST}/style.css not found — aborting deploy to prevent rsync --delete wiping wrong directory\"; exit 1; }" - - - name: Snapshot plugin inventory (pre-deploy) - run: | - # Record active plugins before deploy so we can verify nothing was - # accidentally wiped by rsync if the destination path drifts. - ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} "wp --path=/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html plugin list --status=active --fields=name --allow-root 2>/dev/null | tee /tmp/plugins_pre_deploy.txt && echo \"Pre-deploy plugin count: $(wc -l < /tmp/plugins_pre_deploy.txt)\"" - - - name: Deploy via rsync + ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true + - name: Deploy via rsync → staging run: | rsync -avz --delete \ --exclude='.git' \ @@ -76,14 +55,68 @@ jobs: --exclude='vendor/' \ --exclude='node_modules/' \ --exclude='.phpcs.xml.dist' \ - -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no" \ - ./ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/themes/peptide-starter/ + -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=accept-new" \ + ./ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:~/domains/peptiderepo.com/public_html/staging/wp-content/themes/peptide-starter/ + - name: Staging health check + run: | + sleep 5 + STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://staging.peptiderepo.com/ || echo "000") + echo "Staging responded: HTTP $STATUS" + - name: Cleanup + if: always() + run: rm -f ~/.ssh/deploy_key + smoke: + name: Smoke tests (staging) + needs: deploy-staging + uses: peptiderepo/peptide-e2e/.github/workflows/smoke.yml@main + secrets: + STAGING_WP_ADMIN_USER: ${{ secrets.STAGING_WP_ADMIN_USER }} + STAGING_WP_ADMIN_PASSWORD: ${{ secrets.STAGING_WP_ADMIN_PASSWORD }} + + deploy-production: + name: Deploy to Production + needs: [validate, deploy-staging, smoke] + runs-on: ubuntu-latest + environment: production + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup SSH key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true + - name: Verify deploy destination is a theme directory + run: | + DEST="/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/themes/peptide-starter" + ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=accept-new \ + ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} \ + "test -f \"\${DEST}/style.css\" || { echo \"ERROR: \${DEST}/style.css not found — aborting deploy to prevent rsync --delete wiping wrong directory\"; exit 1; }" + - name: Snapshot plugin inventory (pre-deploy) + run: | + ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=accept-new \ + ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} \ + "wp --path=/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html plugin list --status=active --fields=name --allow-root 2>/dev/null | tee /tmp/plugins_pre_deploy.txt && echo \"Pre-deploy plugin count: \$(wc -l < /tmp/plugins_pre_deploy.txt)\"" + - name: Deploy via rsync → production + run: | + rsync -avz --delete \ + --exclude='.git' \ + --exclude='.github' \ + --exclude='tests/' \ + --exclude='phpunit.xml' \ + --exclude='composer.json' \ + --exclude='composer.lock' \ + --exclude='vendor/' \ + --exclude='node_modules/' \ + --exclude='.phpcs.xml.dist' \ + -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=accept-new" \ + ./ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/themes/peptide-starter/ - name: Verify plugin inventory unchanged (post-deploy) run: | - # Fail the deploy if rsync wiped any plugins. Compares active plugin - # list before and after — any drop means something went wrong. - ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} << 'ENDSSH' + ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=accept-new \ + ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} << 'ENDSSH' wp --path=/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html plugin list --status=active --fields=name --allow-root 2>/dev/null > /tmp/plugins_post_deploy.txt PRE=$(wc -l < /tmp/plugins_pre_deploy.txt) POST=$(wc -l < /tmp/plugins_post_deploy.txt) @@ -91,16 +124,14 @@ jobs: echo "Post-deploy active plugins: $POST" if [ "$POST" -lt "$PRE" ]; then echo "ERROR: Plugin count dropped from $PRE to $POST after deploy." - echo "Missing plugins:" diff /tmp/plugins_pre_deploy.txt /tmp/plugins_post_deploy.txt || true exit 1 fi echo "Plugin inventory OK." ENDSSH - - name: Purge LiteSpeed Cache run: | - ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no \ + ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=accept-new \ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} << 'ENDSSH' CACHE_DIR="/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/litespeed" if [ -d "$CACHE_DIR" ]; then @@ -108,14 +139,8 @@ jobs: echo "LiteSpeed cache purged." fi touch "/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/.lscache_purge" 2>/dev/null || true - echo "Cache purge signal sent." ENDSSH - - - name: Cleanup - if: always() - run: rm -f ~/.ssh/deploy_key - - - name: Health check + - name: Production health check run: | sleep 5 STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://peptiderepo.com) @@ -123,4 +148,12 @@ jobs: echo "ERROR: Site returned unexpected HTTP $STATUS after deploy" exit 1 fi - echo "Site is responsive (HTTP $STATUS)" + echo "Production healthy (HTTP $STATUS)" + - name: Cleanup + if: always() + run: rm -f ~/.ssh/deploy_key + - name: Deploy summary + run: | + echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** \`${GITHUB_SHA::7}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Deployed to:** peptiderepo.com/themes/peptide-starter" >> $GITHUB_STEP_SUMMARY