@@ -20,16 +20,46 @@ async function Bump (args, version) {
20
20
configsToUpdate = { }
21
21
22
22
if ( args . skip . bump ) return version
23
+
24
+ if ( args . releaseAs && ! ( [ 'major' , 'minor' , 'patch' ] . includes ( args . releaseAs . toLowerCase ( ) ) || semver . valid ( args . releaseAs ) ) ) {
25
+ throw new Error ( "releaseAs must be one of 'major', 'minor' or 'patch', or a valid semvar version." )
26
+ }
27
+
23
28
let newVersion = version
24
29
await runLifecycleScript ( args , 'prerelease' )
25
30
const stdout = await runLifecycleScript ( args , 'prebump' )
26
- if ( stdout && stdout . trim ( ) . length ) args . releaseAs = stdout . trim ( )
27
- const release = await bumpVersion ( args . releaseAs , version , args )
31
+ if ( stdout ?. trim ( ) . length ) {
32
+ const prebumpString = stdout . trim ( )
33
+ if ( semver . valid ( prebumpString ) ) args . releaseAs = prebumpString
34
+ }
28
35
if ( ! args . firstRelease ) {
29
- const releaseType = getReleaseType ( args . prerelease , release . releaseType , version )
30
- const releaseTypeAsVersion = releaseType === 'pre' + release . releaseType ? semver . valid ( release . releaseType + '-' + args . prerelease + '.0' ) : semver . valid ( releaseType )
36
+ if ( semver . valid ( args . releaseAs ) ) {
37
+ const releaseAs = new semver . SemVer ( args . releaseAs )
38
+ if ( isString ( args . prerelease ) && releaseAs . prerelease . length && releaseAs . prerelease . slice ( 0 , - 1 ) . join ( '.' ) !== args . prerelease ) {
39
+ // If both releaseAs and the prerelease identifier are supplied, they must match. The behavior
40
+ // for a mismatch is undefined, so error out instead.
41
+ throw new Error ( 'releaseAs and prerelease have conflicting prerelease identifiers' )
42
+ } else if ( isString ( args . prerelease ) && releaseAs . prerelease . length ) {
43
+ newVersion = releaseAs . version
44
+ } else if ( isString ( args . prerelease ) ) {
45
+ newVersion = `${ releaseAs . major } .${ releaseAs . minor } .${ releaseAs . patch } -${ args . prerelease } .0`
46
+ } else {
47
+ newVersion = releaseAs . version
48
+ }
49
+
50
+ // Check if the previous version is the same version and prerelease, and increment if so
51
+ if ( isString ( args . prerelease ) && [ 'prerelease' , null ] . includes ( semver . diff ( version , newVersion ) ) && semver . lte ( newVersion , version ) ) {
52
+ newVersion = semver . inc ( version , 'prerelease' , args . prerelease )
53
+ }
31
54
32
- newVersion = releaseTypeAsVersion || semver . inc ( version , releaseType , args . prerelease )
55
+ // Append any build info from releaseAs
56
+ newVersion = semvarToVersionStr ( newVersion , releaseAs . build )
57
+ } else {
58
+ const release = await bumpVersion ( args . releaseAs , version , args )
59
+ const releaseType = getReleaseType ( args . prerelease , release . releaseType , version )
60
+
61
+ newVersion = semver . inc ( version , releaseType , args . prerelease )
62
+ }
33
63
updateConfigs ( args , newVersion )
34
64
} else {
35
65
checkpoint ( args , 'skip version bump on first release' , [ ] , chalk . red ( figures . cross ) )
@@ -42,6 +72,16 @@ Bump.getUpdatedConfigs = function () {
42
72
return configsToUpdate
43
73
}
44
74
75
+ /**
76
+ * Convert a semver object to a full version string including build metadata
77
+ * @param {string } semverVersion The semvar version string
78
+ * @param {string[] } semverBuild An array of the build metadata elements, to be joined with '.'
79
+ * @returns {string }
80
+ */
81
+ function semvarToVersionStr ( semverVersion , semverBuild ) {
82
+ return [ semverVersion , semverBuild . join ( '.' ) ] . filter ( Boolean ) . join ( '+' )
83
+ }
84
+
45
85
function getReleaseType ( prerelease , expectedReleaseType , currentVersion ) {
46
86
if ( isString ( prerelease ) ) {
47
87
if ( isInPrerelease ( currentVersion ) ) {
0 commit comments