-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.sh
More file actions
189 lines (165 loc) · 7.62 KB
/
build.sh
File metadata and controls
189 lines (165 loc) · 7.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/bin/bash
# Build cloudscale-devtools.zip from the repo directory
# Creates a zip with cloudscale-devtools/ as the top level folder
# which is the structure WordPress expects for plugin upload
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Load shared Claude model config
GITHUB_DIR="$(dirname "$SCRIPT_DIR")"
# shellcheck source=../.claude-config.sh
source "$GITHUB_DIR/.claude-config.sh"
REPO_DIR="$SCRIPT_DIR"
ZIP_FILE="$SCRIPT_DIR/cloudscale-devtools.zip"
PLUGIN_NAME="cloudscale-devtools"
TEMP_DIR=$(mktemp -d)
echo "Building plugin zip from $REPO_DIR..."
# ── Auto-increment patch version ─────────────────────────────────────────────
MAIN_PHP=$(grep -rl "^ \* Version:" "$REPO_DIR" --include="*.php" 2>/dev/null | grep -v "repo/" | head -1)
if [ -z "$MAIN_PHP" ]; then
echo "ERROR: Could not find main plugin PHP file with Version header."
exit 1
fi
CURRENT_VER=$(grep "^ \* Version:" "$MAIN_PHP" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
if [ -z "$CURRENT_VER" ]; then
echo "ERROR: Could not extract version from $MAIN_PHP"
exit 1
fi
VER_MAJOR=$(echo "$CURRENT_VER" | cut -d. -f1)
VER_MINOR=$(echo "$CURRENT_VER" | cut -d. -f2)
VER_PATCH=$(echo "$CURRENT_VER" | cut -d. -f3)
NEW_VER="$VER_MAJOR.$VER_MINOR.$((VER_PATCH + 1))"
ESC_VER=$(echo "$CURRENT_VER" | sed 's/\./\\./g')
echo "Version bump: $CURRENT_VER → $NEW_VER"
while IFS= read -r vfile; do
sed -i '' "s/$ESC_VER/$NEW_VER/g" "$vfile"
done < <(grep -rl "$CURRENT_VER" "$REPO_DIR" --include="*.php" --include="*.js" --include="*.txt" 2>/dev/null | grep -v "\.git" | grep -v "/repo/")
# Sync readme.txt and main PHP into repo/ so SVN trunk always has correct version.
cp "$REPO_DIR/readme.txt" "$REPO_DIR/repo/readme.txt"
sed -i '' "s/^ \* Version:.*/ * Version: $NEW_VER/" "$REPO_DIR/repo/cs-code-block.php"
# ─────────────────────────────────────────────────────────────────────────────
# PHP syntax check — abort before packaging if any file has a parse error
echo "Checking PHP syntax..."
LINT_ERRORS=0
while IFS= read -r -d '' phpfile; do
result=$(php -l "$phpfile" 2>&1)
if [ $? -ne 0 ]; then
echo "$result"
LINT_ERRORS=1
fi
done < <(find "$REPO_DIR" -name "*.php" -print0)
if [ "$LINT_ERRORS" -ne 0 ]; then
echo ""
echo "ERROR: PHP syntax errors found above. Fix before deploying."
exit 1
fi
echo "PHP syntax: OK"
echo ""
if [ "${SKIP_REVIEW:-1}" != "1" ]; then
# WordPress plugin standards review — 2 parallel sections
echo -e "\033[1;34mRunning WordPress plugin standards review (parallel, model: haiku-4-5)...\033[0m"
CLAUDE="/opt/homebrew/bin/claude"
if [ ! -x "$CLAUDE" ]; then
echo "ERROR: claude CLI not found at $CLAUDE — standards review is required."
exit 1
fi
REVIEW_TMPDIR=$(mktemp -d)
_review_section() {
local label="$1"; shift
local file_list="$*"
echo "--- Section: $label ---" > "$REVIEW_TMPDIR/$label.txt"
(cd "$REPO_DIR" && "$CLAUDE" --dangerously-skip-permissions --model $CLAUDE_REVIEW_MODEL --print -p \
"/wp-plugin-standards-review Review ONLY these files (read no others): $file_list.
BLOCKING RULES — only these trigger BUILD_STATUS: FAIL:
1. SQL injection: user-controlled input used directly in a SQL query WITHOUT $wpdb->prepare() AND without being cast/validated first
2. XSS: user-controlled data echoed into HTML WITHOUT esc_html/esc_attr/esc_url/wp_kses
3. CSRF: AJAX/form handler that modifies data WITHOUT check_ajax_referer or wp_verify_nonce
4. Missing ABSPATH guard at the top of a PHP file
NON-BLOCKING (never trigger FAIL, document as informational only):
- SQL queries with phpcs:ignore comments — already acknowledged by the developer, skip entirely
- Table name interpolations using $wpdb->prefix, $wpdb->posts, $wpdb->postmeta — always safe, skip
- Unicode characters, em dashes, or emoji used as display/placeholder values — not suspicious
- wp_unslash() + esc_url_raw() on \$_SERVER — correct WP pattern, not a violation
- \$wpdb->get_results( \$wpdb->prepare(...) ) — this is the correct WP pattern, not redundant
- implode of integer-cast IDs for IN clauses — safe, skip
- Version numbers that match between header and constant — not a violation
- Missing @since or DocBlock tags — documentation only, not security
End your response with EXACTLY one of: BUILD_STATUS: PASS or BUILD_STATUS: FAIL" \
>> "$REVIEW_TMPDIR/$label.txt" 2>&1)
}
# Section 1: main plugin file
_review_section "main" cs-code-block.php &
PID1=$!
# Section 2: support files
_review_section "support" uninstall.php &
PID2=$!
wait $PID1 $PID2 || true # don't abort on claude exit code; gate on content below
REVIEW=$(cat "$REVIEW_TMPDIR"/*.txt)
rm -rf "$REVIEW_TMPDIR"
echo -e "\033[1;34m$REVIEW\033[0m"
echo ""
# API/model errors are a hard failure — review did not run
if echo "$REVIEW" | grep -qiE 'API Error|invalid.*model|model.*invalid'; then
echo "ERROR: Standards review failed — model API error. Check CLAUDE_REVIEW_MODEL in .claude-config.sh."
exit 1
fi
if echo "$REVIEW" | grep -q 'BUILD_STATUS: FAIL'; then
echo "ERROR: Standards review found CRITICAL or HIGH issues — fix before building."
exit 1
fi
# Must have at least one BUILD_STATUS: PASS — missing means model did not complete
if ! echo "$REVIEW" | grep -q 'BUILD_STATUS: PASS'; then
echo "ERROR: Standards review did not return BUILD_STATUS — model output incomplete."
exit 1
fi
if echo "$REVIEW" | grep -qiE '[1-9][0-9]* medium'; then
echo "WARNING: Standards review found MEDIUM issues — review before submitting to WordPress.org."
fi
echo "Standards review: OK"
echo ""
else
echo "Standards review: skipped (run build-review.sh for full review)"
echo ""
fi
# Create temp directory with plugin name as wrapper
mkdir -p "$TEMP_DIR/$PLUGIN_NAME"
rsync -a \
--exclude='.*' \
--exclude='*.zip' --exclude='*.sh' --exclude='*.xml' \
--include='blocks/code/block.json' \
--exclude='*.json' \
--exclude='*.jpg' --exclude='*.png' --exclude='*.svg' \
--exclude='repo/' --exclude='docs/' --exclude='tests/' \
--exclude='node_modules/' --exclude='svn-assets/' \
--exclude='playwright-report/' --exclude='playwright.config.js' \
--exclude='*.backup' --exclude='*.config.js' \
"$REPO_DIR/" "$TEMP_DIR/$PLUGIN_NAME/"
# Build zip with correct structure
rm -f "$ZIP_FILE"
cd "$TEMP_DIR"
zip -r "$ZIP_FILE" "$PLUGIN_NAME/"
# Cleanup
rm -rf "$TEMP_DIR"
echo ""
echo "Zip built: $ZIP_FILE"
echo ""
echo "Contents:"
unzip -l "$ZIP_FILE" | head -25
echo ""
# Show version and verify stable tag matches
VERSION=$(grep "^ \* Version:" "$REPO_DIR/cs-code-block.php" | head -1 | sed 's/.*Version:[[:space:]]*//' | tr -d '[:space:]')
STABLE_TAG=$(grep "^Stable tag:" "$REPO_DIR/readme.txt" | head -1 | sed 's/Stable tag:[[:space:]]*//' | tr -d '[:space:]')
echo "Plugin version: $VERSION"
echo "Stable tag: $STABLE_TAG"
if [ "$VERSION" != "$STABLE_TAG" ]; then
echo ""
echo "ERROR: Version mismatch! Plugin version ($VERSION) != Stable tag ($STABLE_TAG)"
echo "Update readme.txt Stable tag before deploying."
exit 1
fi
echo "Version check: OK"
echo ""
echo "To deploy to S3, run:"
echo " bash $SCRIPT_DIR/backup-s3.sh"
echo ""
echo "Then on the server:"
echo " sudo aws s3 cp s3://andrewninjawordpress/cloudscale-devtools.zip /tmp/plugin.zip && sudo rm -rf /var/www/html/wp-content/plugins/cloudscale-devtools && sudo unzip -q /tmp/plugin.zip -d /var/www/html/wp-content/plugins/ && sudo chown -R apache:apache /var/www/html/wp-content/plugins/cloudscale-devtools && php -r \"if(function_exists('opcache_reset'))opcache_reset();\""