release-it / conventional-changelog

Conventional changelog plugin for release-it
MIT License
128 stars 38 forks source link

Ignore version bump for non-conventional commits #22

Open ivandov opened 3 years ago

ivandov commented 3 years ago

In most conventions supported with conventional-changelog, there are commit types that should not trigger a version bump.

For example, when using the angular or conventionalcommits preset, version bumps should only be applicable if using commits that begin with fix, feat, or other types that include a ! to signify a BREAKING CHANGE.

For commit messages that either do not conform to the types for the specified preset or are not one of the types listed above that signify a version change, release-it and this plugin should ignore the creation of a new semver release.

Is this achievable by this plug-in, since it overrides the standard version bump logic that happens in release-it?

webpro commented 3 years ago

The options provided to this plugin are sent to its underlying dependency: https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-recommended-bump#readme

However, at first glance I don't see an option for what you are trying to achieve. But maybe it's standard behavior?

ivandov commented 3 years ago

Right, my experience here was from using semantic-release and how it would ignore version bumps unless commit messages actually matched the criteria outlined in the convention specified.

webpro commented 3 years ago

Did a little bit of digging and testing, and I can see the conventional-recommended-bump dependency for this plugin gives only major, minor and patch. Never null or undefined, regardless of the commit messages:

{
  level: 2,
  reason: 'There are 0 BREAKING CHANGES and 0 features',
  releaseType: 'patch'
}

Only when a whatBump function is provided to parse the commits manually. However, that would defeat the whole purpose of this plugin, imho.

ivandov commented 3 years ago

As mentioned in release-it/release-it#798 by vonovak... This sounds like something that should be an optional flag for modifying the return types of conventional-recommended-bump.

I think that'd be a valid contribution if something along these lines doesn't already exist there. And, I'd also question how semantic-release is achieving its semver determination? Is there just a different library that can be used?

webpro commented 3 years ago

So there are a few options:

ivandov commented 3 years ago

I'm not sure any of these options provide a really good solution...

Implementing a whatBump() function that would properly handle all the conventions that this plugin support and conditionally ignoring a version bump if it doesn't meet some standard... would essentially be re-implementing a core piece of what conventional-recommended-bump likely already does internally.

To echo your sentiment:

Only when a whatBump function is provided to parse the commits manually. However, that would defeat the whole purpose of this plugin, imho.

Moving the getIncrementedVersion() method to another plugin seems like a misplaced solution that causes tight dependencies between plugins, which I imagine is not intended.

Adding a hook to the CLI command puts all the onus on the user of this plugin and is subject to significant user error.


Personally, I think this type of logic should really be a core feature in the conventional-recommended-bump library. I also looked through its interfaces and did not see any published mechanism for what would be needed here.

Haven't had a chance to look, but, I'd be curious what library semantic-release uses to handle this exact scenario internally... Did they code up their own?

webpro commented 3 years ago

Totally agreed.

Looks like semantic-release has a analyzeCommits step/plugin which parses commits itself (and potentially return null): https://github.com/semantic-release/commit-analyzer/blob/master/index.js

vonovak commented 2 years ago

Hello @webpro, I'm wondering, has this been fixed, or do you plan to fix it? I'd love to run release-it in CI but if it makes releases for commits that should not trigger one, it's not possible. Thank you 🙂

webpro commented 2 years ago

Looking into it again, I'm seeing basically all presets for recommended bump work the same. Here's the angular preset: https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-angular/conventional-recommended-bump.js (this is the whatBump function).

It always returns value 0, 1 or 2 for level, never null or undefined, always resulting in a value of this array here: https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-recommended-bump/index.js#L10

However, I just released a small update of release-it (warning: it's only in the upcoming release-it v15), which together with a custom whatBump option could do what you want. I've added a spec in this repo (warning: only in v5): https://github.com/release-it/conventional-changelog/commit/124351c3d05a98263b168bab5cca033942ec3edb

So, with release-it v15 and this plugin v5 this would allow something like this in .release-it.js:

module.exports = {
  plugins: {
    '@release-it/conventional-changelog': {
      whatBump: commits => ({ level: null, reason: 'Parsed commits do not warrant a version bump.' })
    }
  }
};

Still, you would need to properly implement the whatBump function.

(You could use this already using the esm npm dist tags. Planning to release the majors shortly, though.)

ivandov commented 2 years ago

@webpro How does your example code snippet leverage whatBump to properly decide when to send null for the level?

Are you suggesting that the function would be extended with additional conditional logic to properly determine when to set the null value?

webpro commented 2 years ago

@webpro How does your example code snippet leverage whatBump to properly decide when to send null for the level?

Are you suggesting that the function would be extended with additional conditional logic to properly determine when to set the null value?

My code example is only to indicate where the function fits in the release-it/plugin config.

So yes, additional logic is required, much like the original (linked to above).

jamesvillarrubia commented 1 year ago

Following up on this. I have created a whatBump that seems to align more with the intent of the angular preset and the semantic-release version.

Here's the function:

whatBump: (commits,options)=>{
          let defaults = {
            build: 'ignore',
            ci: 'ignore',
            docs: 'ignore',
            feat: 'minor',
            fix: 'patch',
            perf: 'patch',
            refactor: 'ignore',
            test: 'ignore'
          }
          let types = (options?.preset?.types || [])
          .reduce((a, v) => {
            return { ...a, [v.type]: v.release}
          }, {}) 

          types = Object.assign({},defaults,types)
          let breakings = 0
          let features = 0
          let levelSet = ['major','minor','patch','ignore']
          let level = Math.min.apply(Math, commits.map(commit => {
            let level = levelSet.indexOf(types[commit.type])
            level = level<0?3:level
            if (commit.notes.length > 0) {
              breakings += commit.notes.length
            }
            if(commit.type === 'feat'){
              features += 1;
            }
            return level
          }))

          return {
            level: level,
            reason: breakings === 1
              ? `There is ${breakings} BREAKING CHANGE and ${features} features`
              : `There are ${breakings} BREAKING CHANGES and ${features} features`
          }
}

You can then combine this with:

"preset": {
        "name": "conventionalcommits",
        "types": [
          {
            "type": "refactor",
            "release": "patch"
          },
          {
            "type": "style",
            "release": "patch"
          },
          {
            "type": "perf",
            "release": "patch"
          },
          {
            "type": "chore",
            "release": "patch"
          },
          {
            "type": "ci",
            "release": "patch"
          }
        ]
      }

This gives you the ability to override the specific types with one of ['major', 'minor', 'patch', 'ignore']. You can also set your own types.

jamesvillarrubia commented 1 year ago

I'm happy to make a PR if it's deemed appropriate. Possibly to the angular plugin or the conventionalcommit. @webpro

webpro commented 1 year ago

That would be nice, @jamesvillarrubia! Are you still up for this? Would be great to have options to ignore certain types of commits.

mogelbrod commented 1 year ago

Following up on this. I have created a whatBump that seems to align more with the intent of the angular preset and the semantic-release version.

Thanks for sharing! I might be wrong, but it doesn't look like the code does a major bump on ...!: ... and BREAKING CHANGES style commits?

webpro commented 1 year ago

Maybe the function can be extended; I'll be happy to add it to the docs or maybe even merge it into the codebase (with some logic/option to enable it).

Blackclaws commented 6 months ago

@webpro This function doesn't work for preRelease and null is ignored there. The . version is still being incremented.

borisdamevin commented 1 month ago

Hi,

Someone has any new about this issue?

Thank you.

Blackclaws commented 1 month ago

This is fixed in #102