index.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. 'use strict'
  2. const concat = require('concat-stream')
  3. const conventionalCommitsFilter = require('conventional-commits-filter')
  4. const conventionalCommitsParser = require('conventional-commits-parser')
  5. const conventionalChangelogPresetLoader = require('conventional-changelog-preset-loader')
  6. const gitSemverTags = require('git-semver-tags')
  7. const gitRawCommits = require('git-raw-commits')
  8. const presetResolver = require('./preset-resolver')
  9. const VERSIONS = ['major', 'minor', 'patch']
  10. module.exports = conventionalRecommendedBump
  11. function conventionalRecommendedBump (optionsArgument, parserOptsArgument, cbArgument) {
  12. if (typeof optionsArgument !== 'object') {
  13. throw new Error('The \'options\' argument must be an object.')
  14. }
  15. const options = Object.assign({ ignoreReverted: true }, optionsArgument)
  16. const cb = typeof parserOptsArgument === 'function' ? parserOptsArgument : cbArgument
  17. if (typeof cb !== 'function') {
  18. throw new Error('You must provide a callback function.')
  19. }
  20. let presetPackage = options.config || {}
  21. if (options.preset) {
  22. try {
  23. presetPackage = conventionalChangelogPresetLoader(options.preset)
  24. } catch (err) {
  25. if (err.message === 'does not exist') {
  26. const preset = typeof options.preset === 'object' ? options.preset.name : options.preset
  27. return cb(new Error(`Unable to load the "${preset}" preset package. Please make sure it's installed.`))
  28. } else {
  29. return cb(err)
  30. }
  31. }
  32. }
  33. presetResolver(presetPackage).then(config => {
  34. const whatBump = options.whatBump ||
  35. ((config.recommendedBumpOpts && config.recommendedBumpOpts.whatBump)
  36. ? config.recommendedBumpOpts.whatBump
  37. : noop)
  38. if (typeof whatBump !== 'function') {
  39. throw Error('whatBump must be a function')
  40. }
  41. // TODO: For now we defer to `config.recommendedBumpOpts.parserOpts` if it exists, as our initial refactor
  42. // efforts created a `parserOpts` object under the `recommendedBumpOpts` object in each preset package.
  43. // In the future we want to merge differences found in `recommendedBumpOpts.parserOpts` into the top-level
  44. // `parserOpts` object and remove `recommendedBumpOpts.parserOpts` from each preset package if it exists.
  45. const parserOpts = Object.assign({},
  46. config.recommendedBumpOpts && config.recommendedBumpOpts.parserOpts
  47. ? config.recommendedBumpOpts.parserOpts
  48. : config.parserOpts,
  49. parserOptsArgument)
  50. const warn = typeof parserOpts.warn === 'function' ? parserOpts.warn : noop
  51. gitSemverTags({
  52. lernaTags: !!options.lernaPackage,
  53. package: options.lernaPackage,
  54. tagPrefix: options.tagPrefix,
  55. skipUnstable: options.skipUnstable
  56. }, (err, tags) => {
  57. if (err) {
  58. return cb(err)
  59. }
  60. gitRawCommits({
  61. format: '%B%n-hash-%n%H',
  62. from: tags[0] || '',
  63. path: options.path
  64. })
  65. .pipe(conventionalCommitsParser(parserOpts))
  66. .pipe(concat(data => {
  67. const commits = options.ignoreReverted ? conventionalCommitsFilter(data) : data
  68. if (!commits || !commits.length) {
  69. warn('No commits since last release')
  70. }
  71. let result = whatBump(commits, options)
  72. if (result && result.level != null) {
  73. result.releaseType = VERSIONS[result.level]
  74. } else if (result == null) {
  75. result = {}
  76. }
  77. cb(null, result)
  78. }))
  79. })
  80. }).catch(err => cb(err))
  81. }
  82. function noop () {}