fixed form element #35
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release Widget | |
| on: | |
| push: | |
| tags: | |
| - 'v*' # Trigger on version tags (e.g., v1.4.0) | |
| permissions: | |
| contents: write # Required to create GitHub releases | |
| id-token: write # Required for Cloudflare authentication (if using OIDC) | |
| jobs: | |
| build-and-release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm install | |
| # Note: Since this project has no dependencies, npm install just creates/updates package-lock.json | |
| - name: Install Wrangler CLI | |
| run: npm install -g wrangler | |
| - name: Verify Wrangler and Cloudflare credentials | |
| run: | | |
| echo "=== Verifying Wrangler Installation ===" | |
| wrangler --version | |
| echo "=== Verifying Cloudflare Credentials ===" | |
| if [ -z "$CLOUDFLARE_API_TOKEN" ]; then | |
| echo "❌ CLOUDFLARE_API_TOKEN is not set" | |
| exit 1 | |
| fi | |
| if [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then | |
| echo "❌ CLOUDFLARE_ACCOUNT_ID is not set" | |
| exit 1 | |
| fi | |
| if [ -z "$CLOUDFLARE_R2_BUCKET_NAME" ]; then | |
| echo "❌ CLOUDFLARE_R2_BUCKET_NAME is not set" | |
| exit 1 | |
| fi | |
| echo "✅ All required secrets are set" | |
| echo "Account ID: $CLOUDFLARE_ACCOUNT_ID" | |
| echo "Bucket: $CLOUDFLARE_R2_BUCKET_NAME" | |
| # Note: Authentication will be tested during the actual upload | |
| # If credentials are wrong, the upload step will fail with a clear error | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| CLOUDFLARE_R2_BUCKET_NAME: ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} | |
| - name: Extract version from tag | |
| id: get_version | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version extracted: $VERSION" | |
| - name: Build widget | |
| run: | | |
| echo "Building widget from Git tag..." | |
| npm run build:tag | |
| echo "Build completed. Files in dist/:" | |
| ls -lh dist/ || echo "dist/ directory not found" | |
| - name: Verify build output | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| echo "=== Checking widget files ===" | |
| for file in \ | |
| "dist/widget-${VERSION}.js" \ | |
| "dist/widget-${VERSION}.min.js" \ | |
| "dist/widget-${VERSION}.css" \ | |
| "dist/widget-${VERSION}.min.css" \ | |
| "dist/widget.js" \ | |
| "dist/widget.min.js" \ | |
| "dist/widget.css" \ | |
| "dist/widget.min.css" | |
| do | |
| if [ ! -f "$file" ]; then | |
| echo "❌ Error: $file not found" | |
| exit 1 | |
| fi | |
| echo "✓ $file" | |
| done | |
| echo "" | |
| echo "=== Checking ezform files ===" | |
| for file in \ | |
| "dist/ezform-${VERSION}.js" \ | |
| "dist/ezform-${VERSION}.min.js" \ | |
| "dist/ezform.js" \ | |
| "dist/ezform.min.js" | |
| do | |
| if [ ! -f "$file" ]; then | |
| echo "❌ Error: $file not found" | |
| exit 1 | |
| fi | |
| echo "✓ $file" | |
| done | |
| echo "" | |
| echo "✅ Build verification passed" | |
| echo "" | |
| echo "=== File sizes ===" | |
| ls -lh dist/ | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: | | |
| dist/widget-${{ steps.get_version.outputs.version }}.js | |
| dist/widget-${{ steps.get_version.outputs.version }}.min.js | |
| dist/widget-${{ steps.get_version.outputs.version }}.css | |
| dist/widget-${{ steps.get_version.outputs.version }}.min.css | |
| dist/widget.js | |
| dist/widget.min.js | |
| dist/widget.css | |
| dist/widget.min.css | |
| dist/ezform-${{ steps.get_version.outputs.version }}.js | |
| dist/ezform-${{ steps.get_version.outputs.version }}.min.js | |
| dist/ezform.js | |
| dist/ezform.min.js | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload to Cloudflare R2 (Versioned Files) | |
| run: | | |
| set -e # Exit on error | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| BUCKET="${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}" | |
| echo "=== Upload Configuration ===" | |
| echo "Version: $VERSION" | |
| echo "Bucket: $BUCKET" | |
| echo "Account ID: $CLOUDFLARE_ACCOUNT_ID" | |
| echo "API Token: ${CLOUDFLARE_API_TOKEN:0:10}..." # Show first 10 chars only | |
| if [ -z "$BUCKET" ]; then | |
| echo "❌ Error: CLOUDFLARE_R2_BUCKET_NAME secret is not set" | |
| exit 1 | |
| fi | |
| if [ -z "$CLOUDFLARE_API_TOKEN" ]; then | |
| echo "❌ Error: CLOUDFLARE_API_TOKEN secret is not set" | |
| exit 1 | |
| fi | |
| if [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then | |
| echo "❌ Error: CLOUDFLARE_ACCOUNT_ID secret is not set" | |
| exit 1 | |
| fi | |
| # Verify files exist before uploading | |
| if [ ! -f "dist/widget-${VERSION}.js" ]; then | |
| echo "❌ Error: dist/widget-${VERSION}.js not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/widget-${VERSION}.css" ]; then | |
| echo "❌ Error: dist/widget-${VERSION}.css not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/ezform-${VERSION}.js" ]; then | |
| echo "❌ Error: dist/ezform-${VERSION}.js not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/widget-${VERSION}.min.js" ]; then | |
| echo "❌ Error: dist/widget-${VERSION}.min.js not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/ezform-${VERSION}.min.js" ]; then | |
| echo "❌ Error: dist/ezform-${VERSION}.min.js not found" | |
| exit 1 | |
| fi | |
| echo "=== Uploading versioned files ===" | |
| # Upload versioned files with cache headers (--remote flag required!) | |
| echo "Uploading widget-${VERSION}.js..." | |
| wrangler r2 object put ${BUCKET}/widget-${VERSION}.js \ | |
| --file=dist/widget-${VERSION}.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=31536000, immutable" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget-${VERSION}.js" | |
| exit 1 | |
| } | |
| echo "Uploading widget-${VERSION}.css..." | |
| wrangler r2 object put ${BUCKET}/widget-${VERSION}.css \ | |
| --file=dist/widget-${VERSION}.css \ | |
| --content-type="text/css" \ | |
| --cache-control="public, max-age=31536000, immutable" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget-${VERSION}.css" | |
| exit 1 | |
| } | |
| echo "Uploading ezform-${VERSION}.js..." | |
| wrangler r2 object put ${BUCKET}/ezform-${VERSION}.js \ | |
| --file=dist/ezform-${VERSION}.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=31536000, immutable" \ | |
| --remote || { | |
| echo "❌ Failed to upload ezform-${VERSION}.js" | |
| exit 1 | |
| } | |
| # Upload minified versioned files | |
| echo "Uploading widget-${VERSION}.min.js..." | |
| wrangler r2 object put ${BUCKET}/widget-${VERSION}.min.js \ | |
| --file=dist/widget-${VERSION}.min.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=31536000, immutable" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget-${VERSION}.min.js" | |
| exit 1 | |
| } | |
| echo "Uploading widget-${VERSION}.min.css..." | |
| wrangler r2 object put ${BUCKET}/widget-${VERSION}.min.css \ | |
| --file=dist/widget-${VERSION}.min.css \ | |
| --content-type="text/css" \ | |
| --cache-control="public, max-age=31536000, immutable" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget-${VERSION}.min.css" | |
| exit 1 | |
| } | |
| echo "Uploading ezform-${VERSION}.min.js..." | |
| wrangler r2 object put ${BUCKET}/ezform-${VERSION}.min.js \ | |
| --file=dist/ezform-${VERSION}.min.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=31536000, immutable" \ | |
| --remote || { | |
| echo "❌ Failed to upload ezform-${VERSION}.min.js" | |
| exit 1 | |
| } | |
| echo "✅ Uploaded versioned files for v${VERSION}" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| - name: Upload to Cloudflare R2 (Latest Files) | |
| run: | | |
| set -e # Exit on error | |
| BUCKET="${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}" | |
| echo "=== Uploading latest files ===" | |
| if [ -z "$BUCKET" ]; then | |
| echo "❌ Error: CLOUDFLARE_R2_BUCKET_NAME secret is not set" | |
| exit 1 | |
| fi | |
| # Verify files exist before uploading | |
| if [ ! -f "dist/widget.js" ]; then | |
| echo "❌ Error: dist/widget.js not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/widget.css" ]; then | |
| echo "❌ Error: dist/widget.css not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/ezform.js" ]; then | |
| echo "❌ Error: dist/ezform.js not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/widget.min.js" ]; then | |
| echo "❌ Error: dist/widget.min.js not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/ezform.min.js" ]; then | |
| echo "❌ Error: dist/ezform.min.js not found" | |
| exit 1 | |
| fi | |
| # Upload latest files with shorter cache (--remote flag required!) | |
| echo "Uploading widget.js..." | |
| wrangler r2 object put ${BUCKET}/widget.js \ | |
| --file=dist/widget.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=3600" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget.js" | |
| exit 1 | |
| } | |
| echo "Uploading widget.css..." | |
| wrangler r2 object put ${BUCKET}/widget.css \ | |
| --file=dist/widget.css \ | |
| --content-type="text/css" \ | |
| --cache-control="public, max-age=3600" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget.css" | |
| exit 1 | |
| } | |
| echo "Uploading ezform.js..." | |
| wrangler r2 object put ${BUCKET}/ezform.js \ | |
| --file=dist/ezform.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=3600" \ | |
| --remote || { | |
| echo "❌ Failed to upload ezform.js" | |
| exit 1 | |
| } | |
| # Upload minified latest files | |
| echo "Uploading widget.min.js..." | |
| wrangler r2 object put ${BUCKET}/widget.min.js \ | |
| --file=dist/widget.min.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=3600" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget.min.js" | |
| exit 1 | |
| } | |
| echo "Uploading widget.min.css..." | |
| wrangler r2 object put ${BUCKET}/widget.min.css \ | |
| --file=dist/widget.min.css \ | |
| --content-type="text/css" \ | |
| --cache-control="public, max-age=3600" \ | |
| --remote || { | |
| echo "❌ Failed to upload widget.min.css" | |
| exit 1 | |
| } | |
| echo "Uploading ezform.min.js..." | |
| wrangler r2 object put ${BUCKET}/ezform.min.js \ | |
| --file=dist/ezform.min.js \ | |
| --content-type="application/javascript" \ | |
| --cache-control="public, max-age=3600" \ | |
| --remote || { | |
| echo "❌ Failed to upload ezform.min.js" | |
| exit 1 | |
| } | |
| echo "✅ Uploaded latest files" | |
| # Note: Verification skipped - upload success is confirmed by "Upload complete" message | |
| # Files may take a moment to propagate, but upload was successful | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| - name: Purge Cloudflare Cache | |
| run: | | |
| set -e | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| ZONE_ID="${CLOUDFLARE_ZONE_ID}" | |
| CUSTOM_DOMAIN="${CLOUDFLARE_CUSTOM_DOMAIN:-cdn.ezcontactform.com}" | |
| # Skip if ZONE_ID is not set | |
| if [ -z "$ZONE_ID" ]; then | |
| echo "⚠️ CLOUDFLARE_ZONE_ID not set, skipping cache purge" | |
| echo "To enable cache purging, add CLOUDFLARE_ZONE_ID to your repository secrets" | |
| exit 0 | |
| fi | |
| echo "=== Purging Cloudflare Cache ===" | |
| echo "Zone ID: ${ZONE_ID:0:10}..." | |
| echo "Custom Domain: ${CUSTOM_DOMAIN}" | |
| # Build the list of files to purge as JSON | |
| FILES_TO_PURGE='{"files":["https://'"${CUSTOM_DOMAIN}"'/widget-'"${VERSION}"'.js","https://'"${CUSTOM_DOMAIN}"'/widget-'"${VERSION}"'.min.js","https://'"${CUSTOM_DOMAIN}"'/widget-'"${VERSION}"'.css","https://'"${CUSTOM_DOMAIN}"'/widget-'"${VERSION}"'.min.css","https://'"${CUSTOM_DOMAIN}"'/widget.js","https://'"${CUSTOM_DOMAIN}"'/widget.min.js","https://'"${CUSTOM_DOMAIN}"'/widget.css","https://'"${CUSTOM_DOMAIN}"'/widget.min.css","https://'"${CUSTOM_DOMAIN}"'/ezform-'"${VERSION}"'.js","https://'"${CUSTOM_DOMAIN}"'/ezform-'"${VERSION}"'.min.js","https://'"${CUSTOM_DOMAIN}"'/ezform.js","https://'"${CUSTOM_DOMAIN}"'/ezform.min.js"]}' | |
| echo "Files to purge:" | |
| echo "$FILES_TO_PURGE" | jq -r '.files[]' 2>/dev/null || echo "$FILES_TO_PURGE" | |
| # Make the API call | |
| RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \ | |
| -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ | |
| -H "Content-Type: application/json" \ | |
| --data "$FILES_TO_PURGE") | |
| # Check response | |
| SUCCESS=$(echo "$RESPONSE" | jq -r '.success' 2>/dev/null || echo "unknown") | |
| if [ "$SUCCESS" = "true" ]; then | |
| echo "✅ Cache purge successful" | |
| else | |
| echo "⚠️ Cache purge response:" | |
| echo "$RESPONSE" | jq . 2>/dev/null || echo "$RESPONSE" | |
| # Don't fail the build on cache purge issues | |
| fi | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} | |
| CLOUDFLARE_CUSTOM_DOMAIN: ${{ vars.CLOUDFLARE_CUSTOM_DOMAIN }} | |
| - name: Build Summary | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| echo "## Build Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version:** ${VERSION}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Widget Files" >> $GITHUB_STEP_SUMMARY | |
| echo "| File | Size |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| widget-${VERSION}.js | $(du -h dist/widget-${VERSION}.js | cut -f1) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| widget-${VERSION}.min.js | $(du -h dist/widget-${VERSION}.min.js | cut -f1) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| widget-${VERSION}.css | $(du -h dist/widget-${VERSION}.css | cut -f1) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| widget-${VERSION}.min.css | $(du -h dist/widget-${VERSION}.min.css | cut -f1) |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### EZForm Files" >> $GITHUB_STEP_SUMMARY | |
| echo "| File | Size |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| ezform-${VERSION}.js | $(du -h dist/ezform-${VERSION}.js | cut -f1) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| ezform-${VERSION}.min.js | $(du -h dist/ezform-${VERSION}.min.js | cut -f1) |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- **R2 Upload:** ✅ Completed" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Cache Purge:** ✅ Completed (if CLOUDFLARE_ZONE_ID is set)" >> $GITHUB_STEP_SUMMARY | |