File: deploy-pantheon.yml
Trigger: Automatic on merged PR to master
Automatically deploys custom code to Pantheon when a pull request is merged.
What it does:
- Pushes custom theme and MU plugins to Pantheon
- Installs plugins/themes from
manifest.dev.json - Clears cache
- Reports deployment status
No manual trigger needed - happens automatically on PR merge.
File: sync-manifest-from-pantheon.yml
Trigger: Manual (workflow_dispatch) or Scheduled (weekly)
Pulls current state from Pantheon environments and updates manifest files.
How to run:
- Go to Actions tab in GitHub
- Select "Sync Manifest from Pantheon"
- Click "Run workflow"
- Choose environments:
all(default) - syncs dev, test, live (also checks for multidevs)dev- only dev environmenttest- only test environmentlive- only live environmentdev,test- multiple specific environments (comma-separated)
- Click "Run workflow"
What it does:
- Connects to Pantheon via Terminus
- For each selected environment:
- Queries WordPress version, PHP version, plugins, themes
- Saves to
bin/manifest.{env}.json
- Auto-commits changed manifest files back to repo
Output files:
bin/manifest.dev.json- Dev environment statebin/manifest.test.json- Test environment statebin/manifest.live.json- Live environment statebin/manifest.{multidev}.json- Multidev states (only when syncing "all")
When to use:
- After installing/updating plugins in Pantheon dashboard
- Before major deployments (to capture current state)
- Weekly (runs automatically on Mondays at 9am UTC)
- When you want to see what's installed in each environment
Optimizations:
- ✅ Terminus binary caching (saves ~3-5 seconds)
- ✅ Multidev check only runs when syncing "all"
- ✅ Properly detects and commits new manifest files
Auto-scheduled: Runs every Monday at 9am UTC
File: sync-pantheon-from-manifest.yml
Trigger: Manual (workflow_dispatch)
Syncs Pantheon dev environment to match a manifest file (local, dev, test, or live).
How to run:
- Go to Actions tab in GitHub
- Select "Sync Pantheon from Manifest"
- Click "Run workflow"
- Configure:
- source_env: Which manifest to use (local, dev, test, live)
- force_reinstall: Force reinstall everything (slow, default: false)
- commit_changes: Commit changes to Pantheon dev (default: false)
- deploy_to_test: Deploy to test after dev sync (default: false)
- deploy_to_live: Deploy to live after test (default: false)
- debug_mode: Enable verbose debug output (default: false)
- Click "Run workflow"
What it does:
- Switches Pantheon dev to SFTP mode
- Compares current dev state with selected manifest
- Shows detailed comparison summary:
- ✅ Unchanged plugins (already match)
- 📦 Plugins to install
- 🔄 Plugins to update/downgrade
- ⚡ Plugins to activate
- ⏸️ Plugins to deactivate
- 🗑️ Plugins to uninstall (not in manifest)
- Smart execution:
- If no changes needed → exits early (saves ~3 minutes!)
- Only executes operations for items that need changes
- Shows progress counters:
[3/10] Installing...
- Updates
manifest.dev.jsonwith final state - Auto-commits manifest changes back to repo
- Optionally deploys to test/live environments
New Features (April 2026):
- 🚀 Early exit: Skips execution when already in sync
- 📊 Comparison summary: See what will change before execution
- 🎯 Smart sync: Only touches plugins that need changes
- 🐛 Debug mode: Optional verbose output
- 📈 Progress tracking: Shows
[current/total]for all operations
Example Comparison Output:
╔═══════════════════════════════════════════╗
║ Plugin Comparison Summary ║
╚═══════════════════════════════════════════╝
✓ Unchanged (already match): 25
↓ Install (not present): 0
↑ Update/Downgrade (version): 2
⚡ Activate (inactive): 1
⚠ Deactivate (active): 0
✗ Uninstall (not in manifest): 4
⚠️ Plugins to be REMOVED:
- all-in-one-wp-migration|7.75
- altis-accelerate|1.0
- classic-editor|1.6.3
- custom-post-type-ui|1.13.8
Use cases:
- Sync local to dev: source_env=local (after making local changes)
- Replicate test to dev: source_env=test
- Reset dev to live: source_env=live
- Remove obsolete plugins: They'll show in "Uninstall" list
Performance:
- No changes: ~30 seconds (85% faster than before!)
- With changes: ~2-5 minutes (depending on number of plugins)
- Debug mode: adds ~10-20 seconds for verbose output
All workflows require these GitHub secrets to be configured:
| Secret Name | Description | Where to Get It |
|---|---|---|
PANTHEON_MACHINE_TOKEN |
Terminus authentication | https://dashboard.pantheon.io/users/#account/tokens/ |
PANTHEON_SITE_NAME |
Site machine name | eventsph |
PANTHEON_SSH_PRIVATE_KEY |
SSH key for Pantheon | Generate with ssh-keygen, add public key to Pantheon |
Setup:
- Go to repository Settings → Secrets and variables → Actions
- Click "New repository secret"
- Add each secret
1. Make changes locally (install/update plugins)
2. Run locally: ./bin/save-local-to-manifest.sh
3. Commit: git add bin/manifest.local.json && git commit -m "..."
4. Push: git push
5. Run "Sync Pantheon from Manifest" workflow
- source_env: local
- commit_changes: true
- deploy_to_test: false (optional)
→ Dev now matches your local environment
1. Remove plugins locally
2. Run locally: ./bin/save-local-to-manifest.sh
3. Commit and push manifest
4. Run "Sync Pantheon from Manifest" workflow
- source_env: local
- commit_changes: true
→ Workflow will show plugins in "Uninstall" list
→ Removes plugins not in manifest
1. Install/update plugin in Pantheon dev dashboard
2. Run "Sync Manifest from Pantheon" workflow
- environments: dev
→ Captures new plugin version in manifest.dev.json
→ Auto-commits to repo
3. Pull: git pull
4. Run locally: ./bin/local-install-from-manifest.sh --source-env=dev
→ Your local now matches dev
1. Run "Sync Manifest from Pantheon"
- environments: live
→ Captures live state to manifest.live.json
2. Run "Sync Pantheon from Manifest"
- source_env: live
- (this targets dev by default)
→ Dev now matches live
3. Deploy to test: terminus env:deploy eventsph.test
→ Test now matches live
Every Monday at 9am UTC:
→ "Sync Manifest from Pantheon" runs automatically
→ Commits show any drift between environments
→ Team reviews what changed during the week
→ Each environment has its own manifest file for easy comparison
1. Run "Sync Pantheon from Manifest" workflow
- source_env: local
- commit_changes: false
- debug_mode: false
2. Check workflow summary
→ Shows comparison without making changes
→ If "Already in Sync" → no action needed
→ If changes listed → run again with commit_changes=true
Per-environment files:
bin/
├── manifest.local.json ← Your local WordPress state
├── manifest.dev.json ← Pantheon dev environment
├── manifest.test.json ← Pantheon test environment
└── manifest.live.json ← Pantheon live environment
Benefits:
- ✅ Easier git tracking (clear diff per environment)
- ✅ Fewer merge conflicts
- ✅ Compare environments:
diff manifest.dev.json manifest.live.json - ✅ Simpler jq queries (no nested paths)
Each manifest contains:
{
"site_name": "eventsph",
"site_id": "4bf58ee6-...",
"environment": "dev",
"wordpress": {
"version": "6.9.4",
"db_version": "60717"
},
"php_version": "8.2",
"plugins": {
"jetpack": {
"version": "13.9",
"status": "active",
"update": "none"
}
},
"themes": { ... },
"active_theme": "astra",
"multisite": false,
"last_updated": "2026-04-21T12:00:00Z"
}- The selected source_env manifest doesn't exist
- Run "Sync Manifest from Pantheon" to create it
- Or run locally:
./bin/save-local-to-manifest.sh
- Check
PANTHEON_SITE_NAMEsecret is set toeventsph
- Regenerate
PANTHEON_MACHINE_TOKENin Pantheon dashboard - Update the GitHub secret
- Environment may not be in SFTP mode
- SSH keys not configured
- Try running workflow again (auto-switches to SFTP)
- Check if plugin exists on WordPress.org
- Premium plugins can't be auto-installed (need manual upload)
- Check exclusion list:
bin/manifest-exclude.txt
- This is normal if nothing changed since last sync
- Check workflow summary for "Already in Sync" message
- Fixed in April 2026!
- Now uses smart comparison
- Only reinstalls plugins with version/status differences
- Fixed in April 2026!
- Workflow now runs
git pull --rebasebefore push - Handles concurrent workflow runs
- Fixed in April 2026!
- Multidev check only runs when environments="all"
Each workflow creates a summary on the Actions run page showing:
- Comparison details (before execution)
- What was synced/deployed
- Plugin and theme changes
- Any errors or warnings
- Links to environments
- Execution time
New in April 2026:
- ✅ Early exit message when no changes needed
- 📊 Detailed comparison summary with counts
- 🎯 Progress tracking:
[3/10] Installing... - ⚡ Performance metrics
Check the Actions tab to see all workflow runs and their status.
- Workflows use GitHub Actions secrets (encrypted)
- Only repository admins can modify workflows
- Terminus token has limited scope (site access only)
- All actions are logged in GitHub Actions
- SSH keys stored securely in GitHub secrets
- Manifest files committed to repo (no sensitive data)
- Manifest structure: Single file → Per-environment files
bin/manifest.json→bin/manifest.{env}.json- Migration: Re-run sync workflows to create new files
- Smart comparison: Only syncs plugins that need changes
- Early exit: Skips execution when already in sync
- Debug mode: Optional verbose output via input flag
- Progress tracking: Shows
[current/total]for all operations - Terminus caching: Saves 3-5 seconds per workflow run
- Git pull before push: Prevents concurrent run conflicts
- No-change runs: ~3 min → ~30 sec (85% faster)
- With changes: Same speed, better visibility
- Reduced log verbosity by 70% (default mode)
- ✅ Multidev check only runs when needed
- ✅ New manifest files properly committed
- ✅ Git push conflicts handled automatically
- ✅ Plugins no longer reinstalled unnecessarily
- GitHub Actions Documentation
- Terminus Documentation
- Pantheon Workflows
- bin/README.md - Script documentation
- CHANGELOG.md - Detailed change history