From bbed41ca71f3e9d6595837db0049184b13982fe3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 31 Mar 2026 08:25:52 +0000 Subject: [PATCH 1/2] Add Google Analytics via deploy-time injection Adds a placeholder comment to src/index.html that the deploy workflow replaces with the GA4 gtag snippet at build time using the GA_MEASUREMENT_ID repository variable. If the variable is unset or fails format validation (^G-[A-Z0-9]+$), the placeholder is removed cleanly so the site deploys without errors or leftover comments. https://claude.ai/code/session_01YRP3nqtybUtdG2Jqs5tggo --- .github/workflows/deploy.yml | 37 ++++++++++++++++++++++++++++++++++++ src/index.html | 1 + 2 files changed, 38 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c1951e5..29d71e5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -75,6 +75,43 @@ jobs: - uses: actions/checkout@v4 - name: Setup Pages uses: actions/configure-pages@v4 + - name: Inject Google Analytics + env: + GA_ID: ${{ vars.GA_MEASUREMENT_ID }} + run: | + python3 - << 'EOF' + import os, re + + ga_id = os.environ.get('GA_ID', '').strip() + placeholder = '' + + with open('src/index.html', 'r') as f: + html = f.read() + + if re.match(r'^G-[A-Z0-9]+$', ga_id): + snippet = ( + '\n' + ' \n' + ' ' + ) + html = html.replace(placeholder, snippet) + print('Google Analytics injected:', ga_id) + else: + html = html.replace(placeholder, '') + if ga_id: + print('WARNING: GA_MEASUREMENT_ID "' + ga_id + '" is not a valid GA4 ID (expected G-XXXXXXXXXX). Skipping.') + else: + print('GA_MEASUREMENT_ID not set — skipping analytics injection.') + + with open('src/index.html', 'w') as f: + f.write(html) + EOF + - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: diff --git a/src/index.html b/src/index.html index 9d66b28..e6ccfcd 100644 --- a/src/index.html +++ b/src/index.html @@ -20,6 +20,7 @@ + From 44e4ed2c5fe1b879a54d26381b19173f6069873c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 31 Mar 2026 08:40:11 +0000 Subject: [PATCH 2/2] Fix Copilot review comments on GA injection step - Open index.html with explicit encoding='utf-8' (read + write) to handle non-ASCII characters deterministically across runner locales - Verify placeholder occurs exactly once before replacing; exit 1 if count != 1 so a missing/duplicate placeholder surfaces as a build failure rather than a silent no-op - Use re.sub with MULTILINE to strip the entire placeholder line (including indentation and newline) when skipping injection, leaving no blank or whitespace-only lines in the deployed HTML - Fix warning message to accurately describe the actual regex rule (any length G-[A-Z0-9]+) rather than implying a fixed 10-char format https://claude.ai/code/session_01YRP3nqtybUtdG2Jqs5tggo --- .github/workflows/deploy.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 29d71e5..f934e07 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -80,15 +80,19 @@ jobs: GA_ID: ${{ vars.GA_MEASUREMENT_ID }} run: | python3 - << 'EOF' - import os, re + import os, re, sys ga_id = os.environ.get('GA_ID', '').strip() placeholder = '' - with open('src/index.html', 'r') as f: + with open('src/index.html', 'r', encoding='utf-8') as f: html = f.read() if re.match(r'^G-[A-Z0-9]+$', ga_id): + count = html.count(placeholder) + if count != 1: + print(f'ERROR: Expected exactly 1 placeholder, found {count}. Cannot inject Google Analytics.') + sys.exit(1) snippet = ( '\n' ' \n' @@ -102,13 +106,13 @@ jobs: html = html.replace(placeholder, snippet) print('Google Analytics injected:', ga_id) else: - html = html.replace(placeholder, '') + html = re.sub(r'^[ \t]*' + re.escape(placeholder) + r'[ \t]*\r?\n?', '', html, flags=re.MULTILINE) if ga_id: - print('WARNING: GA_MEASUREMENT_ID "' + ga_id + '" is not a valid GA4 ID (expected G-XXXXXXXXXX). Skipping.') + print('WARNING: GA_MEASUREMENT_ID "' + ga_id + '" is not a valid GA4 ID (expected format: G- followed by uppercase letters/digits, e.g. G-HHYVHP2GN1). Skipping.') else: print('GA_MEASUREMENT_ID not set — skipping analytics injection.') - with open('src/index.html', 'w') as f: + with open('src/index.html', 'w', encoding='utf-8') as f: f.write(html) EOF