diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a5aeba..b73341b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,17 @@ jobs: steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history for gitversion + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v4 + with: + versionSpec: '6.x.x' + + - name: Determine Version + id: gitversion + uses: gittools/actions/gitversion/execute@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 @@ -31,6 +42,14 @@ jobs: - name: Build project run: npm run build + env: + GITVERSION_SEMVER: ${{ steps.gitversion.outputs.semVer }} + GITVERSION_FULLSEMVER: ${{ steps.gitversion.outputs.fullSemVer }} + GITVERSION_INFORMATIONALVERSION: ${{ steps.gitversion.outputs.informationalVersion }} - name: Run tests (includes linting, formatting, and type checking) - run: npm test \ No newline at end of file + run: npm test + env: + GITVERSION_SEMVER: ${{ steps.gitversion.outputs.semVer }} + GITVERSION_FULLSEMVER: ${{ steps.gitversion.outputs.fullSemVer }} + GITVERSION_INFORMATIONALVERSION: ${{ steps.gitversion.outputs.informationalVersion }} \ No newline at end of file diff --git a/.github/workflows/deploy-develop.yml b/.github/workflows/deploy-develop.yml index 68a8c0d..8546e26 100644 --- a/.github/workflows/deploy-develop.yml +++ b/.github/workflows/deploy-develop.yml @@ -82,41 +82,107 @@ jobs: - name: Install dependencies run: npm ci - # First: Build main branch content for the root - - name: Checkout and build main branch + # First: Build develop branch content for the subdirectory + - name: Build develop branch for sub-directory + run: npm run build + env: + GITVERSION_SEMVER: ${{ steps.gitversion.outputs.semVer }} + GITVERSION_FULLSEMVER: ${{ steps.gitversion.outputs.fullSemVer }} + GITVERSION_INFORMATIONALVERSION: ${{ steps.gitversion.outputs.informationalVersion }} + + # Save develop build + - name: Save develop build + run: mv dist develop-dist + + # Second: Build main branch content for the root + - name: Checkout and build main branch with test site link run: | - # Save current state - git stash push -m "Save develop changes" + # Save current develop state + git stash push -m "Save develop changes" || echo "No changes to stash" - # Checkout main branch + # Checkout main branch with full history and ensure tags are available git checkout main + git pull origin main || echo "No changes to pull" - # Build main branch content + # Ensure all tags are fetched for version calculation + git fetch --tags || echo "Tags already available" + + # Build main branch content with proper main branch GitVersion npm run build # Save main build mv dist main-dist - # Return to develop branch + # Return to develop branch and restore state git checkout develop - # Only pop the stash if one exists, and fail if pop fails - if git stash list | grep -q .; then + if git stash list | grep -q "Save develop changes"; then git stash pop - else - echo "No stash to pop" fi env: - GITVERSION_SEMVER: ${{ steps.gitversion.outputs.semVer }} - GITVERSION_FULLSEMVER: ${{ steps.gitversion.outputs.fullSemVer }} - GITVERSION_INFORMATIONALVERSION: ${{ steps.gitversion.outputs.informationalVersion }} + # Pass test site info for footer link + TEST_SITE_PATH: ${{ steps.pr-info.outputs.deploy_path }} - # Second: Build develop branch content for the subdirectory - - name: Build develop branch for sub-directory - run: npm run build + # Get GitVersion for main branch after checking it out + - name: Get main branch GitVersion + id: gitversion-main + run: | + # Save current develop state + git stash push -m "Save develop changes" || echo "No changes to stash" + + # Checkout main branch + git checkout main + git pull origin main || echo "No changes to pull" + git fetch --tags || echo "Tags already available" + + # Get GitVersion for main branch + gitversion /output json | tee gitversion-main.json + MAIN_SEMVER=$(cat gitversion-main.json | grep -o '"SemVer":"[^"]*"' | cut -d'"' -f4) + MAIN_FULLSEMVER=$(cat gitversion-main.json | grep -o '"FullSemVer":"[^"]*"' | cut -d'"' -f4) + MAIN_INFORMATIONAL=$(cat gitversion-main.json | grep -o '"InformationalVersion":"[^"]*"' | cut -d'"' -f4) + + echo "main_semver=$MAIN_SEMVER" >> $GITHUB_OUTPUT + echo "main_fullsemver=$MAIN_FULLSEMVER" >> $GITHUB_OUTPUT + echo "main_informational=$MAIN_INFORMATIONAL" >> $GITHUB_OUTPUT + + echo "::notice::Main branch GitVersion - SemVer: $MAIN_SEMVER" + echo "::notice::Main branch GitVersion - FullSemVer: $MAIN_FULLSEMVER" + + # Return to develop branch and restore state + git checkout develop + if git stash list | grep -q "Save develop changes"; then + git stash pop + fi + + # Rebuild main with proper GitVersion values + - name: Rebuild main branch with correct GitVersion + run: | + # Save current develop state + git stash push -m "Save develop changes" || echo "No changes to stash" + + # Checkout main branch + git checkout main + git pull origin main || echo "No changes to pull" + git fetch --tags || echo "Tags already available" + + # Build main branch content with proper main branch GitVersion + npm run build + + # Save main build + rm -rf main-dist + mv dist main-dist + + # Return to develop branch and restore state + git checkout develop + if git stash list | grep -q "Save develop changes"; then + git stash pop + fi env: - GITVERSION_SEMVER: ${{ steps.gitversion.outputs.semVer }} - GITVERSION_FULLSEMVER: ${{ steps.gitversion.outputs.fullSemVer }} - GITVERSION_INFORMATIONALVERSION: ${{ steps.gitversion.outputs.informationalVersion }} + # Use proper GitVersion values for main branch + GITVERSION_SEMVER: ${{ steps.gitversion-main.outputs.main_semver }} + GITVERSION_FULLSEMVER: ${{ steps.gitversion-main.outputs.main_fullsemver }} + GITVERSION_INFORMATIONALVERSION: ${{ steps.gitversion-main.outputs.main_informational }} + # Pass test site info for footer link + TEST_SITE_PATH: ${{ steps.pr-info.outputs.deploy_path }} # Third: Combine both builds into a single directory structure - name: Combine builds for deployment @@ -131,21 +197,21 @@ jobs: mkdir -p "combined-dist/$DEPLOY_PATH" # Modify develop build for sub-directory deployment - if [ -f dist/index.html ]; then + if [ -f develop-dist/index.html ]; then # Add base tag for sub-directory if not present - if ! grep -q "/s||\n |' dist/index.html > "combined-dist/$DEPLOY_PATH/index.html" + if ! grep -q "/s||\n |' develop-dist/index.html > "combined-dist/$DEPLOY_PATH/index.html" echo "::notice::Added base tag to index.html for sub-directory support" else - cp dist/index.html "combined-dist/$DEPLOY_PATH/" + cp develop-dist/index.html "combined-dist/$DEPLOY_PATH/" echo "::notice::Base tag already exists in index.html" fi # Copy other files, preserving directory structure - rsync -av --exclude=index.html dist/ "combined-dist/$DEPLOY_PATH/" + rsync -av --exclude=index.html develop-dist/ "combined-dist/$DEPLOY_PATH/" else - echo "::warning::dist/index.html not found, copying all files as-is" - cp -r dist/* "combined-dist/$DEPLOY_PATH/" + echo "::warning::develop-dist/index.html not found, copying all files as-is" + cp -r develop-dist/* "combined-dist/$DEPLOY_PATH/" fi # Replace dist with combined structure diff --git a/package-lock.json b/package-lock.json index 0ec6f7a..efd1fa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "suncalc": "^1.9.0" }, "devDependencies": { + "@axe-core/playwright": "^4.10.2", "@commitlint/cli": "^19.8.1", "@commitlint/config-conventional": "^19.8.1", "@eslint/js": "^9.32.0", @@ -21,12 +22,15 @@ "@typescript-eslint/eslint-plugin": "^8.39.0", "@typescript-eslint/parser": "^8.37.0", "@vitest/ui": "^3.2.4", + "axe-core": "^4.10.3", + "axe-playwright": "^2.1.0", "eslint": "^9.32.0", "eslint-config-prettier": "^10.1.5", "eslint-plugin-prettier": "^5.5.4", "happy-dom": "^18.0.1", "husky": "^9.1.7", "jsdom": "^26.1.0", + "playwright": "^1.54.2", "prettier": "^3.6.2", "typescript": "^5.9.2", "vitest": "^3.2.4" @@ -46,6 +50,19 @@ "lru-cache": "^10.4.3" } }, + "node_modules/@axe-core/playwright": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.10.2.tgz", + "integrity": "sha512-6/b5BJjG6hDaRNtgzLIfKr5DfwyiLHO4+ByTLB0cJgWSM8Ll7KqtdblIS6bEkwSF642/Ex91vNqIl3GLXGlceg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "axe-core": "~4.10.3" + }, + "peerDependencies": { + "playwright-core": ">= 1.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -1559,6 +1576,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/junit-report-builder": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/junit-report-builder/-/junit-report-builder-3.0.2.tgz", + "integrity": "sha512-R5M+SYhMbwBeQcNXYWNCZkl09vkVfAtcPIaCGdzIkkbeaTrVbGQ7HVgi4s+EmM/M1K4ZuWQH0jGcvMvNePfxYA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "24.2.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz", @@ -2054,6 +2078,49 @@ "node": ">=12" } }, + "node_modules/axe-core": { + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", + "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axe-html-reporter": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/axe-html-reporter/-/axe-html-reporter-2.2.11.tgz", + "integrity": "sha512-WlF+xlNVgNVWiM6IdVrsh+N0Cw7qupe5HT9N6Uyi+aN7f6SSi92RDomiP1noW8OWIV85V6x404m5oKMeqRV3tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mustache": "^4.0.1" + }, + "engines": { + "node": ">=8.9.0" + }, + "peerDependencies": { + "axe-core": ">=3" + } + }, + "node_modules/axe-playwright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/axe-playwright/-/axe-playwright-2.1.0.tgz", + "integrity": "sha512-tY48SX56XaAp16oHPyD4DXpybz8Jxdz9P7exTjF/4AV70EGUavk+1fUPWirM0OYBR+YyDx6hUeDvuHVA6fB9YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/junit-report-builder": "^3.0.2", + "axe-core": "^4.10.1", + "axe-html-reporter": "2.2.11", + "junit-report-builder": "^5.1.1", + "picocolors": "^1.1.1" + }, + "peerDependencies": { + "playwright": ">1.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3588,6 +3655,21 @@ "node": "*" } }, + "node_modules/junit-report-builder": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-5.1.1.tgz", + "integrity": "sha512-ZNOIIGMzqCGcHQEA2Q4rIQQ3Df6gSIfne+X9Rly9Bc2y55KxAZu8iGv+n2pP0bLf0XAOctJZgeloC54hWzCahQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "make-dir": "^3.1.0", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3635,6 +3717,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -3722,6 +3811,32 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/meow": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", @@ -3802,6 +3917,16 @@ "dev": true, "license": "MIT" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -3987,6 +4112,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz", + "integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.54.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz", + "integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -5032,6 +5204,16 @@ "node": ">=18" } }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", diff --git a/package.json b/package.json index 1f5f61a..5a02ee4 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,13 @@ "build:watch": "tsc --watch", "dev": "tsc --watch", "clean": "rm -rf dist", - "copy-assets": "cp src/*.* dist/ && cp -r src/styles src/scripts dist/ && cp src/favicons/* dist/ && mkdir -p dist/scripts/suncalc && cp node_modules/suncalc/suncalc.js node_modules/suncalc/LICENSE dist/scripts/suncalc/ && mkdir -p dist/scripts/temporal && cp node_modules/@js-temporal/polyfill/dist/index.umd.js dist/scripts/temporal/", + "copy-assets": "cp src/*.* dist/ && cp -r src/styles src/scripts dist/ && cp src/favicons/* dist/ && mkdir -p dist/scripts/suncalc && cp node_modules/suncalc/suncalc.js node_modules/suncalc/LICENSE dist/scripts/suncalc/ && mkdir -p dist/scripts/temporal && cp node_modules/@js-temporal/polyfill/dist/index.umd.js node_modules/@js-temporal/polyfill/dist/index.umd.js.map dist/scripts/temporal/", "type-check": "tsc --noEmit", "lint": "eslint src/**/*.ts --no-warn-ignored", "lint:fix": "eslint src/**/*.ts --fix", "format": "prettier --write src/**/*.{ts,js,json,html,css,md}", "format:check": "prettier --check src/**/*.{ts,js,json,html,css,md}", - "test": "npm run lint && npm run format:check && npm run type-check && vitest run", + "test": "npm run build && npm run lint && npm run format:check && npm run type-check && vitest run", "test:watch": "vitest", "test:ui": "vitest --ui", "test:coverage": "vitest run --coverage", @@ -31,6 +31,7 @@ "author": "Taylor Marvin", "license": "MIT", "devDependencies": { + "@axe-core/playwright": "^4.10.2", "@commitlint/cli": "^19.8.1", "@commitlint/config-conventional": "^19.8.1", "@eslint/js": "^9.32.0", @@ -38,12 +39,15 @@ "@typescript-eslint/eslint-plugin": "^8.39.0", "@typescript-eslint/parser": "^8.37.0", "@vitest/ui": "^3.2.4", + "axe-core": "^4.10.3", + "axe-playwright": "^2.1.0", "eslint": "^9.32.0", "eslint-config-prettier": "^10.1.5", "eslint-plugin-prettier": "^5.5.4", "happy-dom": "^18.0.1", "husky": "^9.1.7", "jsdom": "^26.1.0", + "playwright": "^1.54.2", "prettier": "^3.6.2", "typescript": "^5.9.2", "vitest": "^3.2.4" diff --git a/src/build/inject-version.ts b/src/build/inject-version.ts index ca5a6ed..a1b5beb 100644 --- a/src/build/inject-version.ts +++ b/src/build/inject-version.ts @@ -3,63 +3,33 @@ import { join } from 'path'; import { execSync } from 'child_process'; function getGitVersion(): string { - // First, check if GitVersion environment variables are available (from CI) + // Check GitVersion environment variables (from CI) const envSemVer = process.env.GITVERSION_SEMVER; + const envFullSemVer = process.env.GITVERSION_FULLSEMVER; - if (envSemVer) { - console.log(`Using GitVersion from environment: ${envSemVer}`); - return envSemVer; + // Check if environment variables are defined (even if empty) + if (envSemVer !== undefined || envFullSemVer !== undefined) { + const version = envSemVer || envFullSemVer; + if (!version || version.trim() === '') { + throw new Error('GitVersion environment variables are present but empty. Expected valid version string.'); + } + console.log(`Using GitVersion from environment: ${version}`); + return version; } + // Try GitVersion CLI try { - // Try GitVersion CLI tool (if available locally) const gitVersionOutput = execSync('gitversion', { encoding: 'utf-8', cwd: process.cwd() }); const gitVersionData = JSON.parse(gitVersionOutput); - console.log(`Using GitVersion from CLI: ${gitVersionData.SemVer || gitVersionData.FullSemVer}`); - return gitVersionData.SemVer || gitVersionData.FullSemVer; - } catch { - // Fallback to simple git tag approach - try { - const lastTag = execSync('git describe --tags --abbrev=0', { encoding: 'utf-8', cwd: process.cwd() }).trim(); - const commitsSince = execSync(`git rev-list ${lastTag}..HEAD --count`, { - encoding: 'utf-8', - cwd: process.cwd(), - }).trim(); - const commits = parseInt(commitsSince, 10); - - // Parse the tag version - const match = lastTag.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/); - if (!match || !match[1] || !match[2] || !match[3]) { - console.log('Using default fallback version: 1.0.0'); - return '1.0.0'; - } - - const major = parseInt(match[1], 10); - const minor = parseInt(match[2], 10); - let patch = parseInt(match[3], 10); - - // Simple branch-based logic - const branch = execSync('git branch --show-current', { encoding: 'utf-8', cwd: process.cwd() }).trim(); - if (branch === 'main' && commits > 0) { - patch += 1; - const version = `${major}.${minor}.${patch}`; - console.log(`Using fallback git logic for main branch: ${version}`); - return version; - } else if (commits > 0) { - patch += 1; - const version = `${major}.${minor}.${patch}-alpha.${commits}`; - console.log(`Using fallback git logic for feature branch: ${version}`); - return version; - } - - const version = `${major}.${minor}.${patch}`; - console.log(`Using fallback git logic for tagged commit: ${version}`); - return version; - } catch { - // No git or tags available, use default - console.log('No git available, using default version: 1.0.0'); - return '1.0.0'; - } + const version = gitVersionData.SemVer || gitVersionData.FullSemVer; + console.log(`Using GitVersion from CLI: ${version}`); + return version; + } catch (gitVersionError) { + throw new Error( + `GitVersion is required but was not available. ` + + `Expected GITVERSION_SEMVER environment variable or working 'gitversion' CLI tool. ` + + `Error: ${gitVersionError}`, + ); } } @@ -86,13 +56,19 @@ function injectVersionIntoHtml(): void { htmlContent = htmlContent.replace(metaTagRegex, `$1\n `); } - // Inject version into footer - const footerRegex = /(