recommend-version.js 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. "use strict";
  2. const conventionalRecommendedBump = require("conventional-recommended-bump");
  3. const log = require("npmlog");
  4. const semver = require("semver");
  5. const { getChangelogConfig } = require("./get-changelog-config");
  6. module.exports.recommendVersion = recommendVersion;
  7. /**
  8. * @param {import("@lerna/package").Package} pkg
  9. * @param {import("..").VersioningStrategy} type
  10. * @param {import("..").BaseChangelogOptions & { prereleaseId?: string }} commandOptions
  11. */
  12. function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix, prereleaseId }) {
  13. log.silly(type, "for %s at %s", pkg.name, pkg.location);
  14. const options = {
  15. path: pkg.location,
  16. };
  17. if (type === "independent") {
  18. options.lernaPackage = pkg.name;
  19. } else {
  20. // only fixed mode can have a custom tag prefix
  21. options.tagPrefix = tagPrefix;
  22. }
  23. const shouldBumpPrerelease = (releaseType, version) => {
  24. if (!semver.prerelease(version)) {
  25. return true;
  26. }
  27. switch (releaseType) {
  28. case "major":
  29. return semver.minor(version) !== 0 || semver.patch(version) !== 0;
  30. case "minor":
  31. return semver.patch(version) !== 0;
  32. default:
  33. return false;
  34. }
  35. };
  36. // Ensure potential ValidationError in getChangelogConfig() is propagated correctly
  37. let chain = Promise.resolve();
  38. chain = chain.then(() => getChangelogConfig(changelogPreset, rootPath));
  39. chain = chain.then((config) => {
  40. // "new" preset API
  41. options.config = config;
  42. return new Promise((resolve, reject) => {
  43. conventionalRecommendedBump(options, (err, data) => {
  44. if (err) {
  45. return reject(err);
  46. }
  47. // result might be undefined because some presets are not consistent with angular
  48. // we still need to bump _something_ because lerna saw a change here
  49. let releaseType = data.releaseType || "patch";
  50. if (prereleaseId) {
  51. const shouldBump = shouldBumpPrerelease(releaseType, pkg.version);
  52. const prereleaseType = shouldBump ? `pre${releaseType}` : "prerelease";
  53. log.verbose(type, "increment %s by %s", pkg.version, prereleaseType);
  54. resolve(semver.inc(pkg.version, prereleaseType, prereleaseId));
  55. } else {
  56. if (semver.major(pkg.version) === 0) {
  57. // According to semver, major version zero (0.y.z) is for initial
  58. // development. Anything MAY change at any time. The public API
  59. // SHOULD NOT be considered stable. The version 1.0.0 defines
  60. // the (initial stable) public API.
  61. //
  62. // To allow monorepos to use major version zero meaningfully,
  63. // the transition from 0.x to 1.x must be explicitly requested
  64. // by the user. Breaking changes MUST NOT automatically bump
  65. // the major version from 0.x to 1.x.
  66. //
  67. // The usual convention is to use semver-patch bumps for bugfix
  68. // releases and semver-minor for everything else, including
  69. // breaking changes. This matches the behavior of `^` operator
  70. // as implemented by `npm`.
  71. //
  72. if (releaseType === "major") {
  73. releaseType = "minor";
  74. }
  75. }
  76. log.verbose(type, "increment %s by %s", pkg.version, releaseType);
  77. resolve(semver.inc(pkg.version, releaseType));
  78. }
  79. });
  80. });
  81. });
  82. return chain;
  83. }