Skip to content

Commit

Permalink
fix(release): allow dynamically continuing when current version is un…
Browse files Browse the repository at this point in the history
…resolvable (#28034)

(cherry picked from commit 5216f7a)
  • Loading branch information
JamesHenry authored and FrozenPandaz committed Sep 25, 2024
1 parent d6f223b commit a76b176
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"chalk": "^4.1.0",
"columnify": "^1.6.0",
"detect-port": "^1.5.1",
"enquirer": "~2.3.6",
"fast-glob": "3.2.7",
"ignore": "^5.0.4",
"js-tokens": "^4.0.0",
Expand Down
108 changes: 97 additions & 11 deletions packages/js/src/generators/release-version/release-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
writeJson,
} from '@nx/devkit';
import * as chalk from 'chalk';
import { prompt } from 'enquirer';
import { exec } from 'node:child_process';
import { rm } from 'node:fs/promises';
import { join } from 'node:path';
Expand Down Expand Up @@ -231,11 +232,26 @@ To fix this you will either need to add a package.json file at that location, or
spinner.stop();

if (options.fallbackCurrentVersionResolver === 'disk') {
logger.buffer(
`📄 Unable to resolve the current version from the registry ${registry}. Falling back to the version on disk of ${currentVersionFromDisk}`
);
currentVersion = currentVersionFromDisk;
currentVersionResolvedFromFallback = true;
if (
!currentVersionFromDisk &&
(options.specifierSource === 'conventional-commits' ||
options.specifierSource === 'version-plans')
) {
currentVersion = await handleNoAvailableDiskFallback({
logger,
projectName,
packageJsonPath,
specifierSource: options.specifierSource,
currentVersionSourceMessage: `from the registry ${registry}`,
resolutionSuggestion: `you should publish an initial version to the registry`,
});
} else {
logger.buffer(
`📄 Unable to resolve the current version from the registry ${registry}. Falling back to the version on disk of ${currentVersionFromDisk}`
);
currentVersion = currentVersionFromDisk;
currentVersionResolvedFromFallback = true;
}
} else {
throw new Error(
`Unable to resolve the current version from the registry ${registry}. Please ensure that the package exists in the registry in order to use the "registry" currentVersionResolver. Alternatively, you can use the --first-release option or set "release.version.generatorOptions.fallbackCurrentVersionResolver" to "disk" in order to fallback to the version on disk when the registry lookup fails.`
Expand All @@ -259,7 +275,7 @@ To fix this you will either need to add a package.json file at that location, or
currentVersion = currentVersionFromDisk;
if (!currentVersion) {
throw new Error(
`Unable to determine the current version for project "${project.name}" from ${packageJsonPath}`
`Unable to determine the current version for project "${project.name}" from ${packageJsonPath}, please ensure that the "version" field is set within the file`
);
}
logger.buffer(
Expand All @@ -281,11 +297,26 @@ To fix this you will either need to add a package.json file at that location, or
);
if (!latestMatchingGitTag) {
if (options.fallbackCurrentVersionResolver === 'disk') {
logger.buffer(
`📄 Unable to resolve the current version from git tag using pattern "${releaseTagPattern}". Falling back to the version on disk of ${currentVersionFromDisk}`
);
currentVersion = currentVersionFromDisk;
currentVersionResolvedFromFallback = true;
if (
!currentVersionFromDisk &&
(options.specifierSource === 'conventional-commits' ||
options.specifierSource === 'version-plans')
) {
currentVersion = await handleNoAvailableDiskFallback({
logger,
projectName,
packageJsonPath,
specifierSource: options.specifierSource,
currentVersionSourceMessage: `from git tag using pattern "${releaseTagPattern}"`,
resolutionSuggestion: `you should set an initial git tag on a relevant commit`,
});
} else {
logger.buffer(
`📄 Unable to resolve the current version from git tag using pattern "${releaseTagPattern}". Falling back to the version on disk of ${currentVersionFromDisk}`
);
currentVersion = currentVersionFromDisk;
currentVersionResolvedFromFallback = true;
}
} else {
throw new Error(
`No git tags matching pattern "${releaseTagPattern}" for project "${project.name}" were found. You will need to create an initial matching tag to use as a base for determining the next version. Alternatively, you can use the --first-release option or set "release.version.generatorOptions.fallbackCurrentVersionResolver" to "disk" in order to fallback to the version on disk when no matching git tags are found.`
Expand Down Expand Up @@ -993,3 +1024,58 @@ class ProjectLogger {
});
}
}

/**
* Allow users to be unblocked when locally running releases for the very first time with certain combinations that require an initial
* version in order to function (e.g. a relative semver bump derived via conventional commits or version plans) by providing an interactive
* prompt to let them opt into using 0.0.0 as the implied current version.
*/
async function handleNoAvailableDiskFallback({
logger,
projectName,
packageJsonPath,
specifierSource,
currentVersionSourceMessage,
resolutionSuggestion,
}: {
logger: ProjectLogger;
projectName: string;
packageJsonPath: string;
specifierSource: Exclude<
ReleaseVersionGeneratorSchema['specifierSource'],
'prompt'
>;
currentVersionSourceMessage: string;
resolutionSuggestion: string;
}): Promise<string> {
const unresolvableCurrentVersionError = new Error(
`Unable to resolve the current version ${currentVersionSourceMessage} and there is no version on disk to fall back to. This is invalid with ${specifierSource} because the new version is determined by relatively bumping the current version. To resolve this, ${resolutionSuggestion}, or set an appropriate value for "version" in ${packageJsonPath}`
);
if (process.env.CI === 'true') {
// We can't prompt in CI, so error immediately
throw unresolvableCurrentVersionError;
}
try {
const reply = await prompt<{ useZero: boolean }>([
{
name: 'useZero',
message: `\n${chalk.yellow(
`Warning: Unable to resolve the current version for "${projectName}" ${currentVersionSourceMessage} and there is no version on disk to fall back to. This is invalid with ${specifierSource} because the new version is determined by relatively bumping the current version.\n\nTo resolve this, ${resolutionSuggestion}, or set an appropriate value for "version" in ${packageJsonPath}`
)}. \n\nAlternatively, would you like to continue now by using 0.0.0 as the current version?`,
type: 'confirm',
initial: false,
},
]);
if (!reply.useZero) {
// Throw any error to skip the fallback to 0.0.0, may as well use the one we already have
throw unresolvableCurrentVersionError;
}
const currentVersion = '0.0.0';
logger.buffer(
`📄 Forcibly resolved the current version as "${currentVersion}" based on your response to the prompt above.`
);
return currentVersion;
} catch {
throw unresolvableCurrentVersionError;
}
}

0 comments on commit a76b176

Please sign in to comment.