-
Notifications
You must be signed in to change notification settings - Fork 73
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2480023
commit cce9e9e
Showing
9 changed files
with
273 additions
and
248 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { EOL } from 'os'; | ||
import { NpmClient } from './npm_client.js'; | ||
import { releaseTagToNameAndVersion } from './release_tag_to_name_and_version.js'; | ||
|
||
type DistTagMoveAction = { | ||
/** | ||
* An NPM dist-tag | ||
*/ | ||
distTag: string; | ||
/** | ||
* This is a string of the form <packageName>@<version> | ||
*/ | ||
releaseTag: string; | ||
}; | ||
|
||
/** | ||
* Handles moving npm dist-tags from one package version to another | ||
*/ | ||
export class DistTagMover { | ||
/** | ||
* Initialize with an npmClient | ||
*/ | ||
constructor(private readonly npmClient: NpmClient) {} | ||
|
||
/** | ||
* Given a list of sourceReleaseTags and destReleaseTags, | ||
* any npm dist-tags that are pointing to a sourceReleaseTag will be moved to point to the corresponding destReleaseTag | ||
*/ | ||
moveDistTags = async ( | ||
sourceReleaseTags: string[], | ||
destReleaseTags: string[] | ||
) => { | ||
const moveActions: DistTagMoveAction[] = []; | ||
|
||
for (const sourceReleaseTag of sourceReleaseTags) { | ||
const { packageName, version: sourceVersion } = | ||
releaseTagToNameAndVersion(sourceReleaseTag); | ||
|
||
const { 'dist-tags': distTags } = await this.npmClient.getPackageInfo( | ||
sourceReleaseTag | ||
); | ||
|
||
Object.entries(distTags).forEach(([tagName, versionAtTag]) => { | ||
if (versionAtTag !== sourceVersion) { | ||
return; | ||
} | ||
const destReleaseTag = destReleaseTags.find((releaseTag) => | ||
releaseTag.includes(packageName) | ||
); | ||
if (!destReleaseTag) { | ||
// this should never happen because of the upstream logic that resolves the corresponding versions | ||
throw new Error( | ||
`No corresponding destination release tag found for ${sourceReleaseTag}` | ||
); | ||
} | ||
moveActions.push({ | ||
releaseTag: destReleaseTag, | ||
distTag: tagName, | ||
}); | ||
}); | ||
} | ||
|
||
for (const { distTag, releaseTag } of moveActions) { | ||
console.log(`Moving dist tag "${distTag}" to release tag ${releaseTag}`); | ||
await this.npmClient.setDistTag(releaseTag, distTag); | ||
console.log(`Done!${EOL}`); | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { EOL } from 'os'; | ||
import { GitClient } from './git_client.js'; | ||
import { NpmClient } from './npm_client.js'; | ||
import { GithubClient } from './github_client.js'; | ||
import { DistTagMover } from './dist_tag_mover.js'; | ||
|
||
/** | ||
* | ||
*/ | ||
export class ReleaseDeprecator { | ||
/** | ||
* Initialize with deprecation config and necessary clients | ||
*/ | ||
constructor( | ||
private readonly gitRefToStartReleaseSearchFrom: string, | ||
private readonly deprecationMessage: string, | ||
private readonly githubClient: GithubClient, | ||
private readonly gitClient: GitClient, | ||
private readonly npmClient: NpmClient, | ||
private readonly distTagMover: DistTagMover | ||
) {} | ||
|
||
/** | ||
* This method deprecates a set of package versions that were released by a single release commit. | ||
* | ||
* The steps that it takes are | ||
* 1. Given a starting commit, find the most recent release commit (this could be the commit itself) | ||
* 2. Find the git tags associated with that commit. These are the package versions that need to be deprecated | ||
* 3. Find the git tags associated with the previous versions of the packages that are being deprecated. These are the package versions that need to be marked as "latest" (or whatever the dist-tag for the release is) | ||
* 5. Creates a rollback PR that resets the .changeset directory to its state before the release | ||
* 6. Resets the dist-tags to the previous package versions | ||
* 7. Marks the current package versions as deprecated | ||
*/ | ||
deprecateRelease = async () => { | ||
await this.gitClient.ensureWorkingTreeIsClean(); | ||
|
||
const releaseCommitHashToDeprecate = | ||
await this.gitClient.getNearestReleaseCommit( | ||
this.gitRefToStartReleaseSearchFrom | ||
); | ||
|
||
const releaseTagsToDeprecate = await this.gitClient.getTagsAtCommit( | ||
releaseCommitHashToDeprecate | ||
); | ||
|
||
const previousReleaseTags = await this.gitClient.getPreviousReleaseTags( | ||
releaseCommitHashToDeprecate | ||
); | ||
|
||
// Create the changeset revert PR | ||
// This PR restores the changeset files that were part of the release but does NOT revert the package.json and changelog changes | ||
const prBranch = `revert_changeset/${releaseCommitHashToDeprecate}`; | ||
|
||
await this.gitClient.switchToBranch(prBranch); | ||
await this.gitClient.checkout(`${releaseCommitHashToDeprecate}^`, [ | ||
'.changeset', | ||
]); | ||
await this.gitClient.status(); | ||
await this.gitClient.commitAllChanges( | ||
`Reverting updates to the .changeset directory made by release commit ${releaseCommitHashToDeprecate}` | ||
); | ||
await this.gitClient.push({ force: true }); | ||
|
||
console.log(EOL); | ||
|
||
const { prUrl } = await this.githubClient.createPr({ | ||
head: prBranch, | ||
title: `Deprecate release ${releaseCommitHashToDeprecate}`, | ||
body: `Reverting updates to the .changeset directory made by release commit ${releaseCommitHashToDeprecate}`, | ||
}); | ||
|
||
console.log(`Created deprecation PR at ${prUrl}`); | ||
|
||
// 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 | ||
|
||
await this.distTagMover.moveDistTags( | ||
releaseTagsToDeprecate, | ||
previousReleaseTags | ||
); | ||
|
||
for (const releaseTag of releaseTagsToDeprecate) { | ||
console.log(`Deprecating package version ${releaseTag}`); | ||
await this.npmClient.deprecatePackage( | ||
releaseTag, | ||
this.deprecationMessage | ||
); | ||
console.log(`Done!${EOL}`); | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.