conventional_commits 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/README.md +22 -1
- data/exe/conventional_commits +1 -0
- data/lib/cli/branch_name_cli.rb +12 -0
- data/lib/conventional_commits/version.rb +1 -1
- data/lib/git/git.rb +10 -0
- data/lib/models/release_rule.rb +3 -2
- data/lib/release/next_version_calculator.rb +85 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8ef389be49918b12a03941a89178003c8b6ba9962583516728948bb1c61d5557
|
|
4
|
+
data.tar.gz: e4e5c3dd45bb0e3c140b9519dcd76f432fc7812012402dde8a4a643da8318c9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d8435aa0ae03a4ab74880debbec1f7a925b39a972337a17432234f64907e97388b82d48692f58ac16f2d7566dd0f0d96e365ef2ef86940e5ea6372fd59eb5ad8
|
|
7
|
+
data.tar.gz: 5cc8f961cc6ce9296f0348fe6d200c53edbfb10996320065d3b3ae045125177204aa3a01a1be062b861c95561dc828e0c19236a1400bd0015f8d15f353df2971
|
data/README.md
CHANGED
|
@@ -55,8 +55,29 @@ to create a new branch
|
|
|
55
55
|
- `pattern` - is used to define the separators between in future it will be used to define the order as well
|
|
56
56
|
- `type` - is used for mapping combination of short names for the type of request. Helps to avoid inconsistency.
|
|
57
57
|
|
|
58
|
+
### Validating in CI
|
|
59
|
+
The hooks validate the current branch and `.git/COMMIT_EDITMSG`. In CI, pass them explicitly:
|
|
60
|
+
|
|
61
|
+
$ conventional_commits validate_branch --branch "$GITHUB_HEAD_REF"
|
|
62
|
+
$ conventional_commits validate_commit_msg --msg "$(git log -1 --format=%B "$SHA")"
|
|
63
|
+
|
|
64
|
+
With a detached `HEAD` and no `--branch`, `validate_branch` falls back to `$GITHUB_HEAD_REF`.
|
|
65
|
+
|
|
58
66
|
### Release
|
|
59
|
-
|
|
67
|
+
`next_version` prints the next version from the commits since the latest version tag
|
|
68
|
+
(`X.Y.Z` or `vX.Y.Z`), following `release.rules`:
|
|
69
|
+
|
|
70
|
+
$ conventional_commits next_version
|
|
71
|
+
0.3.1
|
|
72
|
+
|
|
73
|
+
- Each commit's type is matched against the rules' types; aliases from `type` count as their
|
|
74
|
+
main type, so a `ref:` commit matches a rule listing `refactor`.
|
|
75
|
+
- A breaking change — `type!:` in the subject or a `BREAKING CHANGE:` footer — uses the rule
|
|
76
|
+
for `breaking`.
|
|
77
|
+
- The biggest bump of all the commits wins (`major` > `minor` > `patch`); `version: none`, or a
|
|
78
|
+
type without a rule, produces no release.
|
|
79
|
+
- It prints nothing when no commit calls for a release, and `--initial` (default `0.1.0`) when
|
|
80
|
+
there is no version tag yet.
|
|
60
81
|
|
|
61
82
|
|
|
62
83
|
## Development
|
data/exe/conventional_commits
CHANGED
data/lib/cli/branch_name_cli.rb
CHANGED
|
@@ -70,6 +70,18 @@ module ConventionalCommits
|
|
|
70
70
|
raise Thor::Error, e.message
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
desc "next_version", "prints the next release version from the commits since the latest version tag"
|
|
74
|
+
option :cfg_path, type: :string, required: false
|
|
75
|
+
option :initial, type: :string, required: false, desc: "Version to print when there is no version tag yet (default 0.1.0)"
|
|
76
|
+
def next_version
|
|
77
|
+
cfg_path = options["cfg_path"] || Configuration::DEFAULT_CONFIGURATION_PATH
|
|
78
|
+
version = ConventionalCommits::NextVersionCalculator.new
|
|
79
|
+
.next_version(cfg_path:, initial: options["initial"] || "0.1.0")
|
|
80
|
+
puts version if version
|
|
81
|
+
rescue StandardError => e
|
|
82
|
+
raise Thor::Error, e.message
|
|
83
|
+
end
|
|
84
|
+
|
|
73
85
|
desc "install_hooks", "install all git hooks"
|
|
74
86
|
def install_hooks
|
|
75
87
|
installer = ConventionalCommits::Configuration::HooksInstaller.new
|
data/lib/git/git.rb
CHANGED
|
@@ -10,6 +10,16 @@ module ConventionalCommits
|
|
|
10
10
|
run_system_command "git symbolic-ref --short HEAD"
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def tags
|
|
14
|
+
run_system_command("git tag --list").split("\n").map(&:strip).reject(&:empty?)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Full messages of the commits reachable from HEAD but not from `ref`, newest first.
|
|
18
|
+
def commit_messages_since(ref)
|
|
19
|
+
run_system_command("git log --format=%B%x00 #{ref}..HEAD")
|
|
20
|
+
.split("\x00").map(&:strip).reject(&:empty?)
|
|
21
|
+
end
|
|
22
|
+
|
|
13
23
|
def run_system_command(_cmd)
|
|
14
24
|
Open3.popen3(_cmd) { |_stdin, stdout, _stderr, _wait_thr| stdout.read }
|
|
15
25
|
end
|
data/lib/models/release_rule.rb
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module ConventionalCommits
|
|
4
4
|
module Configuration
|
|
5
|
-
#
|
|
5
|
+
# A release rule: which commit types produce which version bump
|
|
6
6
|
class ReleaseRule
|
|
7
7
|
attr_reader :types, :version
|
|
8
8
|
|
|
9
|
+
# Accepts both `types: [..]` and the singular `type: ..` used for the breaking rule.
|
|
9
10
|
def initialize(options = {})
|
|
10
|
-
@types = options["types"] || []
|
|
11
|
+
@types = Array(options["types"] || options["type"])
|
|
11
12
|
@version = options["version"] || "none"
|
|
12
13
|
end
|
|
13
14
|
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ConventionalCommits
|
|
4
|
+
# Works out the next release version from the commits since the latest version tag, using the
|
|
5
|
+
# `release.rules` of the configuration: each commit's type (aliases included) maps to a bump,
|
|
6
|
+
# and the biggest bump wins. A breaking change (`type!:` or a `BREAKING CHANGE:` footer) uses
|
|
7
|
+
# the rule for the `breaking` type.
|
|
8
|
+
class NextVersionCalculator
|
|
9
|
+
VERSION_TAG = /\Av?\d+\.\d+\.\d+\z/
|
|
10
|
+
SUBJECT = /\A(?<type>[A-Za-z]+)(?:\([^)]*\))?(?<breaking>!)?:/
|
|
11
|
+
BREAKING_FOOTER = /^BREAKING[ -]CHANGE:/
|
|
12
|
+
BREAKING_TYPE = "breaking"
|
|
13
|
+
BUMPS = %w[none patch minor major].freeze
|
|
14
|
+
|
|
15
|
+
attr_reader :git, :reader
|
|
16
|
+
|
|
17
|
+
def initialize(git: Git.new, reader: Configuration::MainConfigurationReader.new)
|
|
18
|
+
@git = git
|
|
19
|
+
@reader = reader
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# The next version as "X.Y.Z", `initial` when there is no version tag yet, or nil when no
|
|
23
|
+
# commit since the latest tag calls for a release.
|
|
24
|
+
def next_version(cfg_path: Configuration::DEFAULT_CONFIGURATION_PATH, initial: "0.1.0")
|
|
25
|
+
tag = latest_version_tag
|
|
26
|
+
return initial if tag.nil?
|
|
27
|
+
|
|
28
|
+
config = reader.get_configuration(path: cfg_path)
|
|
29
|
+
bumps = git.commit_messages_since(tag).map { |message| bump_for(message, config) }
|
|
30
|
+
bumped(tag, bumps.max_by { |bump| BUMPS.index(bump) } || "none")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def latest_version_tag
|
|
36
|
+
git.tags.grep(VERSION_TAG).max_by { |tag| Gem::Version.new(tag.delete_prefix("v")) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def bump_for(message, config)
|
|
40
|
+
subject = SUBJECT.match(message.lines.first.to_s.strip)
|
|
41
|
+
return "none" if subject.nil?
|
|
42
|
+
|
|
43
|
+
if subject[:breaking] || message.match?(BREAKING_FOOTER)
|
|
44
|
+
rule_bump(BREAKING_TYPE, config) || type_bump(subject[:type], config)
|
|
45
|
+
else
|
|
46
|
+
type_bump(subject[:type], config)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def type_bump(type, config)
|
|
51
|
+
rule_bump(main_type(type.downcase, config), config) || "none"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def rule_bump(type, config)
|
|
55
|
+
rule = config.release.rules.find do |candidate|
|
|
56
|
+
candidate.types.map { |rule_type| main_type(rule_type.to_s, config) }.include?(type)
|
|
57
|
+
end
|
|
58
|
+
rule && validated(rule.version)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Rule types and commit types may be aliases ("feature", "ref"); both sides compare as the
|
|
62
|
+
# configured main type. `breaking` and unknown types stay as they are.
|
|
63
|
+
def main_type(type, config)
|
|
64
|
+
main = config.type.main_type(type)
|
|
65
|
+
main.to_s.empty? ? type : main
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def validated(bump)
|
|
69
|
+
raise GenericError, "Unknown release version '#{bump}', expected one of #{BUMPS}" unless BUMPS.include?(bump)
|
|
70
|
+
|
|
71
|
+
bump
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def bumped(tag, bump)
|
|
75
|
+
return nil if bump == "none"
|
|
76
|
+
|
|
77
|
+
major, minor, patch = tag.delete_prefix("v").split(".").map(&:to_i)
|
|
78
|
+
case bump
|
|
79
|
+
when "major" then "#{major + 1}.0.0"
|
|
80
|
+
when "minor" then "#{major}.#{minor + 1}.0"
|
|
81
|
+
else "#{major}.#{minor}.#{patch + 1}"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: conventional_commits
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Swift-Gurus
|
|
@@ -129,6 +129,7 @@ files:
|
|
|
129
129
|
- lib/models/release_configuration.rb
|
|
130
130
|
- lib/models/release_rule.rb
|
|
131
131
|
- lib/models/type_configuration.rb
|
|
132
|
+
- lib/release/next_version_calculator.rb
|
|
132
133
|
- sig/conventional_commit/branch_name_generator.rbs
|
|
133
134
|
- sig/conventional_commits.rbs
|
|
134
135
|
- sig/conventional_commits/branch_name_cli.rbs
|