|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# Composer Package Updater Script |
| 4 | +# Usage: ./update_composer_package.sh <version> <release_url> [package_name] [description] |
| 5 | +# e.g. .github/scripts/update_composer_package.sh "0.0.5" "https://github.com/wpengine/hwptoolkit/releases/download/%40wpengine%2Fhwp-previews-wordpress-plugin-0.0.5/hwp-previews.zip" "wpengine/previews" "A WordPress plugin for headless previews." |
| 6 | + |
| 7 | + |
| 8 | +set -e |
| 9 | + |
| 10 | +# Function to display usage |
| 11 | +usage() { |
| 12 | + echo "Usage: $0 <version> <release_url> [package_name] [description]" |
| 13 | + echo "" |
| 14 | + echo "Arguments:" |
| 15 | + echo " version - Package version (e.g., 0.0.5)" |
| 16 | + echo " release_url - Download URL for the package zip file" |
| 17 | + echo " package_name - Optional: Package name (auto-detected from URL if not provided)" |
| 18 | + echo " description - Optional: Package description (uses generic default if not provided)" |
| 19 | + echo "" |
| 20 | + echo "Examples:" |
| 21 | + echo " $0 '0.0.2' 'https://github.com/wpengine/hwptoolkit/releases/download/%40wpengine%2Fwpgraphql-webhooks-wordpress-plugin-0.0.2/wp-graphql-webhooks.zip'" |
| 22 | + echo "" |
| 23 | + echo " With custom package name and description:" |
| 24 | + echo " $0 '0.0.5' 'https://example.com/plugin.zip' 'wpengine/my-plugin' 'My custom plugin description'" |
| 25 | + echo "" |
| 26 | + echo "Note: Updates plugins/package.json file" |
| 27 | + exit 1 |
| 28 | +} |
| 29 | + |
| 30 | +# Check if minimum arguments provided |
| 31 | +if [ "$#" -lt 2 ]; then |
| 32 | + echo "Error: Missing required arguments" |
| 33 | + usage |
| 34 | +fi |
| 35 | + |
| 36 | +# Arguments |
| 37 | +VERSION="$1" |
| 38 | +RELEASE_URL="$2" |
| 39 | +PACKAGE_NAME="$3" |
| 40 | +DESCRIPTION="$4" |
| 41 | +COMPOSER_FILE="plugins/package.json" |
| 42 | + |
| 43 | +# Function to extract package name from release URL |
| 44 | +extract_package_name() { |
| 45 | + local url="$1" |
| 46 | + |
| 47 | + # Extract from URL patterns like: |
| 48 | + # https://github.com/wpengine/hwptoolkit/releases/download/%40wpengine%2F{PLUGIN}-wordpress-plugin-{VERSION}/{ZIP_NAME}.zip |
| 49 | + |
| 50 | + # Method 1: Extract from the release tag (between %40wpengine%2F and -wordpress-plugin) |
| 51 | + if [[ "$url" =~ %40wpengine%2F([^-]+)-wordpress-plugin ]]; then |
| 52 | + local plugin_name="${BASH_REMATCH[1]}" |
| 53 | + echo "wpengine/$plugin_name" |
| 54 | + return |
| 55 | + fi |
| 56 | + |
| 57 | + # Method 2: Extract from @wpengine/ format |
| 58 | + if [[ "$url" =~ @wpengine/([^-]+)-wordpress-plugin ]]; then |
| 59 | + local plugin_name="${BASH_REMATCH[1]}" |
| 60 | + echo "wpengine/$plugin_name" |
| 61 | + return |
| 62 | + fi |
| 63 | + |
| 64 | + # Method 3: Extract from the zip filename at the end of URL |
| 65 | + local filename=$(basename "$url" .zip) |
| 66 | + if [[ "$filename" =~ ^(.+)$ ]]; then |
| 67 | + # Clean up common prefixes but keep the core name |
| 68 | + local clean_name="$filename" |
| 69 | + clean_name=$(echo "$clean_name" | sed 's/^hwp-//') |
| 70 | + clean_name=$(echo "$clean_name" | sed 's/^wp-//') |
| 71 | + clean_name=$(echo "$clean_name" | sed 's/^wpengine-//') |
| 72 | + echo "wpengine/$clean_name" |
| 73 | + return |
| 74 | + fi |
| 75 | + |
| 76 | + # Method 4: Try to extract from middle part of URL path |
| 77 | + if [[ "$url" =~ /([^/]+)\.zip$ ]]; then |
| 78 | + local zip_name="${BASH_REMATCH[1]}" |
| 79 | + # Remove common prefixes |
| 80 | + zip_name=$(echo "$zip_name" | sed 's/^hwp-//') |
| 81 | + zip_name=$(echo "$zip_name" | sed 's/^wp-//') |
| 82 | + zip_name=$(echo "$zip_name" | sed 's/^wpengine-//') |
| 83 | + echo "wpengine/$zip_name" |
| 84 | + return |
| 85 | + fi |
| 86 | + |
| 87 | + # Fallback |
| 88 | + echo "wpengine/unknown-plugin" |
| 89 | +} |
| 90 | + |
| 91 | +# Function to generate generic description |
| 92 | +generate_description() { |
| 93 | + local package_name="$1" |
| 94 | + echo "A WordPress plugin for headless functionality." |
| 95 | +} |
| 96 | + |
| 97 | +# Auto-detect package name if not provided |
| 98 | +if [ -z "$PACKAGE_NAME" ]; then |
| 99 | + PACKAGE_NAME=$(extract_package_name "$RELEASE_URL") |
| 100 | + echo "Auto-detected package name: $PACKAGE_NAME" |
| 101 | +fi |
| 102 | + |
| 103 | +# Auto-generate description if not provided |
| 104 | +if [ -z "$DESCRIPTION" ]; then |
| 105 | + DESCRIPTION=$(generate_description "$PACKAGE_NAME") |
| 106 | + echo "Using description: $DESCRIPTION" |
| 107 | +fi |
| 108 | + |
| 109 | +echo "Updating composer package:" |
| 110 | +echo " Package: $PACKAGE_NAME" |
| 111 | +echo " Version: $VERSION" |
| 112 | +echo " File: $COMPOSER_FILE" |
| 113 | +echo " URL: $RELEASE_URL" |
| 114 | +echo " Description: $DESCRIPTION" |
| 115 | + |
| 116 | +# Create plugins directory if it doesn't exist |
| 117 | +mkdir -p "$(dirname "$COMPOSER_FILE")" |
| 118 | + |
| 119 | +# Create initial package.json if it doesn't exist |
| 120 | +if [ ! -f "$COMPOSER_FILE" ]; then |
| 121 | + echo "Creating initial $COMPOSER_FILE..." |
| 122 | + cat > "$COMPOSER_FILE" << 'EOF' |
| 123 | +{ |
| 124 | + "packages": {} |
| 125 | +} |
| 126 | +EOF |
| 127 | +fi |
| 128 | + |
| 129 | +# Validate JSON structure |
| 130 | +if ! python3 -m json.tool "$COMPOSER_FILE" >/dev/null 2>&1; then |
| 131 | + echo "Error: '$COMPOSER_FILE' is not valid JSON" |
| 132 | + exit 1 |
| 133 | +fi |
| 134 | + |
| 135 | +# Function to update package using jq |
| 136 | +update_package_jq() { |
| 137 | + local package_name="$1" |
| 138 | + local version="$2" |
| 139 | + local release_url="$3" |
| 140 | + local description="$4" |
| 141 | + local composer_file="$5" |
| 142 | + |
| 143 | + # Create the new package version object and sort versions in descending order |
| 144 | + jq --arg pkg "$package_name" \ |
| 145 | + --arg ver "$version" \ |
| 146 | + --arg url "$release_url" \ |
| 147 | + --arg desc "$description" \ |
| 148 | + ' |
| 149 | + # Ensure the packages object exists |
| 150 | + if .packages == null then .packages = {} else . end | |
| 151 | +
|
| 152 | + # Ensure the package namespace exists |
| 153 | + if .packages[$pkg] == null then .packages[$pkg] = {} else . end | |
| 154 | +
|
| 155 | + # Add/update the version |
| 156 | + .packages[$pkg][$ver] = { |
| 157 | + "name": $pkg, |
| 158 | + "version": $ver, |
| 159 | + "type": "wordpress-plugin", |
| 160 | + "description": $desc, |
| 161 | + "homepage": "https://github.com/wpengine/hwptoolkit", |
| 162 | + "license": "GPL-2.0", |
| 163 | + "authors": [ |
| 164 | + { |
| 165 | + "name": "WP Engine Headless OSS Development Team", |
| 166 | + |
| 167 | + "homepage": "https://wpengine.com/" |
| 168 | + } |
| 169 | + ], |
| 170 | + "support": { |
| 171 | + "issues": "https://github.com/wpengine/hwptoolkit/issues", |
| 172 | + |
| 173 | + }, |
| 174 | + "dist": { |
| 175 | + "url": $url, |
| 176 | + "type": "zip" |
| 177 | + }, |
| 178 | + "require": { |
| 179 | + "composer/installers": "~1.0 || ~2.0" |
| 180 | + } |
| 181 | + } | |
| 182 | +
|
| 183 | + # Sort versions in descending order (newest first) |
| 184 | + .packages[$pkg] = (.packages[$pkg] | to_entries | sort_by(.key | [splits("[.]")] | map(tonumber)) | reverse | from_entries) |
| 185 | + ' "$composer_file" > "${composer_file}.tmp" && mv "${composer_file}.tmp" "$composer_file" |
| 186 | +} |
| 187 | + |
| 188 | +# Function to update package using Python (fallback) |
| 189 | +update_package_python() { |
| 190 | + local package_name="$1" |
| 191 | + local version="$2" |
| 192 | + local release_url="$3" |
| 193 | + local description="$4" |
| 194 | + local composer_file="$5" |
| 195 | + |
| 196 | + python3 << EOF |
| 197 | +import json |
| 198 | +from packaging import version as pkg_version |
| 199 | +
|
| 200 | +# Read the composer file |
| 201 | +with open('$composer_file', 'r') as f: |
| 202 | + data = json.load(f) |
| 203 | +
|
| 204 | +# Ensure packages object exists |
| 205 | +if 'packages' not in data: |
| 206 | + data['packages'] = {} |
| 207 | +
|
| 208 | +# Ensure package namespace exists |
| 209 | +if '$package_name' not in data['packages']: |
| 210 | + data['packages']['$package_name'] = {} |
| 211 | +
|
| 212 | +# Create the new version entry |
| 213 | +data['packages']['$package_name']['$version'] = { |
| 214 | + "name": "$package_name", |
| 215 | + "version": "$version", |
| 216 | + "type": "wordpress-plugin", |
| 217 | + "description": "$description", |
| 218 | + "homepage": "https://github.com/wpengine/hwptoolkit", |
| 219 | + "license": "GPL-2.0", |
| 220 | + "authors": [ |
| 221 | + { |
| 222 | + "name": "WP Engine Headless OSS Development Team", |
| 223 | + |
| 224 | + "homepage": "https://wpengine.com/" |
| 225 | + } |
| 226 | + ], |
| 227 | + "support": { |
| 228 | + "issues": "https://github.com/wpengine/hwptoolkit/issues", |
| 229 | + |
| 230 | + }, |
| 231 | + "dist": { |
| 232 | + "url": "$release_url", |
| 233 | + "type": "zip" |
| 234 | + }, |
| 235 | + "require": { |
| 236 | + "composer/installers": "~1.0 || ~2.0" |
| 237 | + } |
| 238 | +} |
| 239 | +
|
| 240 | +# Sort versions in descending order (newest first) |
| 241 | +try: |
| 242 | + package_versions = data['packages']['$package_name'] |
| 243 | + sorted_versions = dict(sorted( |
| 244 | + package_versions.items(), |
| 245 | + key=lambda x: pkg_version.parse(x[0]), |
| 246 | + reverse=True |
| 247 | + )) |
| 248 | + data['packages']['$package_name'] = sorted_versions |
| 249 | +except Exception as e: |
| 250 | + # If sorting fails, continue with unsorted versions |
| 251 | + print(f"Warning: Could not sort versions: {e}") |
| 252 | +
|
| 253 | +# Write back to file with proper formatting |
| 254 | +with open('$composer_file', 'w') as f: |
| 255 | + json.dump(data, f, indent=4, separators=(',', ': ')) |
| 256 | +
|
| 257 | +print(f"Successfully updated {package_name} version {version}") |
| 258 | +EOF |
| 259 | +} |
| 260 | + |
| 261 | +# Update the package |
| 262 | +if command -v jq >/dev/null 2>&1; then |
| 263 | + echo "Using jq for JSON manipulation..." |
| 264 | + update_package_jq "$PACKAGE_NAME" "$VERSION" "$RELEASE_URL" "$DESCRIPTION" "$COMPOSER_FILE" |
| 265 | +else |
| 266 | + echo "jq not found, using Python fallback..." |
| 267 | + update_package_python "$PACKAGE_NAME" "$VERSION" "$RELEASE_URL" "$DESCRIPTION" "$COMPOSER_FILE" |
| 268 | +fi |
| 269 | + |
| 270 | +# Validate the updated JSON |
| 271 | +if ! python3 -m json.tool "$COMPOSER_FILE" >/dev/null 2>&1; then |
| 272 | + echo "Error: Updated JSON is invalid" |
| 273 | + exit 1 |
| 274 | +fi |
| 275 | + |
| 276 | +echo "✅ Successfully updated $PACKAGE_NAME to version $VERSION" |
| 277 | + |
| 278 | +# Show the updated section |
| 279 | +echo "" |
| 280 | +echo "Updated package entry:" |
| 281 | +if command -v jq >/dev/null 2>&1; then |
| 282 | + jq --arg pkg "$PACKAGE_NAME" --arg ver "$VERSION" '.packages[$pkg][$ver]' "$COMPOSER_FILE" |
| 283 | +else |
| 284 | + echo "Install jq to see formatted output, or check the file: $COMPOSER_FILE" |
| 285 | +fi |
| 286 | + |
| 287 | +# Optional: Show package summary |
| 288 | +echo "" |
| 289 | +echo "📦 Package Summary:" |
| 290 | +echo " Name: $PACKAGE_NAME" |
| 291 | +echo " Version: $VERSION" |
| 292 | +echo " Description: $DESCRIPTION" |
| 293 | +echo " Download URL: $RELEASE_URL" |
| 294 | +echo " File updated: $COMPOSER_FILE" |
| 295 | + |
| 296 | +# Check if this is a new package or version update |
| 297 | +if command -v jq >/dev/null 2>&1; then |
| 298 | + EXISTING_VERSIONS=$(jq -r --arg pkg "$PACKAGE_NAME" '.packages[$pkg] // {} | keys | length' "$COMPOSER_FILE") |
| 299 | + if [ "$EXISTING_VERSIONS" -gt 1 ]; then |
| 300 | + echo " Status: Updated existing package (now has $EXISTING_VERSIONS versions)" |
| 301 | + else |
| 302 | + echo " Status: Added new package" |
| 303 | + fi |
| 304 | +fi |
0 commit comments