diff --git a/package.json b/package.json index e3c4b30bf..c9e67ce50 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "postinstall": "husky install", "changeset": "changeset", "update-versions-and-changelogs": "changeset version && yarn version-run-all && bash scripts/update-lockfile.sh", - "release": "yarn clean && yarn build --force && changeset publish && git push origin HEAD:master --follow-tags --no-verify", + "release": "yarn clean && yarn build --force && changeset publish && git push origin HEAD:master --follow-tags --no-verify && yarn scripts purge-cdn-cache", "version-run-all": "yarn workspaces foreach -vpt --no-private run version", "core": "yarn workspace @segment/analytics-core", "browser": "yarn workspace @segment/analytics-next", diff --git a/scripts/package.json b/scripts/package.json index c68ec6d17..c04a50d3a 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -6,6 +6,9 @@ ".": "yarn run -T turbo run --filter=@internal/scripts", "lint": "yarn concurrently 'yarn:eslint .' 'yarn:tsc --noEmit'", "create-release-from-tags": "yarn ts-node-script --files create-release-from-tags/run.ts", + "purge-cdn-cache": "yarn concurrently 'yarn:purge-cdn-cache:*'", + "purge-cdn-cache:signals": "node purge-cdn-cache.js '@segment/analytics-signals' 'packages/signals/signals/dist/umd'", + "purge-cdn-cache:consent": "node purge-cdn-cache.js '@segment/analytics-consent-wrapper-onetrust' 'packages/consent/consent-wrapper-onetrust/dist/umd'", "test": "yarn jest", "tsc": "yarn run -T tsc", "eslint": "yarn run -T eslint", diff --git a/scripts/purge-cdn-cache.js b/scripts/purge-cdn-cache.js new file mode 100644 index 000000000..b13c0fa42 --- /dev/null +++ b/scripts/purge-cdn-cache.js @@ -0,0 +1,70 @@ +const { execSync } = require('node:child_process') +const fs = require('node:fs') +const path = require('node:path') +/** + * Given a package name and a relative path to the dist folder -- it reads all the files and runs them through the jsdelivr cache purge API. + * On CI, will abort the purge unless the current commit has a tag with the package name on it. + */ +const purgeJsDelivrCache = async (packageName, relativePath) => { + console.log(`\n\n`) + const gitRoot = path.resolve(__dirname, '..') + const fullPath = path.join(gitRoot, relativePath) + + if (!fs.existsSync(fullPath)) { + console.error(`Path does not exist: ${fullPath}`) + process.exit(1) + } + + // Only run this script if the given package has been published + // Check if the current git HEAD has a tag containing the package name + // This is a bit odd versus just having the cache purge on a prepublish hooks, but publish hooks like post/prepublish had been flaky on CI with changesets when I was setting this up. + if (process.env.CI) { + console.log('Searching for matching tag for package...') + try { + const tags = execSync('git tag --contains HEAD', { + cwd: gitRoot, + }).toString() + + const hasMatchingTag = tags.includes(packageName) + if (!hasMatchingTag) { + console.log( + `No tags containing the package name "${packageName}" found on the current git HEAD. Aborting cache purge.` + ) + process.exit(0) + } + } catch (error) { + console.error(`Failed to check git tags: ${error.message}`) + process.exit(1) + } + } + + const files = fs.readdirSync(fullPath) + + console.log( + `Purging files for ${packageName}: ${JSON.stringify(files, null, 2)}` + ) + for (const file of files) { + const filePath = path.join(relativePath, file) + console.log(`Purging cache: ${file}...`) + const url = `https://purge.jsdelivr.net/npm/${packageName}/${filePath}` + + try { + const response = await fetch(url) + if (!response.ok) { + console.error(`Failed to purge: ${url} - Status: ${response.status}`) + } + } catch (error) { + console.error(`Failed to purge: ${url} - Error: ${error.message}`) + } + } + console.log(`\nPurge of ${packageName} finished.`) +} + +const [packageName, relativePath] = process.argv.slice(2) + +if (!packageName || !relativePath) { + console.error('Usage: node purge-cdn-cache.js ') + process.exit(1) +} + +purgeJsDelivrCache(packageName, relativePath)