From f88774b561e84737430c4a74507a2a6987deb84f Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 12:58:44 +0000 Subject: [PATCH 01/10] chore: migrate unpublish script -> deprecation script --- scripts/release-deprecate.ts | 75 ++++++++++++++++++++++++++++++++++++ scripts/release-unpublish.js | 59 ---------------------------- 2 files changed, 75 insertions(+), 59 deletions(-) create mode 100644 scripts/release-deprecate.ts delete mode 100644 scripts/release-unpublish.js diff --git a/scripts/release-deprecate.ts b/scripts/release-deprecate.ts new file mode 100644 index 00000000000..d0581f0ed37 --- /dev/null +++ b/scripts/release-deprecate.ts @@ -0,0 +1,75 @@ +import { compare } from 'compare-versions'; +import { exec } from 'node:child_process'; +import { readFileSync, readdirSync } from 'node:fs'; +import { join } from 'node:path'; + +const { log, error } = console; + +const UNPUBLISH_TAGS = /next|pr|rc/; +const { version: CURRENT_VERSION } = JSON.parse( + readFileSync(join(process.cwd(), '/packages/fuels/package.json')).toString() +); + +const getPublicPackages = () => { + const packagesDir = join(__dirname, '../packages'); + const packages = readdirSync(packagesDir, { withFileTypes: true }); + const packagesNames = packages.map((p) => { + try { + const packageContent = readFileSync(join(packagesDir, p.name, 'package.json'), 'utf8'); + const packageJson = JSON.parse(packageContent.toString()); + return packageJson.private ? null : packageJson.name; + } catch (err) { + return null; + } + }); + return packagesNames.filter((p) => !!p); +}; + +const main = async () => { + const packages = getPublicPackages(); + await Promise.all( + packages.map(async (packageName) => { + const { versions: packageVersions } = await fetch( + `https://registry.npmjs.org/${packageName}` + ).then((resp) => resp.json()); + + const versionsToDelete = Object.keys(packageVersions).filter( + (packageVersion) => + packageVersion.search(UNPUBLISH_TAGS) > -1 && + !compare(packageVersion, CURRENT_VERSION, '>=') + ); + log('The following versions will be deprecated:'); + log(versionsToDelete.map((v) => ` - ${v}`).join('\n')); + + await Promise.all( + versionsToDelete.map( + async (versionToDelete) => + new Promise((resolve, reject) => { + exec( + `npm deprecate ${packageName}@${versionToDelete} "Version no longer supported."`, + (err, _stdout, stderr) => { + if (err) { + log(`❌ Error ${packageName}@${versionToDelete} not deprecated!\n`); + reject(err); + return; + } + if (stderr) { + log(`❌ Error ${packageName}@${versionToDelete} not deprecated!\n`); + reject(new Error(stderr)); + return; + } + log(`✅ Package ${packageName}@${versionToDelete} deprecated!\n`); + resolve(true); + } + ); + }) + ) + ); + }) + ); +}; + +main().catch((err) => { + error(err); + process.exit(1); +}); diff --git a/scripts/release-unpublish.js b/scripts/release-unpublish.js deleted file mode 100644 index d88f3e91ed9..00000000000 --- a/scripts/release-unpublish.js +++ /dev/null @@ -1,59 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -const { compare } = require('compare-versions'); -const { readFileSync, readdirSync } = require('node:fs'); -const { join } = require('node:path'); -const util = require('node:util'); -const exec = util.promisify(require('node:child_process').exec); - -const DELETE_TAGS = /next|pr/; -const { version: CURRENT_VERSION } = require('../packages/fuels/package.json'); - -const DELETE_PACKAGES = process.env.DELETE_PACKAGES === 'true'; -const dryRun = DELETE_PACKAGES ? '' : '--dry-run'; - -const { log, error } = console; - -const getPublicPackages = () => { - const packagesDir = join(__dirname, '../packages'); - const packages = readdirSync(packagesDir, { withFileTypes: true }); - const packagesNames = packages.map((p) => { - try { - const packageContent = readFileSync(join(packagesDir, p.name, 'package.json'), 'utf8'); - const packageJson = JSON.parse(packageContent.toString()); - return packageJson.private ? null : packageJson.name; - } catch (err) { - return null; - } - }); - return packagesNames.filter((p) => !!p); -}; - -const main = async () => { - const packages = getPublicPackages(); - await packages.map(async (packageName) => { - log(`📦 Fetching ${packageName} versions`); - const { versions: packageVersions } = await fetch( - `https://registry.npmjs.org/${packageName}` - ).then((resp) => resp.json()); - - const versionsToDelete = Object.keys(packageVersions).filter( - (packageVersion) => - packageVersion.search(DELETE_TAGS) > -1 && !compare(packageVersion, CURRENT_VERSION, '>=') - ); - log('The following versions will be deleted:'); - log(versionsToDelete.map((v) => ` - ${v}`).join('\n')); - versionsToDelete.map(async (versionToDelete) => { - const { stderr } = await exec(`npm unpublish ${packageName}@${versionToDelete} ${dryRun}`); - if (stderr) { - log(`❌ Error ${packageName}@${versionToDelete} not deleted!\n`); - } else { - log(`✅ Package ${packageName}@${versionToDelete} deleted!\n`); - } - }); - }); -}; - -main().catch((err) => { - error(err); - process.exit(1); -}); From 07d5962a6df83a4900d34180358511e49e20cd99 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 12:58:55 +0000 Subject: [PATCH 02/10] chore: add deprecation workflow --- .github/workflows/release-unpublish.yaml | 28 ++++++++++-------------- package.json | 1 + 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release-unpublish.yaml b/.github/workflows/release-unpublish.yaml index 77cba5e6ea3..0ae8f6d3c66 100644 --- a/.github/workflows/release-unpublish.yaml +++ b/.github/workflows/release-unpublish.yaml @@ -1,28 +1,22 @@ -name: "Unpublish old versions" +name: "Deprecate Old Versions" on: workflow_dispatch: - inputs: - delete_packages: - type: boolean - description: Delete packages? otherwise dry-run mode will be used - default: false concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - clean-npm-versions: - name: Unpublish versions next and pr + deprecate-npm-versions: + name: Deprecate versions next, pr and rc runs-on: buildjet-4vcpu-ubuntu-2204 steps: - - uses: actions/checkout@v4 - - uses: ./.github/actions/ci-setup - - uses: FuelLabs/github-actions/setups/npm@master - with: - npm-token: ${{ secrets.NPM_TOKEN }} - - run: | - node ./scripts/release-unpublish.js - env: - DELETE_PACKAGES: ${{ github.event.inputs.delete_packages}} + - name: Checkout + uses: actions/checkout@v4 + + - name: CI Setup + uses: ./.github/actions/ci-setup + + - name: Deprecate + run: pnpm release:deprecate diff --git a/package.json b/package.json index 49d473cfa96..8233d69d518 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "changeset:update-changelog": "tsx ./scripts/changeset/update-changelog.mts", "changeset:get-latest-release": "tsx ./scripts/changeset/get-latest-release.mts", "changeset:dependabot": "./scripts/changeset/dependabot-changeset.sh", + "release:deprecate": "tsx ./scripts/release-deprecate.ts", "forc:update": "tsx ./scripts/forc-update", "forc:check": "./scripts/forc-check.sh", "forc:format": "./scripts/forc-format.sh", From f0de5484b37bed289cdd1f1f343a58f8d701b13a Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 12:59:59 +0000 Subject: [PATCH 03/10] chore: changeset --- .changeset/lucky-flies-search.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changeset/lucky-flies-search.md diff --git a/.changeset/lucky-flies-search.md b/.changeset/lucky-flies-search.md new file mode 100644 index 00000000000..1c2edc43fce --- /dev/null +++ b/.changeset/lucky-flies-search.md @@ -0,0 +1,4 @@ +--- +--- + +chore: release deprecation script From 2655877afd9da13aa34201ffa001ac072ef9f52f Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 13:01:06 +0000 Subject: [PATCH 04/10] chore: rename workflow --- .../workflows/{release-unpublish.yaml => release-deprecate.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{release-unpublish.yaml => release-deprecate.yaml} (100%) diff --git a/.github/workflows/release-unpublish.yaml b/.github/workflows/release-deprecate.yaml similarity index 100% rename from .github/workflows/release-unpublish.yaml rename to .github/workflows/release-deprecate.yaml From c5ef167659f46e9bb27a649a623577736e961f4e Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 14:19:46 +0000 Subject: [PATCH 05/10] chore: rebuild From 82caf3afc9cca9bf6eb890cccb9682fd4983bbd0 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 16:21:48 +0000 Subject: [PATCH 06/10] chore: use allSettled --- scripts/release-deprecate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release-deprecate.ts b/scripts/release-deprecate.ts index d0581f0ed37..d2449831a90 100644 --- a/scripts/release-deprecate.ts +++ b/scripts/release-deprecate.ts @@ -27,7 +27,7 @@ const getPublicPackages = () => { const main = async () => { const packages = getPublicPackages(); - await Promise.all( + await Promise.allSettled( packages.map(async (packageName) => { const { versions: packageVersions } = await fetch( `https://registry.npmjs.org/${packageName}` @@ -41,7 +41,7 @@ const main = async () => { log('The following versions will be deprecated:'); log(versionsToDelete.map((v) => ` - ${v}`).join('\n')); - await Promise.all( + await Promise.allSettled( versionsToDelete.map( async (versionToDelete) => new Promise((resolve, reject) => { From 5c35c7133cb4a47d6c67cb3ec00b2f8db1f0ef69 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 16:36:34 +0000 Subject: [PATCH 07/10] chore: add dry run --- .github/workflows/release-deprecate.yaml | 7 ++++ scripts/release-deprecate.ts | 49 +++++++++++++----------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/.github/workflows/release-deprecate.yaml b/.github/workflows/release-deprecate.yaml index 0ae8f6d3c66..61807d69d16 100644 --- a/.github/workflows/release-deprecate.yaml +++ b/.github/workflows/release-deprecate.yaml @@ -2,6 +2,11 @@ name: "Deprecate Old Versions" on: workflow_dispatch: + inputs: + deprecate_versions: + type: boolean + description: Deprecate versions? Otherwise dry-run mode will be used. + default: false concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -20,3 +25,5 @@ jobs: - name: Deprecate run: pnpm release:deprecate + env: + DEPRECATE_VERSIONS: ${{ github.event.inputs.deprecate_versions }} diff --git a/scripts/release-deprecate.ts b/scripts/release-deprecate.ts index d2449831a90..113a8934cdd 100644 --- a/scripts/release-deprecate.ts +++ b/scripts/release-deprecate.ts @@ -9,6 +9,7 @@ const UNPUBLISH_TAGS = /next|pr|rc/; const { version: CURRENT_VERSION } = JSON.parse( readFileSync(join(process.cwd(), '/packages/fuels/package.json')).toString() ); +const deprecateVersions = process.env.DEPRECATE_VERSIONS === 'true'; const getPublicPackages = () => { const packagesDir = join(__dirname, '../packages'); @@ -41,30 +42,32 @@ const main = async () => { log('The following versions will be deprecated:'); log(versionsToDelete.map((v) => ` - ${v}`).join('\n')); - await Promise.allSettled( - versionsToDelete.map( - async (versionToDelete) => - new Promise((resolve, reject) => { - exec( - `npm deprecate ${packageName}@${versionToDelete} "Version no longer supported."`, - (err, _stdout, stderr) => { - if (err) { - log(`❌ Error ${packageName}@${versionToDelete} not deprecated!\n`); - reject(err); - return; + if (deprecateVersions) { + await Promise.allSettled( + versionsToDelete.map( + async (versionToDelete) => + new Promise((resolve, reject) => { + exec( + `npm deprecate ${packageName}@${versionToDelete} "Version no longer supported."`, + (err, _stdout, stderr) => { + if (err) { + log(`❌ Error ${packageName}@${versionToDelete} not deprecated!\n`); + reject(err); + return; + } + if (stderr) { + log(`❌ Error ${packageName}@${versionToDelete} not deprecated!\n`); + reject(new Error(stderr)); + return; + } + log(`✅ Package ${packageName}@${versionToDelete} deprecated!\n`); + resolve(true); } - if (stderr) { - log(`❌ Error ${packageName}@${versionToDelete} not deprecated!\n`); - reject(new Error(stderr)); - return; - } - log(`✅ Package ${packageName}@${versionToDelete} deprecated!\n`); - resolve(true); - } - ); - }) - ) - ); + ); + }) + ) + ); + } }) ); }; From 8cb124fa9cdd8400de44ff53e289520edf1dd7eb Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 16:39:02 +0000 Subject: [PATCH 08/10] chore: refactor --- scripts/release-deprecate.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/release-deprecate.ts b/scripts/release-deprecate.ts index 113a8934cdd..686f37ac196 100644 --- a/scripts/release-deprecate.ts +++ b/scripts/release-deprecate.ts @@ -26,25 +26,29 @@ const getPublicPackages = () => { return packagesNames.filter((p) => !!p); }; +const getVersionsToDeprecate = async (packageName: string) => { + const { versions: packageVersions } = await fetch( + `https://registry.npmjs.org/${packageName}` + ).then((resp) => resp.json()); + + return Object.keys(packageVersions).filter( + (packageVersion) => + packageVersion.search(UNPUBLISH_TAGS) > -1 && !compare(packageVersion, CURRENT_VERSION, '>=') + ); +}; + const main = async () => { const packages = getPublicPackages(); await Promise.allSettled( packages.map(async (packageName) => { - const { versions: packageVersions } = await fetch( - `https://registry.npmjs.org/${packageName}` - ).then((resp) => resp.json()); + const versionsToDeprecate = await getVersionsToDeprecate(packageName); - const versionsToDelete = Object.keys(packageVersions).filter( - (packageVersion) => - packageVersion.search(UNPUBLISH_TAGS) > -1 && - !compare(packageVersion, CURRENT_VERSION, '>=') - ); log('The following versions will be deprecated:'); - log(versionsToDelete.map((v) => ` - ${v}`).join('\n')); + log(versionsToDeprecate.map((v) => ` - ${v}`).join('\n')); if (deprecateVersions) { await Promise.allSettled( - versionsToDelete.map( + versionsToDeprecate.map( async (versionToDelete) => new Promise((resolve, reject) => { exec( From d1d0fa0dda0e0fff17597c1a238abca2943e600f Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 17:31:58 +0000 Subject: [PATCH 09/10] chore: filter out latest next tag --- scripts/release-deprecate.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/scripts/release-deprecate.ts b/scripts/release-deprecate.ts index 686f37ac196..285f3d6c6ba 100644 --- a/scripts/release-deprecate.ts +++ b/scripts/release-deprecate.ts @@ -5,8 +5,8 @@ import { join } from 'node:path'; const { log, error } = console; -const UNPUBLISH_TAGS = /next|pr|rc/; -const { version: CURRENT_VERSION } = JSON.parse( +const deprecateTags = /next|pr|rc/; +const { version: currentVersion } = JSON.parse( readFileSync(join(process.cwd(), '/packages/fuels/package.json')).toString() ); const deprecateVersions = process.env.DEPRECATE_VERSIONS === 'true'; @@ -27,18 +27,23 @@ const getPublicPackages = () => { }; const getVersionsToDeprecate = async (packageName: string) => { - const { versions: packageVersions } = await fetch( - `https://registry.npmjs.org/${packageName}` - ).then((resp) => resp.json()); + const { versions } = await fetch(`https://registry.npmjs.org/${packageName}`).then((resp) => + resp.json() + ); - return Object.keys(packageVersions).filter( - (packageVersion) => - packageVersion.search(UNPUBLISH_TAGS) > -1 && !compare(packageVersion, CURRENT_VERSION, '>=') + // Only deprecate certain tags + const validVersions = Object.keys(versions).filter( + (version) => version.search(deprecateTags) > -1 && !compare(version, currentVersion, '>=') ); + + // Remove the latest next tag from the deprecation list + const latestNextVersion = validVersions.filter((version) => version.search('next') > -1).pop(); + return validVersions.filter((version) => version !== latestNextVersion); }; const main = async () => { - const packages = getPublicPackages(); + // const packages = getPublicPackages(); + const packages = ['fuels']; await Promise.allSettled( packages.map(async (packageName) => { const versionsToDeprecate = await getVersionsToDeprecate(packageName); From a0175f0f6d4e85de03eeb13c27ff5850897186ad Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 11 Dec 2024 17:32:36 +0000 Subject: [PATCH 10/10] chore: remove hardcoded package --- scripts/release-deprecate.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/release-deprecate.ts b/scripts/release-deprecate.ts index 285f3d6c6ba..922b967cc76 100644 --- a/scripts/release-deprecate.ts +++ b/scripts/release-deprecate.ts @@ -42,8 +42,7 @@ const getVersionsToDeprecate = async (packageName: string) => { }; const main = async () => { - // const packages = getPublicPackages(); - const packages = ['fuels']; + const packages = getPublicPackages(); await Promise.allSettled( packages.map(async (packageName) => { const versionsToDeprecate = await getVersionsToDeprecate(packageName);