From b794b17ed91d54ae6443d0c5a838885b78e2ab5a Mon Sep 17 00:00:00 2001 From: Artem Zakharchenko Date: Thu, 21 Apr 2022 17:53:30 +0200 Subject: [PATCH] feat: revert changes in case of errors --- src/commands/publish.ts | 100 ++++++++++++++++++++------------- src/utils/git/createRelease.ts | 6 ++ 2 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/commands/publish.ts b/src/commands/publish.ts index ce17e5f..43b7ffe 100644 --- a/src/commands/publish.ts +++ b/src/commands/publish.ts @@ -41,6 +41,10 @@ export class Publish extends Command { const branchName = await getCurrentBranch() console.log('preparing release from "%s"...', branchName) + /** + * @todo Check that the repo state is without uncommitted changes. + */ + // Get the latest release. const tags = await getTags() const latestRelease = await getLatestRelease(tags) @@ -112,53 +116,73 @@ export class Publish extends Command { console.log(publishResult.data) console.log('published successfully!') - // Create a release commit containing the version bump in package.json - const commitResult = await until(() => { - return createCommit({ - files: ['package.json'], - message: `chore: release ${nextVersion}`, + const revertQueue: Array<() => Promise> = [] + + const result = await until(async () => { + // Create a release commit containing the version bump in package.json + const commitResult = await until(() => { + return createCommit({ + files: ['package.json'], + message: `chore: release ${nextVersion}`, + }) }) - }) - invariant( - commitResult.error == null, - 'Failed to create release commit!\n', - commitResult.error - ) - console.log('created a release commit!') + invariant( + commitResult.error == null, + 'Failed to create release commit!\n', + commitResult.error + ) - // Create a Git tag for the release. - const tagResult = await until(() => createTag(nextVersion)) - invariant( - tagResult.error == null, - 'Failed to tag the release!\n', - tagResult.error - ) + revertQueue.push(async () => { + console.log('reverting the release commit...') + await execAsync('git reset --hard HEAD~1') + }) - console.log('created release tag "%s"!', tagResult.data) + console.log('created a release commit!') - // Push the release commit and tag to the origin. - const pushResult = await until(() => push()) - invariant( - pushResult.error == null, - 'Failed to push changes to origin!\n', - pushResult.error - ) + // Create a Git tag for the release. + const tagResult = await until(() => createTag(nextVersion)) - console.log('pushed changes to origin!') + invariant( + tagResult.error == null, + 'Failed to tag the release!\n', + tagResult.error + ) - // Generate release notes and create a new release on GitHub. - const releaseNotes = await getReleaseNotes(commits) - const releaseMarkdown = toMarkdown(context, releaseNotes) - console.log('generated release notes:\n\n', releaseMarkdown) + revertQueue.push(async () => { + console.log('reverting release tag...') + await execAsync(`git tag -d ${nextVersion}`) + }) - const releaseUrl = await createRelease(context, releaseMarkdown) - console.log('created release: %s', releaseUrl) + console.log('created release tag "%s"!', tagResult.data) - /** - * @todo Revert release tag/commit if anything fails - * after the tag point. - */ + // Push the release commit and tag to the origin. + const pushResult = await until(() => push()) + invariant( + pushResult.error == null, + 'Failed to push changes to origin!\n', + pushResult.error + ) + + console.log('pushed changes to origin!') + + // Generate release notes and create a new release on GitHub. + const releaseNotes = await getReleaseNotes(commits) + const releaseMarkdown = toMarkdown(context, releaseNotes) + console.log('generated release notes:\n\n', releaseMarkdown) + + const releaseUrl = await createRelease(context, releaseMarkdown) + console.log('created release: %s', releaseUrl) + }) + + if (result.error) { + // Revert changes in case of errors. + for (const revert of revertQueue) { + await revert() + } + + throw result.error + } console.log('release done!') } diff --git a/src/utils/git/createRelease.ts b/src/utils/git/createRelease.ts index 692a42e..e2d86de 100644 --- a/src/utils/git/createRelease.ts +++ b/src/utils/git/createRelease.ts @@ -16,6 +16,12 @@ export async function createRelease( ): Promise { const { repo } = context + console.log( + 'creating a new release at "%s/%s"...', + context.repo.owner, + context.repo.name + ) + const response = await fetch( `https://api.github.com/repos/${repo.owner}/${repo.name}/releases`, {