diff --git a/.github/workflows/push_redirects.yml b/.github/workflows/push_redirects.yml new file mode 100644 index 0000000000..802bf7c29f --- /dev/null +++ b/.github/workflows/push_redirects.yml @@ -0,0 +1,41 @@ +name: Push to Redirects + +on: + push: + paths: + - 'public/_redirects' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: Validate redirects + runs-on: ubuntu-latest + defaults: + run: + + steps: + - name: ⬇️ Set up code + uses: actions/checkout@v4 + with: + show-progress: false + + - name: ⎔ Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: npm + + - name: 🏗️ Build Site + working-directory: ./ + run: | + npm install + npm run build + + - name: ✔ Validate redirects + working-directory: ./src/migrations + run: | + npm install + node validate-redirects.mjs diff --git a/src/migrations/validate-redirects.mjs b/src/migrations/validate-redirects.mjs new file mode 100644 index 0000000000..a442184cf0 --- /dev/null +++ b/src/migrations/validate-redirects.mjs @@ -0,0 +1,50 @@ +import { globSync } from 'glob'; +import { open } from 'node:fs/promises'; +import { join } from 'node:path'; +import { validateProductPageUrl } from './utilities.mjs'; + +const redirectPath = join('..', '..', 'public', '_redirects'); +let file = await open(redirectPath, 'r'); + +// get urls from built files +const fileUrls = globSync('../../dist/**/*.html', { ignore: '../../dist/404.html' }).map((path) => + path + .replace('../../dist', '') + .replace(/index\.html$/, '') + .replace(/\/$/, ''), +); + +const errors = []; +let isFirstLine = true; +for await (const line of file.readLines()) { + if (isFirstLine) { + isFirstLine = false; + continue; // Skip the first line + } + + let [source, destination] = line.split(' ').filter((l) => l); + + if (destination.startsWith('/')) { + destination = destination.replace(/\/$/, ''); + if (!fileUrls.includes(destination)) { + const message = `destination: "${destination}" not found`; + console.error(message); + errors.push(message); + } + } else { + const response = await validateProductPageUrl(destination); + if (!response.valid) { + const message = `destination: ${destination} failed validation with message: ${response.message}`; + console.error(message); + errors.push(message); + } + } +} + +file.close(); + +if (errors.length > 0) { + process.exit(1); +} + +process.exit(0);