@entro314labs/release-kit 2.8.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +292 -50
  2. package/TRAIN.md +13 -0
  3. package/package.json +1 -1
  4. package/release.mjs +1257 -159
  5. package/train.mjs +18 -5
package/train.mjs CHANGED
@@ -99,20 +99,33 @@ export function bumpSemver(version, bump) {
99
99
  return `${v.major}.${v.minor}.${v.patch + 1}`
100
100
  }
101
101
 
102
+ /**
103
+ * A commit subject, by the same grammar release.mjs `parseCommit` reads. The two files are
104
+ * separate bins that share no module — release.mjs releases on import — so this is a
105
+ * deliberate copy, and it has to stay a faithful one: a train that infers a different bump
106
+ * than the release-kit run it delegates to plans a version it will not produce.
107
+ */
108
+ const CONVENTIONAL_SUBJECT = /^([a-z][a-z0-9-]*)(?:\([^)]+\))?(!)?: .+$/i
109
+
102
110
  /**
103
111
  * Conventional Commit derivation over full messages: feat → minor, a breaking change
104
- * (`!` in the type or a BREAKING CHANGE footer anywhere in the body) → major, softened
105
- * to minor below 1.0.0, else patch.
112
+ * (`!` in the type or a BREAKING CHANGE footer) → major, softened to minor below 1.0.0,
113
+ * else patch.
106
114
  */
107
115
  export function bumpFromCommits(messages, currentVersion) {
108
116
  let bump = 'patch'
109
117
  const below1 = parseSemver(currentVersion)?.major === 0
110
118
  for (const message of messages) {
111
- const subject = message.split('\n', 1)[0]
112
- if (/^[a-z]+(\([^)]*\))?!:/.test(subject) || /BREAKING CHANGE/.test(message)) {
119
+ const [subject, ...rest] = message.split('\n')
120
+ const match = CONVENTIONAL_SUBJECT.exec(subject.trim())
121
+ if (!match) continue
122
+ const [, type, bang] = match
123
+ // Anchored to a line of its own: a body that merely says "not a BREAKING CHANGE" is
124
+ // prose, and reading it as a footer releases a major nobody asked for.
125
+ if (bang || /^BREAKING[ -]CHANGE:/m.test(rest.join('\n'))) {
113
126
  return below1 ? 'minor' : 'major'
114
127
  }
115
- if (/^feat(\([^)]*\))?:/.test(subject)) bump = 'minor'
128
+ if (/^feat(ure)?$/.test(type.toLowerCase())) bump = 'minor'
116
129
  }
117
130
  return bump
118
131
  }