wordpress-agent-kit 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/wp-bootstrap/SKILL.md +314 -0
- package/.agents/skills/wp-bootstrap/references/composer-setup.md +275 -0
- package/.agents/skills/wp-bootstrap/references/monorepo-patterns.md +184 -0
- package/.agents/skills/wp-bootstrap/scripts/bootstrap.sh +151 -0
- package/.agents/skills/wp-bootstrap/scripts/detect-structure.mjs +466 -0
- package/.agents/skills/wp-bootstrap/scripts/package-wp.sh +173 -0
- package/.agents/skills/wp-bootstrap/scripts/playground-start.sh +148 -0
- package/.agents/skills/wp-bootstrap/scripts/playground-verify.sh +165 -0
- package/.agents/skills/wp-bootstrap/scripts/setup-github.sh +417 -0
- package/{.github → .agents}/skills/wp-wpcli-and-ops/SKILL.md +11 -9
- package/.agents/skills/wp-wpengine/SKILL.md +462 -0
- package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
- package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +743 -0
- package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.github/agents/wp-architect.agent.md +1 -2
- package/.github/copilot-instructions.md +1 -1
- package/.github/instructions/wordpress-workflow.instructions.md +3 -3
- package/AGENTS.md +22 -10
- package/AGENTS.template.md +20 -10
- package/README.md +89 -85
- package/dist/cli.js +7 -1
- package/dist/commands/bootstrap.js +105 -0
- package/dist/commands/clean-skills.js +64 -0
- package/dist/commands/setup.js +6 -2
- package/dist/commands/sync-skills.js +3 -0
- package/dist/lib/api.js +165 -5
- package/dist/lib/bootstrap.js +352 -0
- package/dist/lib/installer.js +166 -2
- package/extensions/wp-agent-kit/index.ts +325 -10
- package/package.json +10 -14
- package/skills-custom/wp-bootstrap/SKILL.md +314 -0
- package/skills-custom/wp-bootstrap/references/composer-setup.md +275 -0
- package/skills-custom/wp-bootstrap/references/monorepo-patterns.md +184 -0
- package/skills-custom/wp-bootstrap/scripts/bootstrap.sh +151 -0
- package/skills-custom/wp-bootstrap/scripts/detect-structure.mjs +466 -0
- package/skills-custom/wp-bootstrap/scripts/package-wp.sh +173 -0
- package/skills-custom/wp-bootstrap/scripts/playground-start.sh +148 -0
- package/skills-custom/wp-bootstrap/scripts/playground-verify.sh +165 -0
- package/skills-custom/wp-bootstrap/scripts/setup-github.sh +417 -0
- package/skills-custom/wp-wpengine/SKILL.md +362 -27
- package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
- package/skills-custom/wp-wpengine/references/github-actions-deploy.md +743 -0
- package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.github/skills/wp-wpengine/SKILL.md +0 -127
- package/.github/workflows/ci.yml +0 -44
- package/.husky/pre-commit +0 -7
- package/CLI_REVIEW.md +0 -250
- package/biome.json +0 -39
- /package/{.github → .agents}/skills/blueprint/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wordpress-router/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wordpress-router/references/decision-tree.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/delegate-helper-pattern.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/domain-vs-projection.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/error-code-vocabulary.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/grouping-heuristic.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/input-schema-gotchas.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/php-registration.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/plugin-family-patterns.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/rest-api.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/shared-core-service.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/references/audit-schema.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/references/capability-gate-tracing.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/references/controller-enumeration.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/annotation-correctness.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/audit-schema-validation.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/permission-roundtrip.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/runtime-harness.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/schema-lints.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/static-enumeration.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/attributes-and-serialization.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/block-json.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/creating-new-blocks.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/deprecations.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/dynamic-rendering.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/inner-blocks.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/registration.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/supports-and-wrappers.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/tooling-and-testing.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/scripts/list_blocks.mjs +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/creating-new-block-theme.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/patterns.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/style-variations.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/templates-and-parts.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/theme-json.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/scripts/detect_block_themes.mjs +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/references/directives-quickref.md +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/references/server-side-rendering.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/autoload-options.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/cron.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/database.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/http-api.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/measurement.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/object-cache.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/query-monitor-headless.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/server-timing.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/wp-cli-doctor.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/wp-cli-profile.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/scripts/perf_inspect.mjs +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/references/configuration.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/references/third-party-classes.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/references/wordpress-annotations.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/scripts/phpstan_inspect.mjs +0 -0
- /package/{.github → .agents}/skills/wp-playground/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/blueprints.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/cli-commands.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/e2e-playwright.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/data-and-cron.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/lifecycle.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/security.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/settings-api.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/structure.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/scripts/detect_plugins.mjs +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/naming-rules.md +0 -0
- /package/{.github → .agents}/skills/wp-project-triage/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-project-triage/references/triage.schema.json +0 -0
- /package/{.github → .agents}/skills/wp-project-triage/scripts/detect_wp_project.mjs +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/authentication.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/custom-content-types.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/discovery-and-params.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/responses-and-fields.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/routes-and-endpoints.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/schema.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/automation.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/cron-and-cache.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/multisite.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/packages-and-updates.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/safety.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/search-replace.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +0 -0
- /package/{.github → .agents}/skills/wpds/SKILL.md +0 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# setup-github.sh — configure GitHub repo for WP Engine CI/CD using the gh CLI.
|
|
3
|
+
#
|
|
4
|
+
# Checks authentication, reports missing secrets, sets them interactively or
|
|
5
|
+
# from provided values, and configures branch protection for deploy branches.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# bash .agents/skills/wp-bootstrap/scripts/setup-github.sh [OPTIONS]
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
# --check-only Report status without making any changes (default if no --set-*)
|
|
12
|
+
# --set-secrets Interactively set missing WP Engine secrets
|
|
13
|
+
# --set-protection Configure branch protection for main/staging/develop
|
|
14
|
+
# --set-all Set secrets + branch protection
|
|
15
|
+
# --wpe-key=<file> Path to WP Engine SSH private key (default: ~/.ssh/wpengine_ed25519)
|
|
16
|
+
# --wpe-prod=<slug> WP Engine production install slug
|
|
17
|
+
# --wpe-staging=<slug> WP Engine staging install slug
|
|
18
|
+
# --wpe-dev=<slug> WP Engine dev install slug
|
|
19
|
+
# --no-confirm Skip confirmation prompts (use with care)
|
|
20
|
+
#
|
|
21
|
+
# Requires: gh CLI installed and authenticated (gh auth login)
|
|
22
|
+
#
|
|
23
|
+
# Exit codes:
|
|
24
|
+
# 0 All checks passed / actions completed
|
|
25
|
+
# 1 Error or user cancelled
|
|
26
|
+
# 2 gh CLI not installed or not authenticated
|
|
27
|
+
|
|
28
|
+
set -uo pipefail
|
|
29
|
+
|
|
30
|
+
# ── Parse args ────────────────────────────────────────────────────────────────
|
|
31
|
+
CHECK_ONLY=true
|
|
32
|
+
SET_SECRETS=false
|
|
33
|
+
SET_PROTECTION=false
|
|
34
|
+
WPE_KEY_FILE="${HOME}/.ssh/wpengine_ed25519"
|
|
35
|
+
WPE_PROD=""
|
|
36
|
+
WPE_STAGING=""
|
|
37
|
+
WPE_DEV=""
|
|
38
|
+
NO_CONFIRM=false
|
|
39
|
+
|
|
40
|
+
for arg in "$@"; do
|
|
41
|
+
case "$arg" in
|
|
42
|
+
--check-only) CHECK_ONLY=true ;;
|
|
43
|
+
--set-secrets) SET_SECRETS=true; CHECK_ONLY=false ;;
|
|
44
|
+
--set-protection) SET_PROTECTION=true; CHECK_ONLY=false ;;
|
|
45
|
+
--set-all) SET_SECRETS=true; SET_PROTECTION=true; CHECK_ONLY=false ;;
|
|
46
|
+
--wpe-key=*) WPE_KEY_FILE="${arg#--wpe-key=}" ;;
|
|
47
|
+
--wpe-prod=*) WPE_PROD="${arg#--wpe-prod=}" ;;
|
|
48
|
+
--wpe-staging=*) WPE_STAGING="${arg#--wpe-staging=}" ;;
|
|
49
|
+
--wpe-dev=*) WPE_DEV="${arg#--wpe-dev=}" ;;
|
|
50
|
+
--no-confirm) NO_CONFIRM=true ;;
|
|
51
|
+
esac
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
55
|
+
ok() { printf ' \033[32m✓\033[0m %s\n' "$*"; }
|
|
56
|
+
fail() { printf ' \033[31m✗\033[0m %s\n' "$*" >&2; }
|
|
57
|
+
warn() { printf ' \033[33m⚠\033[0m %s\n' "$*"; }
|
|
58
|
+
info() { printf ' \033[34m→\033[0m %s\n' "$*"; }
|
|
59
|
+
sep() { printf '\n\033[1m── %s\033[0m\n' "$*"; }
|
|
60
|
+
|
|
61
|
+
confirm() {
|
|
62
|
+
local prompt="${1} [y/N] "
|
|
63
|
+
$NO_CONFIRM && { echo "(auto-confirmed)"; return 0; }
|
|
64
|
+
read -r -p "$prompt" ans
|
|
65
|
+
[[ "${ans,,}" == "y" || "${ans,,}" == "yes" ]]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# ── 1. Check gh CLI ───────────────────────────────────────────────────────────
|
|
69
|
+
sep "GitHub CLI check"
|
|
70
|
+
|
|
71
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
72
|
+
fail "gh CLI not installed."
|
|
73
|
+
echo " Install: https://cli.github.com"
|
|
74
|
+
echo " macOS: brew install gh"
|
|
75
|
+
echo " Linux: sudo apt install gh (or see above URL)"
|
|
76
|
+
exit 2
|
|
77
|
+
fi
|
|
78
|
+
ok "gh $(gh --version | head -1 | awk '{print $3}')"
|
|
79
|
+
|
|
80
|
+
# ── 2. Check authentication ────────────────────────────────────────────────────
|
|
81
|
+
sep "Authentication"
|
|
82
|
+
|
|
83
|
+
AUTH_STATUS=$(gh auth status 2>&1)
|
|
84
|
+
if ! echo "$AUTH_STATUS" | grep -q "Logged in to github.com"; then
|
|
85
|
+
fail "Not authenticated. Run: gh auth login"
|
|
86
|
+
exit 2
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
ACCOUNT=$(echo "$AUTH_STATUS" | grep -o 'account [^ ]*' | awk '{print $2}' | head -1)
|
|
90
|
+
ok "Authenticated as @${ACCOUNT}"
|
|
91
|
+
|
|
92
|
+
# ── 3. Detect repo ────────────────────────────────────────────────────────────
|
|
93
|
+
sep "Repository"
|
|
94
|
+
|
|
95
|
+
ORIGIN=$(git remote get-url origin 2>/dev/null || echo "")
|
|
96
|
+
if [ -z "$ORIGIN" ]; then
|
|
97
|
+
fail "No 'origin' remote found. Is this a git repo with a GitHub remote?"
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Parse owner/repo from SSH or HTTPS URL
|
|
102
|
+
if [[ "$ORIGIN" =~ git@github\.com[:/]([^/]+)/([^.]+)(\.git)?$ ]]; then
|
|
103
|
+
OWNER="${BASH_REMATCH[1]}"
|
|
104
|
+
REPO="${BASH_REMATCH[2]}"
|
|
105
|
+
elif [[ "$ORIGIN" =~ https?://github\.com/([^/]+)/([^/.]+) ]]; then
|
|
106
|
+
OWNER="${BASH_REMATCH[1]}"
|
|
107
|
+
REPO="${BASH_REMATCH[2]}"
|
|
108
|
+
else
|
|
109
|
+
fail "Cannot parse GitHub owner/repo from remote: $ORIGIN"
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Verify repo is accessible
|
|
114
|
+
REPO_INFO=$(gh repo view "${OWNER}/${REPO}" --json name,owner,url,defaultBranchRef,visibility 2>&1)
|
|
115
|
+
if ! echo "$REPO_INFO" | grep -q '"name"'; then
|
|
116
|
+
fail "Cannot access repo ${OWNER}/${REPO}. Check permissions."
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
VISIBILITY=$(echo "$REPO_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['visibility'])" 2>/dev/null || echo "unknown")
|
|
121
|
+
DEFAULT_BRANCH=$(echo "$REPO_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['defaultBranchRef']['name'])" 2>/dev/null || echo "main")
|
|
122
|
+
REPO_URL=$(echo "$REPO_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['url'])" 2>/dev/null || echo "")
|
|
123
|
+
|
|
124
|
+
ok "${OWNER}/${REPO} (${VISIBILITY,,}) — ${REPO_URL}"
|
|
125
|
+
info "Default branch: ${DEFAULT_BRANCH}"
|
|
126
|
+
|
|
127
|
+
# ── 4. Check secrets ──────────────────────────────────────────────────────────
|
|
128
|
+
sep "GitHub Secrets"
|
|
129
|
+
|
|
130
|
+
EXISTING_JSON=$(gh secret list --repo "${OWNER}/${REPO}" --json name 2>/dev/null || echo "[]")
|
|
131
|
+
EXISTING_SECRETS=$(echo "$EXISTING_JSON" | python3 -c "
|
|
132
|
+
import sys,json
|
|
133
|
+
secrets = json.load(sys.stdin)
|
|
134
|
+
for s in secrets: print(s['name'])
|
|
135
|
+
" 2>/dev/null || echo "")
|
|
136
|
+
|
|
137
|
+
# Define required secrets and their descriptions
|
|
138
|
+
declare -A SECRET_DESC
|
|
139
|
+
SECRET_DESC[WPE_SSH_KEY]="WP Engine SSH private key (contents of wpengine_ed25519)"
|
|
140
|
+
SECRET_DESC[WPE_SSH_KNOWN_HOSTS]="Known hosts for git.wpengine.com + ssh.wpengine.net"
|
|
141
|
+
SECRET_DESC[WPE_PROD_INSTALL]="Production install slug (e.g. mysite)"
|
|
142
|
+
SECRET_DESC[WPE_PROD_GIT_URL]="Production git push URL from WPE portal"
|
|
143
|
+
SECRET_DESC[WPE_STAGING_INSTALL]="Staging install slug (e.g. mysitestg)"
|
|
144
|
+
SECRET_DESC[WPE_STAGING_GIT_URL]="Staging git push URL from WPE portal"
|
|
145
|
+
SECRET_DESC[WPE_DEV_INSTALL]="Development install slug (e.g. mysitedev)"
|
|
146
|
+
SECRET_DESC[WPE_DEV_GIT_URL]="Development git push URL from WPE portal"
|
|
147
|
+
SECRET_DESC[WPE_API_USER]="WP Engine API username (from my.wpengine.com/api_access)"
|
|
148
|
+
SECRET_DESC[WPE_API_PASSWORD]="WP Engine API password"
|
|
149
|
+
SECRET_DESC[SLACK_WEBHOOK_URL]="Slack incoming webhook URL (optional)"
|
|
150
|
+
|
|
151
|
+
REQUIRED_SECRETS=(
|
|
152
|
+
WPE_SSH_KEY WPE_SSH_KNOWN_HOSTS
|
|
153
|
+
WPE_PROD_INSTALL WPE_PROD_GIT_URL
|
|
154
|
+
WPE_STAGING_INSTALL WPE_STAGING_GIT_URL
|
|
155
|
+
WPE_DEV_INSTALL WPE_DEV_GIT_URL
|
|
156
|
+
WPE_API_USER WPE_API_PASSWORD
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
MISSING_SECRETS=()
|
|
160
|
+
for secret in "${REQUIRED_SECRETS[@]}"; do
|
|
161
|
+
if echo "$EXISTING_SECRETS" | grep -qx "$secret"; then
|
|
162
|
+
ok "$secret"
|
|
163
|
+
else
|
|
164
|
+
warn "$secret — MISSING"
|
|
165
|
+
MISSING_SECRETS+=("$secret")
|
|
166
|
+
fi
|
|
167
|
+
done
|
|
168
|
+
|
|
169
|
+
# Optional
|
|
170
|
+
if echo "$EXISTING_SECRETS" | grep -qx "SLACK_WEBHOOK_URL"; then
|
|
171
|
+
ok "SLACK_WEBHOOK_URL (optional)"
|
|
172
|
+
else
|
|
173
|
+
info "SLACK_WEBHOOK_URL — not set (optional)"
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
echo ""
|
|
177
|
+
if [ "${#MISSING_SECRETS[@]}" -eq 0 ]; then
|
|
178
|
+
ok "All required secrets are set ✓"
|
|
179
|
+
else
|
|
180
|
+
warn "${#MISSING_SECRETS[@]} secret(s) missing — run with --set-secrets to configure"
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
# ── 5. Set missing secrets ────────────────────────────────────────────────────
|
|
184
|
+
if $SET_SECRETS && [ "${#MISSING_SECRETS[@]}" -gt 0 ]; then
|
|
185
|
+
sep "Setting missing secrets"
|
|
186
|
+
|
|
187
|
+
for secret in "${MISSING_SECRETS[@]}"; do
|
|
188
|
+
echo ""
|
|
189
|
+
info "Setting: ${secret}"
|
|
190
|
+
info "Purpose: ${SECRET_DESC[$secret]}"
|
|
191
|
+
|
|
192
|
+
VALUE=""
|
|
193
|
+
|
|
194
|
+
case "$secret" in
|
|
195
|
+
WPE_SSH_KEY)
|
|
196
|
+
if [ -f "$WPE_KEY_FILE" ]; then
|
|
197
|
+
info "Reading from $WPE_KEY_FILE"
|
|
198
|
+
if confirm " Set WPE_SSH_KEY from $WPE_KEY_FILE?"; then
|
|
199
|
+
VALUE=$(cat "$WPE_KEY_FILE")
|
|
200
|
+
fi
|
|
201
|
+
else
|
|
202
|
+
warn "Key file not found: $WPE_KEY_FILE"
|
|
203
|
+
info "Alternatives:"
|
|
204
|
+
info " 1. op read 'op://Employee/wpengine_ed25519/private key' > ~/.ssh/wpengine_ed25519"
|
|
205
|
+
info " 2. Paste the key manually below (enter blank line when done)"
|
|
206
|
+
if confirm " Enter key manually?"; then
|
|
207
|
+
LINES=()
|
|
208
|
+
echo " Paste private key (empty line to finish):"
|
|
209
|
+
while IFS= read -r line; do
|
|
210
|
+
[ -z "$line" ] && break
|
|
211
|
+
LINES+=("$line")
|
|
212
|
+
done
|
|
213
|
+
VALUE=$(printf '%s\n' "${LINES[@]}")
|
|
214
|
+
fi
|
|
215
|
+
fi
|
|
216
|
+
;;
|
|
217
|
+
|
|
218
|
+
WPE_SSH_KNOWN_HOSTS)
|
|
219
|
+
info "Generating from ssh-keyscan..."
|
|
220
|
+
VALUE=$(
|
|
221
|
+
{
|
|
222
|
+
# git push host — RSA key
|
|
223
|
+
ssh-keyscan -t rsa git.wpengine.com 2>/dev/null
|
|
224
|
+
# Include hashed entry for git.wpengine.com too
|
|
225
|
+
ssh-keyscan -H git.wpengine.com 2>/dev/null
|
|
226
|
+
# Note: SSH gateway subdomains ({install}.ssh.wpengine.net) use
|
|
227
|
+
# StrictHostKeyChecking=accept-new in the workflow SSH config,
|
|
228
|
+
# so they don't need pre-scanned entries here.
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
if [ -n "$VALUE" ]; then
|
|
232
|
+
info "Generated $(echo "$VALUE" | wc -l) known_hosts entries"
|
|
233
|
+
info "Gateway subdomains auto-accepted via StrictHostKeyChecking=accept-new"
|
|
234
|
+
confirm " Set WPE_SSH_KNOWN_HOSTS?" && true || VALUE=""
|
|
235
|
+
else
|
|
236
|
+
warn "ssh-keyscan failed — check network connectivity"
|
|
237
|
+
fi
|
|
238
|
+
;;
|
|
239
|
+
|
|
240
|
+
WPE_PROD_INSTALL)
|
|
241
|
+
[ -n "$WPE_PROD" ] && VALUE="$WPE_PROD" || {
|
|
242
|
+
read -r -p " Production install slug (e.g. mysite): " VALUE
|
|
243
|
+
}
|
|
244
|
+
;;
|
|
245
|
+
|
|
246
|
+
WPE_PROD_GIT_URL)
|
|
247
|
+
SLUG="${WPE_PROD:-}"
|
|
248
|
+
if [ -z "$SLUG" ]; then
|
|
249
|
+
# Try to get from wp-cli.yml
|
|
250
|
+
SLUG=$(grep -A2 '@production' wp-cli.yml 2>/dev/null | grep 'ssh:' | awk '{print $2}' | cut -d@ -f1 || echo "")
|
|
251
|
+
fi
|
|
252
|
+
info "Get exact URL from: https://my.wpengine.com/installs/${SLUG:-<install>}/git_push"
|
|
253
|
+
read -r -p " Production git URL (e.g. git@git.wpengine.com:mysite.git): " VALUE
|
|
254
|
+
;;
|
|
255
|
+
|
|
256
|
+
WPE_STAGING_INSTALL)
|
|
257
|
+
[ -n "$WPE_STAGING" ] && VALUE="$WPE_STAGING" || {
|
|
258
|
+
read -r -p " Staging install slug (e.g. mysitestg): " VALUE
|
|
259
|
+
}
|
|
260
|
+
;;
|
|
261
|
+
|
|
262
|
+
WPE_STAGING_GIT_URL)
|
|
263
|
+
SLUG="${WPE_STAGING:-}"
|
|
264
|
+
info "Get exact URL from: https://my.wpengine.com/installs/${SLUG:-<install>}/git_push"
|
|
265
|
+
read -r -p " Staging git URL (e.g. git@git.wpengine.com:mysitestg.git): " VALUE
|
|
266
|
+
;;
|
|
267
|
+
|
|
268
|
+
WPE_DEV_INSTALL)
|
|
269
|
+
[ -n "$WPE_DEV" ] && VALUE="$WPE_DEV" || {
|
|
270
|
+
read -r -p " Dev install slug (e.g. mysitedev): " VALUE
|
|
271
|
+
}
|
|
272
|
+
;;
|
|
273
|
+
|
|
274
|
+
WPE_DEV_GIT_URL)
|
|
275
|
+
SLUG="${WPE_DEV:-}"
|
|
276
|
+
info "Get exact URL from: https://my.wpengine.com/installs/${SLUG:-<install>}/git_push"
|
|
277
|
+
read -r -p " Dev git URL (e.g. git@git.wpengine.com:mysitedev.git): " VALUE
|
|
278
|
+
;;
|
|
279
|
+
|
|
280
|
+
WPE_API_USER)
|
|
281
|
+
info "Find at: https://my.wpengine.com/api_access"
|
|
282
|
+
read -r -p " WP Engine API username: " VALUE
|
|
283
|
+
;;
|
|
284
|
+
|
|
285
|
+
WPE_API_PASSWORD)
|
|
286
|
+
info "Find at: https://my.wpengine.com/api_access"
|
|
287
|
+
read -r -s -p " WP Engine API password (hidden): " VALUE
|
|
288
|
+
echo ""
|
|
289
|
+
;;
|
|
290
|
+
esac
|
|
291
|
+
|
|
292
|
+
if [ -n "$VALUE" ]; then
|
|
293
|
+
echo "$VALUE" | gh secret set "$secret" --repo "${OWNER}/${REPO}"
|
|
294
|
+
ok "$secret set"
|
|
295
|
+
else
|
|
296
|
+
warn "$secret skipped"
|
|
297
|
+
fi
|
|
298
|
+
done
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
# ── 6. Branch protection ──────────────────────────────────────────────────────
|
|
302
|
+
sep "Branch Protection"
|
|
303
|
+
|
|
304
|
+
check_branch_protection() {
|
|
305
|
+
local branch="$1"
|
|
306
|
+
local prot
|
|
307
|
+
prot=$(gh api "repos/${OWNER}/${REPO}/branches/${branch}/protection" 2>/dev/null || echo "")
|
|
308
|
+
if [ -z "$prot" ] || echo "$prot" | grep -q '"message"'; then
|
|
309
|
+
warn "${branch}: not protected"
|
|
310
|
+
return 1
|
|
311
|
+
fi
|
|
312
|
+
local checks
|
|
313
|
+
checks=$(echo "$prot" | python3 -c "
|
|
314
|
+
import sys,json
|
|
315
|
+
p = json.load(sys.stdin)
|
|
316
|
+
checks = p.get('required_status_checks',{}).get('contexts',[])
|
|
317
|
+
reviews = p.get('required_pull_request_reviews',{}).get('required_approving_review_count',0)
|
|
318
|
+
print(f'status checks={checks}, reviewers={reviews}')
|
|
319
|
+
" 2>/dev/null || echo "configured")
|
|
320
|
+
ok "${branch}: protected (${checks})"
|
|
321
|
+
return 0
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
BRANCHES_NEEDING_PROTECTION=()
|
|
325
|
+
|
|
326
|
+
for branch in "$DEFAULT_BRANCH" "staging" "develop"; do
|
|
327
|
+
if ! check_branch_protection "$branch" 2>/dev/null; then
|
|
328
|
+
BRANCHES_NEEDING_PROTECTION+=("$branch")
|
|
329
|
+
fi
|
|
330
|
+
done
|
|
331
|
+
|
|
332
|
+
if [ "${#BRANCHES_NEEDING_PROTECTION[@]}" -eq 0 ]; then
|
|
333
|
+
ok "Branch protection looks good"
|
|
334
|
+
elif ! $SET_PROTECTION; then
|
|
335
|
+
warn "${#BRANCHES_NEEDING_PROTECTION[@]} branch(es) not protected — run with --set-protection to configure"
|
|
336
|
+
fi
|
|
337
|
+
|
|
338
|
+
# ── 7. Apply branch protection ────────────────────────────────────────────────
|
|
339
|
+
if $SET_PROTECTION && [ "${#BRANCHES_NEEDING_PROTECTION[@]}" -gt 0 ]; then
|
|
340
|
+
sep "Configuring Branch Protection"
|
|
341
|
+
|
|
342
|
+
for branch in "${BRANCHES_NEEDING_PROTECTION[@]}"; do
|
|
343
|
+
echo ""
|
|
344
|
+
info "Configuring: ${branch}"
|
|
345
|
+
|
|
346
|
+
# Determine required reviewer count
|
|
347
|
+
if [ "$branch" = "$DEFAULT_BRANCH" ]; then
|
|
348
|
+
REVIEWERS=2 # Production needs 2
|
|
349
|
+
else
|
|
350
|
+
REVIEWERS=1 # Staging/develop needs 1
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Required status checks — gate-passed is the canonical check from ci-gate.yml
|
|
354
|
+
CONTEXTS='["gate-passed"]'
|
|
355
|
+
|
|
356
|
+
# For production, also require staging-source-check
|
|
357
|
+
if [ "$branch" = "$DEFAULT_BRANCH" ]; then
|
|
358
|
+
CONTEXTS='["gate-passed","staging-source-check"]'
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
if ! confirm " Set ${branch} protection (${REVIEWERS} reviewers, checks: ${CONTEXTS})?"; then
|
|
362
|
+
warn "${branch}: skipped"
|
|
363
|
+
continue
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
PAYLOAD=$(python3 -c "
|
|
367
|
+
import json
|
|
368
|
+
contexts = ${CONTEXTS}
|
|
369
|
+
payload = {
|
|
370
|
+
'required_status_checks': {
|
|
371
|
+
'strict': True,
|
|
372
|
+
'contexts': contexts
|
|
373
|
+
},
|
|
374
|
+
'enforce_admins': True,
|
|
375
|
+
'required_pull_request_reviews': {
|
|
376
|
+
'dismiss_stale_reviews': True,
|
|
377
|
+
'require_code_owner_reviews': False,
|
|
378
|
+
'required_approving_review_count': ${REVIEWERS}
|
|
379
|
+
},
|
|
380
|
+
'restrictions': None,
|
|
381
|
+
'allow_force_pushes': False,
|
|
382
|
+
'allow_deletions': False
|
|
383
|
+
}
|
|
384
|
+
print(json.dumps(payload))
|
|
385
|
+
")
|
|
386
|
+
|
|
387
|
+
if echo "$PAYLOAD" | gh api "repos/${OWNER}/${REPO}/branches/${branch}/protection" \
|
|
388
|
+
--method PUT --input - >/dev/null 2>&1; then
|
|
389
|
+
ok "${branch}: protection configured (${REVIEWERS} reviewer(s), checks: ${CONTEXTS})"
|
|
390
|
+
else
|
|
391
|
+
fail "${branch}: failed to configure protection"
|
|
392
|
+
info "You may need admin access or a GitHub token with 'repo' scope"
|
|
393
|
+
fi
|
|
394
|
+
done
|
|
395
|
+
fi
|
|
396
|
+
|
|
397
|
+
# ── 8. Summary ────────────────────────────────────────────────────────────────
|
|
398
|
+
sep "Summary"
|
|
399
|
+
|
|
400
|
+
TOTAL_MISSING="${#MISSING_SECRETS[@]}"
|
|
401
|
+
TOTAL_UNPROTECTED="${#BRANCHES_NEEDING_PROTECTION[@]}"
|
|
402
|
+
|
|
403
|
+
if [ "$TOTAL_MISSING" -eq 0 ] && [ "$TOTAL_UNPROTECTED" -eq 0 ]; then
|
|
404
|
+
ok "GitHub repo is fully configured for WP Engine CI/CD"
|
|
405
|
+
ok "Secrets: all set | Branch protection: all configured"
|
|
406
|
+
else
|
|
407
|
+
[ "$TOTAL_MISSING" -gt 0 ] && warn "Secrets missing: $TOTAL_MISSING (run --set-secrets)"
|
|
408
|
+
[ "$TOTAL_UNPROTECTED" -gt 0 ] && warn "Branches unprotected: ${BRANCHES_NEEDING_PROTECTION[*]} (run --set-protection)"
|
|
409
|
+
echo ""
|
|
410
|
+
info "Re-run: bash ${0} --set-all"
|
|
411
|
+
fi
|
|
412
|
+
|
|
413
|
+
echo ""
|
|
414
|
+
info "GitHub Actions: https://github.com/${OWNER}/${REPO}/actions"
|
|
415
|
+
info "Secrets: https://github.com/${OWNER}/${REPO}/settings/secrets/actions"
|
|
416
|
+
info "Branch rules: https://github.com/${OWNER}/${REPO}/settings/branches"
|
|
417
|
+
echo ""
|