command.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. "use strict";
  2. const log = require("npmlog");
  3. const semver = require("semver");
  4. /**
  5. * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module
  6. */
  7. exports.command = "version [bump]";
  8. exports.describe = "Bump version of packages changed since the last release.";
  9. exports.builder = (yargs, composed) => {
  10. const opts = {
  11. "allow-branch": {
  12. describe: "Specify which branches to allow versioning from.",
  13. type: "array",
  14. },
  15. amend: {
  16. describe: "Amend the existing commit, instead of generating a new one.",
  17. type: "boolean",
  18. },
  19. "conventional-commits": {
  20. describe: "Use conventional-changelog to determine version bump and generate CHANGELOG.",
  21. type: "boolean",
  22. },
  23. "conventional-graduate": {
  24. describe: "Version currently prereleased packages to a non-prerelease version.",
  25. // type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
  26. },
  27. "conventional-prerelease": {
  28. describe: "Version changed packages as prereleases when using --conventional-commits.",
  29. // type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
  30. },
  31. "changelog-preset": {
  32. describe: "Custom conventional-changelog preset.",
  33. type: "string",
  34. requiresArg: true,
  35. defaultDescription: "angular",
  36. },
  37. exact: {
  38. describe: "Specify cross-dependency version numbers exactly rather than with a caret (^).",
  39. type: "boolean",
  40. },
  41. "force-publish": {
  42. describe: "Always include targeted packages in versioning operations, skipping default logic.",
  43. // type must remain ambiguous because it is overloaded (boolean _or_ string _or_ array)
  44. },
  45. "git-remote": {
  46. describe: "Push git changes to the specified remote.",
  47. type: "string",
  48. requiresArg: true,
  49. defaultDescription: "origin",
  50. },
  51. "create-release": {
  52. describe: "Create an official GitHub or GitLab release for every version.",
  53. type: "string",
  54. choices: ["gitlab", "github"],
  55. },
  56. "ignore-changes": {
  57. describe: [
  58. "Ignore changes in files matched by glob(s) when detecting changed packages.",
  59. "Pass --no-ignore-changes to completely disable.",
  60. ].join("\n"),
  61. type: "array",
  62. },
  63. "ignore-scripts": {
  64. describe: "Disable all lifecycle scripts",
  65. type: "boolean",
  66. },
  67. "include-merged-tags": {
  68. describe: "Include tags from merged branches when detecting changed packages.",
  69. type: "boolean",
  70. },
  71. m: {
  72. describe: "Use a custom commit message when creating the version commit.",
  73. alias: "message",
  74. type: "string",
  75. requiresArg: true,
  76. },
  77. "no-changelog": {
  78. describe: "Do not generate CHANGELOG.md files when using --conventional-commits.",
  79. type: "boolean",
  80. },
  81. changelog: {
  82. // proxy for --no-changelog
  83. hidden: true,
  84. type: "boolean",
  85. },
  86. "no-commit-hooks": {
  87. describe: "Do not run git commit hooks when committing version changes.",
  88. type: "boolean",
  89. },
  90. "commit-hooks": {
  91. // proxy for --no-commit-hooks
  92. hidden: true,
  93. type: "boolean",
  94. },
  95. "no-git-tag-version": {
  96. describe: "Do not commit or tag version changes.",
  97. type: "boolean",
  98. },
  99. "git-tag-version": {
  100. // proxy for --no-git-tag-version
  101. hidden: true,
  102. type: "boolean",
  103. },
  104. // TODO: (major) make --no-granular-pathspec the default
  105. "no-granular-pathspec": {
  106. describe: "Do not stage changes file-by-file, but globally.",
  107. type: "boolean",
  108. },
  109. "granular-pathspec": {
  110. // proxy for --no-granular-pathspec
  111. hidden: true,
  112. // describe: "Stage changes file-by-file, not globally.",
  113. type: "boolean",
  114. },
  115. // TODO: (major) make --no-private the default
  116. "no-private": {
  117. describe: "Do not version private packages.",
  118. type: "boolean",
  119. },
  120. private: {
  121. // proxy for --no-private
  122. hidden: true,
  123. type: "boolean",
  124. },
  125. "no-push": {
  126. describe: "Do not push tagged commit to git remote.",
  127. type: "boolean",
  128. },
  129. push: {
  130. // proxy for --no-push
  131. hidden: true,
  132. type: "boolean",
  133. },
  134. // preid is copied into ../publish/command because a whitelist for one option isn't worth it
  135. preid: {
  136. describe: "Specify the prerelease identifier when versioning a prerelease",
  137. type: "string",
  138. requiresArg: true,
  139. defaultDescription: "alpha",
  140. },
  141. "sign-git-commit": {
  142. describe: "Pass the `--gpg-sign` flag to `git commit`.",
  143. type: "boolean",
  144. },
  145. "sign-git-tag": {
  146. describe: "Pass the `--sign` flag to `git tag`.",
  147. type: "boolean",
  148. },
  149. "force-git-tag": {
  150. describe: "Pass the `--force` flag to `git tag`.",
  151. type: "boolean",
  152. },
  153. "tag-version-prefix": {
  154. describe: "Customize the tag prefix. To remove entirely, pass an empty string.",
  155. type: "string",
  156. requiresArg: true,
  157. defaultDescription: "v",
  158. },
  159. y: {
  160. describe: "Skip all confirmation prompts.",
  161. alias: "yes",
  162. type: "boolean",
  163. },
  164. };
  165. if (composed) {
  166. // hide options from composed command's help output
  167. Object.keys(opts).forEach((key) => {
  168. opts[key].hidden = true;
  169. });
  170. // set argv.composed for wrapped execution logic
  171. yargs.default("composed", composed).hide("composed");
  172. } else {
  173. exports.addBumpPositional(yargs);
  174. }
  175. yargs.options(opts);
  176. // workaround yargs bug that re-interprets unknown arguments in argv._
  177. yargs.parserConfiguration({
  178. "populate--": true,
  179. });
  180. if (!composed) {
  181. // hide options from composed command's help output
  182. yargs.group(Object.keys(opts), "Command Options:");
  183. }
  184. return yargs
  185. .option("ignore", {
  186. // TODO: remove in next major release
  187. // NOT the same as filter-options --ignore
  188. hidden: true,
  189. conflicts: "ignore-changes",
  190. type: "array",
  191. })
  192. .option("cd-version", {
  193. // TODO: remove in next major release
  194. hidden: true,
  195. conflicts: "bump",
  196. type: "string",
  197. requiresArg: true,
  198. })
  199. .option("repo-version", {
  200. // TODO: remove in next major release
  201. hidden: true,
  202. conflicts: "bump",
  203. type: "string",
  204. requiresArg: true,
  205. })
  206. .option("skip-git", {
  207. // TODO: remove in next major release
  208. hidden: true,
  209. type: "boolean",
  210. })
  211. .option("github-release", {
  212. // TODO: remove in next major release
  213. hidden: true,
  214. type: "boolean",
  215. })
  216. .check((argv) => {
  217. /* eslint-disable no-param-reassign */
  218. if (argv.ignore) {
  219. argv.ignoreChanges = argv.ignore;
  220. delete argv.ignore;
  221. log.warn("deprecated", "--ignore has been renamed --ignore-changes");
  222. }
  223. if (argv.cdVersion && !argv.bump) {
  224. argv.bump = argv.cdVersion;
  225. delete argv.cdVersion;
  226. delete argv["cd-version"];
  227. log.warn("deprecated", "--cd-version has been replaced by positional [bump]");
  228. }
  229. if (argv.repoVersion && !argv.bump) {
  230. argv.bump = argv.repoVersion;
  231. delete argv.repoVersion;
  232. delete argv["repo-version"];
  233. log.warn("deprecated", "--repo-version has been replaced by positional [bump]");
  234. }
  235. if (argv.skipGit) {
  236. argv.gitTagVersion = false;
  237. argv["git-tag-version"] = false;
  238. argv.push = false;
  239. delete argv.skipGit;
  240. delete argv["skip-git"];
  241. log.warn("deprecated", "--skip-git has been replaced by --no-git-tag-version --no-push");
  242. }
  243. if (argv.githubRelease) {
  244. argv.createRelease = "github";
  245. delete argv.githubRelease;
  246. log.warn("deprecated", "--github-release has been replaced by --create-release=github");
  247. }
  248. /* eslint-enable no-param-reassign */
  249. if (argv["--"]) {
  250. log.warn("EDOUBLEDASH", "Arguments after -- are no longer passed to subprocess executions.");
  251. log.warn("EDOUBLEDASH", "This will cause an error in a future major version.");
  252. }
  253. return argv;
  254. });
  255. };
  256. exports.handler = function handler(argv) {
  257. return require(".")(argv);
  258. };
  259. exports.addBumpPositional = function addBumpPositional(yargs, additionalKeywords = []) {
  260. const semverKeywords = ["major", "minor", "patch", "premajor", "preminor", "prepatch", "prerelease"].concat(
  261. additionalKeywords
  262. );
  263. const bumpOptionList = `'${semverKeywords.slice(0, -1).join("', '")}', or '${
  264. semverKeywords[semverKeywords.length - 1]
  265. }'.`;
  266. yargs.positional("bump", {
  267. describe: `Increment version(s) by explicit version _or_ semver keyword,\n${bumpOptionList}`,
  268. type: "string",
  269. coerce: (choice) => {
  270. if (!semver.valid(choice) && semverKeywords.indexOf(choice) === -1) {
  271. throw new Error(`bump must be an explicit version string _or_ one of: ${bumpOptionList}`);
  272. }
  273. return choice;
  274. },
  275. });
  276. };