diff --git a/.github/workflows/deprecate_release.yml b/.github/workflows/deprecate_release.yml index 2e17dac6b3..c7e96a2d6f 100644 --- a/.github/workflows/deprecate_release.yml +++ b/.github/workflows/deprecate_release.yml @@ -51,5 +51,8 @@ jobs: fetch-depth: 0 - uses: ./.github/actions/setup_node - uses: ./.github/actions/restore_install_cache + - name: Start local proxy + if: !inputs.useNpmRegistry + run: npm run start:npm-proxy - name: Deprecate release versions run: npx tsx scripts/deprecate_release.ts diff --git a/.github/workflows/restore_release.yml b/.github/workflows/restore_release.yml index 5e177d48e4..36a51e6043 100644 --- a/.github/workflows/restore_release.yml +++ b/.github/workflows/restore_release.yml @@ -46,5 +46,8 @@ jobs: fetch-depth: 0 - uses: ./.github/actions/setup_node - uses: ./.github/actions/restore_install_cache + - name: Start local proxy + if: !inputs.useNpmRegistry + run: npm run start:npm-proxy - name: Restore release versions run: npx tsx scripts/restore_release.ts diff --git a/scripts/components/git_client.ts b/scripts/components/git_client.ts index 19b0298cf9..fc93acdde0 100644 --- a/scripts/components/git_client.ts +++ b/scripts/components/git_client.ts @@ -218,23 +218,20 @@ class GitClient { ); // eslint-disable-next-line spellcheck/spell-checker - await $`git config ${userEmailKey} "github-actions[bot]@users.noreply.github.com"`; - await $`git config ${userNameKey} "github-actions[bot]"`; - - await $`git config --unset-all ${autoSetupRemoteKey}`; - await $`git config ${autoSetupRemoteKey} true`; + await $`git config --replace-all ${userEmailKey} "github-actions[bot]@users.noreply.github.com"`; + await $`git config --replace-all ${userNameKey} "github-actions[bot]"`; + await $`git config --replace-all ${autoSetupRemoteKey} true`; this.registerCleanup(async () => { // reset config on exit if (originalEmail) { - await $`git config user.email ${originalEmail}`; + await $`git config --replace-all ${userEmailKey} ${originalEmail}`; } if (originalName) { - await $`git config ${userNameKey} ${originalName}`; + await $`git config --replace-all ${userNameKey} ${originalName}`; } if (originalAutoSetupRemote) { - await $`git config --unset-all ${autoSetupRemoteKey}`; - await $`git config ${autoSetupRemoteKey} ${originalAutoSetupRemote}`; + await $`git config --replace-all ${autoSetupRemoteKey} ${originalAutoSetupRemote}`; } }); this.isConfigured = true; diff --git a/scripts/components/release_lifecycle_manager.test.ts b/scripts/components/release_lifecycle_manager.test.ts new file mode 100644 index 0000000000..3cc86bd584 --- /dev/null +++ b/scripts/components/release_lifecycle_manager.test.ts @@ -0,0 +1,36 @@ +import { after, before, beforeEach, describe, it } from 'node:test'; + +/** + * This test suite is more of an integration test than a unit test. + * It uses the real file system and git repo but mocks the GitHub API client + * It spins up verdaccio to test updating package metadata locally + * + * Since all of these tests are sharing the same git tree, we're running concurrently to avoid conflicts (mostly around duplicate tag names) + */ +void describe('ReleaseLifecycleManager', { concurrency: 1 }, () => { + before(async () => { + await import('../start_npm_proxy.js'); + }); + + after(async () => { + await import('../stop_npm_proxy.js'); + }); + + beforeEach(async () => { + // checkout test branch + // add changeset that releases minor of package A + // run changeset version && publish + // add changeset that releases minor of package A and B + // run changeset version && publish + }); + void describe('deprecateRelease', () => { + void it('deprecates expected versions and updates dist-tags', async () => {}); + + void it('does not update dist-tags when deprecating a past release'); + }); + void describe('restoreRelease', () => { + void it('un-deprecates expected versions and updates dist-tags', async () => {}); + + void it('does not update dist-tags when restoring a past release', async () => {}); + }); +}); diff --git a/scripts/components/release_lifecycle_manager.ts b/scripts/components/release_lifecycle_manager.ts index 1331ac14fb..f339cfcda5 100644 --- a/scripts/components/release_lifecycle_manager.ts +++ b/scripts/components/release_lifecycle_manager.ts @@ -2,7 +2,6 @@ import { EOL } from 'os'; import { gitClient as _gitClient } from './git_client.js'; import { npmClient as _npmClient } from './npm_client.js'; import { getDistTagFromReleaseTag } from './get_dist_tag_from_release_tag.js'; -import { execa } from 'execa'; import { githubClient as _githubClient } from './github_client.js'; /** @@ -107,12 +106,6 @@ export class ReleaseLifecycleManager { // if anything fails before this point, we haven't actually modified anything on NPM yet. // now we actually update the npm dist tags and mark the packages as deprecated - if (this.registryTarget === 'local-proxy') { - await execa('npm', ['run', 'start:npm-proxy'], { stdio: 'inherit' }); - } - - await this.npmClient.configureNpmRc({ target: this.registryTarget }); - for (const releaseTag of releaseTagsToRestoreDistTagPointers) { const distTag = getDistTagFromReleaseTag(releaseTag); console.log( @@ -196,12 +189,6 @@ export class ReleaseLifecycleManager { // if anything fails before this point, we haven't actually modified anything on NPM yet. // now we actually update the npm dist tags and mark the packages as un-deprecated - if (this.registryTarget === 'local-proxy') { - await execa('npm', ['run', 'start:npm-proxy'], { stdio: 'inherit' }); - } - - await this.npmClient.configureNpmRc({ target: this.registryTarget }); - for (const releaseTag of releaseTagsToRestoreDistTagPointers) { const distTag = getDistTagFromReleaseTag(releaseTag); console.log( @@ -225,6 +212,6 @@ export class ReleaseLifecycleManager { The release deprecation workflow requires a clean working tree to create the rollback PR. `); } - await this.gitClient.fetchTags(); + await this.npmClient.configureNpmRc({ target: this.registryTarget }); }; }