schmersion 1.0.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 +7 -0
- data/VERSION +1 -0
- data/bin/schmersion +20 -0
- data/cli/help.rb +21 -0
- data/cli/init.rb +49 -0
- data/cli/lint-prepare.rb +14 -0
- data/cli/lint-validate.rb +28 -0
- data/cli/log.rb +28 -0
- data/cli/pending.rb +49 -0
- data/cli/release.rb +40 -0
- data/cli/setup-linting.rb +22 -0
- data/cli/versions.rb +14 -0
- data/lib/schmersion.rb +4 -0
- data/lib/schmersion/commit.rb +23 -0
- data/lib/schmersion/commit_parser.rb +60 -0
- data/lib/schmersion/config.rb +67 -0
- data/lib/schmersion/error.rb +6 -0
- data/lib/schmersion/formatter.rb +30 -0
- data/lib/schmersion/formatters.rb +15 -0
- data/lib/schmersion/formatters/markdown.rb +108 -0
- data/lib/schmersion/formatters/yaml.rb +63 -0
- data/lib/schmersion/helpers.rb +32 -0
- data/lib/schmersion/host.rb +25 -0
- data/lib/schmersion/hosts.rb +25 -0
- data/lib/schmersion/hosts/github.rb +50 -0
- data/lib/schmersion/linter.rb +147 -0
- data/lib/schmersion/message.rb +95 -0
- data/lib/schmersion/message_validator.rb +67 -0
- data/lib/schmersion/releaser.rb +135 -0
- data/lib/schmersion/repo.rb +127 -0
- data/lib/schmersion/schmersion_version.rb +12 -0
- data/lib/schmersion/version.rb +32 -0
- data/lib/schmersion/version_calculator.rb +71 -0
- metadata +207 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b913b0f1449212f78614fa4d033a16ee85a839d9992b847978869c35dc4dfc29
|
4
|
+
data.tar.gz: a1452b8b38d15ce8676e20dca1ef936d783b1a66124ab7eedb054a8220cf80e9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 380925581f98a27eb2b5fb45ab4a0e2e1b09dce184040881e8c4bf8541a71e7d74915e18cae2b09580e2454ab801e959be82ff84d3f005c9258d48079193da9e
|
7
|
+
data.tar.gz: 27720896c464ed1d871cd7841e0caa7b705135d23efe3cdc14db9644eac65b91dcae3b2588e42dabc9778f0724025189a1c3bc857afc4db3f5b8376c3744a13f
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/bin/schmersion
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
5
|
+
|
6
|
+
require 'schmersion'
|
7
|
+
require 'swamp/cli'
|
8
|
+
require 'git'
|
9
|
+
require 'colorize'
|
10
|
+
|
11
|
+
begin
|
12
|
+
cli = Swamp::CLI.new(:schmersion, version: Schmersion::VERSION)
|
13
|
+
cli.load_from_directory(File.expand_path('../cli', __dir__))
|
14
|
+
cli.dispatch(ARGV.empty? ? ['help'] : ARGV)
|
15
|
+
rescue Swamp::Error, Git::GitExecuteError, Schmersion::Error => e
|
16
|
+
warn "\e[31mError: #{e.message}\e[0m"
|
17
|
+
exit 2
|
18
|
+
rescue Interrupt
|
19
|
+
exit 3
|
20
|
+
end
|
data/cli/help.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :help do
|
4
|
+
desc 'Display this help text'
|
5
|
+
action do |context|
|
6
|
+
puts "\e[35mWelcome to Schmersion v#{Schmersion::VERSION}\e[0m"
|
7
|
+
puts 'For documentation see https://github.com/krystal/schmersion.'
|
8
|
+
puts
|
9
|
+
|
10
|
+
puts 'The following commands are supported:'
|
11
|
+
puts
|
12
|
+
context.cli.commands.sort_by { |k, _v| k.to_s }.each do |_, command|
|
13
|
+
if command.description
|
14
|
+
puts " \e[36m#{command.name.to_s.ljust(18, ' ')}\e[0m #{command.description}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
puts
|
18
|
+
puts 'For details for the options available for each command, use the --help option.'
|
19
|
+
puts "For example 'schmersion pending --help'."
|
20
|
+
end
|
21
|
+
end
|
data/cli/init.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :init do
|
4
|
+
desc 'Create a .schmersion.yml config file'
|
5
|
+
|
6
|
+
option '-f', '--force', 'Override existing hooks if they exist' do |_, options|
|
7
|
+
options[:force] = true
|
8
|
+
end
|
9
|
+
|
10
|
+
action do |context|
|
11
|
+
if File.exist?('.schmersion.yaml') && !context.options[:force]
|
12
|
+
puts 'A file already exists at .schmersion.yaml'
|
13
|
+
puts 'Use --force if you wish to re-generate it.'
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
example = <<~EXAMPLE
|
18
|
+
# Welcome to the Schmersion config file
|
19
|
+
#
|
20
|
+
# This is an array of all the commit types that are supported. You can
|
21
|
+
# override this to define your own set as needed per-project.
|
22
|
+
#
|
23
|
+
# types: [feat, fix, style, chore, test, refactor, perf, docs, ci, build, revert]
|
24
|
+
#
|
25
|
+
# By default, you can use any scope (the word in brackets following the type).
|
26
|
+
# If you wish to restrict this, you can define a list of valid scopes.
|
27
|
+
# scopes: [auth, api, ...]
|
28
|
+
#
|
29
|
+
# A key part of the configuration is how you wish to export your CHANGELOG files.w
|
30
|
+
exports:
|
31
|
+
- name: CHANGELOG.md
|
32
|
+
formatter: markdown
|
33
|
+
options:
|
34
|
+
title: CHANGELOG
|
35
|
+
description: This file contains all the latest changes and updates to this application.
|
36
|
+
sections:
|
37
|
+
- title: Features
|
38
|
+
types: [feat]
|
39
|
+
- title: Bug Fixes
|
40
|
+
types: [fix]
|
41
|
+
#
|
42
|
+
# There are additional options you can define, check out the README for details.
|
43
|
+
# https://github.com/krystal/schmersion
|
44
|
+
EXAMPLE
|
45
|
+
|
46
|
+
File.write('.schmersion.yaml', example)
|
47
|
+
puts 'Created new .schmersion.yaml file'.green
|
48
|
+
end
|
49
|
+
end
|
data/cli/lint-prepare.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# rubocop:disable Naming/FileName
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
command :'lint-prepare' do
|
5
|
+
action do |context|
|
6
|
+
require 'schmersion/repo'
|
7
|
+
require 'schmersion/linter'
|
8
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
9
|
+
linter = Schmersion::Linter.new(repo)
|
10
|
+
linter.prepare(context.args[0], context.args[1])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# rubocop:enable Naming/FileName
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# rubocop:disable Naming/FileName
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
command :'lint-validate' do
|
5
|
+
action do |context|
|
6
|
+
require 'schmersion/repo'
|
7
|
+
require 'schmersion/linter'
|
8
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
9
|
+
linter = Schmersion::Linter.new(repo)
|
10
|
+
errors = linter.validate_file(context.args[0])
|
11
|
+
if errors.empty?
|
12
|
+
exit 0
|
13
|
+
end
|
14
|
+
|
15
|
+
puts
|
16
|
+
puts ' Schmersion Commit Linting'.cyan
|
17
|
+
puts
|
18
|
+
puts " Uh oh. There's a few things wrong with your commit message...".red
|
19
|
+
puts ' Please correct these and re-commit to continue.'.red
|
20
|
+
puts
|
21
|
+
errors.each do |error|
|
22
|
+
puts " => #{error}"
|
23
|
+
end
|
24
|
+
puts
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# rubocop:enable Naming/FileName
|
data/cli/log.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :log do
|
4
|
+
desc 'Print all commits in a range nicely'
|
5
|
+
|
6
|
+
option '--from [REF]', 'Commit to start from (default: beginning of time)' do |value, options|
|
7
|
+
options[:from] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
option '--to [REF]', 'Commit to finish with (default: current branch)' do |value, options|
|
11
|
+
options[:to] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
action do |context|
|
15
|
+
require 'schmersion/repo'
|
16
|
+
require 'schmersion/helpers'
|
17
|
+
require 'colorize'
|
18
|
+
|
19
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
20
|
+
|
21
|
+
from = context.options[:from] || :start
|
22
|
+
to = context.options[:to] || repo.current_branch
|
23
|
+
|
24
|
+
commits = repo.commits(from, to, exclude_with_invalid_messages: true)
|
25
|
+
|
26
|
+
Schmersion::Helpers.print_commit_list(commits)
|
27
|
+
end
|
28
|
+
end
|
data/cli/pending.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :pending do
|
4
|
+
desc 'Displays commits pending'
|
5
|
+
|
6
|
+
option '--from [REF]', 'Version to start from (default: latest version)' do |value, options|
|
7
|
+
options[:from] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
option '--to [REF]', 'Commit to end at (default: HEAD)' do |value, options|
|
11
|
+
options[:to] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
option '--pre [PREFIX]', 'Create a pre-release version' do |value, options|
|
15
|
+
options[:pre] = value || true
|
16
|
+
end
|
17
|
+
|
18
|
+
action do |context|
|
19
|
+
require 'schmersion/repo'
|
20
|
+
require 'schmersion/helpers'
|
21
|
+
|
22
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
23
|
+
current_version, next_version = repo.pending_version(
|
24
|
+
from: context.options[:from],
|
25
|
+
to: context.options[:to],
|
26
|
+
version_options: {
|
27
|
+
pre: context.options[:pre]
|
28
|
+
}
|
29
|
+
)
|
30
|
+
|
31
|
+
puts
|
32
|
+
if current_version
|
33
|
+
puts 'The current published version is:'
|
34
|
+
puts
|
35
|
+
puts " #{current_version.to_s.cyan}"
|
36
|
+
puts
|
37
|
+
puts 'The next version will be:'
|
38
|
+
else
|
39
|
+
puts 'The first version will be:'
|
40
|
+
end
|
41
|
+
puts
|
42
|
+
puts " #{next_version.version.to_s.green}"
|
43
|
+
puts
|
44
|
+
puts 'The following commits will be included:'
|
45
|
+
puts
|
46
|
+
Schmersion::Helpers.print_commit_list(next_version.commits, prefix: ' ')
|
47
|
+
puts
|
48
|
+
end
|
49
|
+
end
|
data/cli/release.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :release do
|
4
|
+
desc 'Create a release'
|
5
|
+
|
6
|
+
option '-r [VERSION]', 'Override the version number' do |value, options|
|
7
|
+
options[:version] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
option '--dry-run', "Don't actually do anything, just show a preview" do |_, options|
|
11
|
+
options[:dry_run] = true
|
12
|
+
end
|
13
|
+
|
14
|
+
option '--pre [PREFIX]', 'Create a pre-release version' do |value, options|
|
15
|
+
options[:pre] = value || true
|
16
|
+
end
|
17
|
+
|
18
|
+
option '--skip-export', "Don't generate new CHANGELOG exports" do |_, options|
|
19
|
+
options[:skips] ||= []
|
20
|
+
options[:skips] << :export
|
21
|
+
end
|
22
|
+
|
23
|
+
option '--skip-commit', "Don't commit anything" do |_, options|
|
24
|
+
options[:skips] ||= []
|
25
|
+
options[:skips] << :commit
|
26
|
+
end
|
27
|
+
|
28
|
+
option '--skip-tag', "Don't create a tag" do |_, options|
|
29
|
+
options[:skips] ||= []
|
30
|
+
options[:skips] << :tag
|
31
|
+
end
|
32
|
+
|
33
|
+
action do |context|
|
34
|
+
require 'schmersion/repo'
|
35
|
+
require 'schmersion/releaser'
|
36
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
37
|
+
releaser = Schmersion::Releaser.new(repo, context.options)
|
38
|
+
releaser.release
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# rubocop:disable Naming/FileName
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
command :'setup-linting' do
|
5
|
+
desc 'Install git hooks to lint commit messages'
|
6
|
+
|
7
|
+
option '-f', '--force', 'Override existing hooks if they exist' do |_, options|
|
8
|
+
options[:force] = true
|
9
|
+
end
|
10
|
+
|
11
|
+
action do |context|
|
12
|
+
require 'schmersion/repo'
|
13
|
+
require 'schmersion/linter'
|
14
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
15
|
+
linter = Schmersion::Linter.new(repo)
|
16
|
+
linter.setup(force: context.options[:force])
|
17
|
+
|
18
|
+
puts 'Installed hooks successfully'.green
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# rubocop:enable Naming/FileName
|
data/cli/versions.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
command :versions do
|
4
|
+
desc 'Print a list of all versions in version order'
|
5
|
+
action do
|
6
|
+
require 'schmersion/repo'
|
7
|
+
require 'colorize'
|
8
|
+
|
9
|
+
repo = Schmersion::Repo.new(FileUtils.pwd)
|
10
|
+
repo.versions.each do |version, _|
|
11
|
+
puts version
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/schmersion.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'schmersion/message'
|
4
|
+
|
5
|
+
module Schmersion
|
6
|
+
class Commit
|
7
|
+
|
8
|
+
attr_reader :message
|
9
|
+
attr_reader :ref
|
10
|
+
attr_reader :date
|
11
|
+
attr_reader :author
|
12
|
+
attr_reader :raw_commit
|
13
|
+
|
14
|
+
def initialize(commit)
|
15
|
+
@message = Message.new(commit.message)
|
16
|
+
@ref = commit.sha
|
17
|
+
@date = commit.date
|
18
|
+
@author = commit.author.name
|
19
|
+
@raw_commit = commit
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'schmersion/commit'
|
4
|
+
require 'schmersion/version_calculator'
|
5
|
+
|
6
|
+
module Schmersion
|
7
|
+
class CommitParser
|
8
|
+
|
9
|
+
MAX_COMMITS = 100_000_000
|
10
|
+
|
11
|
+
attr_reader :commits
|
12
|
+
|
13
|
+
def initialize(repo, start_commit, end_commit, **options)
|
14
|
+
@start_commit = start_commit
|
15
|
+
@end_commit = end_commit
|
16
|
+
@options = options
|
17
|
+
|
18
|
+
@commits = []
|
19
|
+
|
20
|
+
if @start_commit == :start
|
21
|
+
# If start is provided, use the first commit as the initial reference.
|
22
|
+
# Ideally this would actually start from the beginning of time and include
|
23
|
+
# this commit.
|
24
|
+
first_commit = repo.log(MAX_COMMITS).last
|
25
|
+
@start_commit = first_commit.sha
|
26
|
+
end
|
27
|
+
|
28
|
+
@raw_commits = repo.log(MAX_COMMITS).between(@start_commit, @end_commit)
|
29
|
+
|
30
|
+
parse
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse
|
34
|
+
@commits = []
|
35
|
+
@raw_commits.each do |commit|
|
36
|
+
commit = Commit.new(commit)
|
37
|
+
|
38
|
+
next if skip_commit?(commit)
|
39
|
+
|
40
|
+
@commits << commit
|
41
|
+
end
|
42
|
+
@commits = @commits.reverse
|
43
|
+
@commits
|
44
|
+
end
|
45
|
+
|
46
|
+
def next_version_after(current_version, **options)
|
47
|
+
calculator = VersionCalculator.new(current_version, commits, **options)
|
48
|
+
calculator.calculate
|
49
|
+
end
|
50
|
+
|
51
|
+
def skip_commit?(commit)
|
52
|
+
# We never want to see merge commits...
|
53
|
+
return true if commit.raw_commit.parents.size > 1
|
54
|
+
return true unless commit.message.valid?
|
55
|
+
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Schmersion
|
4
|
+
class Config
|
5
|
+
|
6
|
+
DEFAULT_TYPES = %w[feat fix style chore test refactor perf docs ci build revert].freeze
|
7
|
+
|
8
|
+
DEFAULT_VERSION_OPTIONS = {
|
9
|
+
breaking_change_not_major: false
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
DEFAULT_LINTING_OPTIONS = {
|
13
|
+
max_description_length: 60
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
def initialize(hash)
|
17
|
+
@hash = hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def types
|
21
|
+
@hash['types'] || DEFAULT_TYPES
|
22
|
+
end
|
23
|
+
|
24
|
+
def valid_type?(type)
|
25
|
+
return true if types.empty?
|
26
|
+
|
27
|
+
types.include?(type.to_s)
|
28
|
+
end
|
29
|
+
|
30
|
+
def scopes
|
31
|
+
@hash['scopes'] || []
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid_scope?(scope)
|
35
|
+
return true if scopes.empty?
|
36
|
+
|
37
|
+
scopes.include?(scope.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def exports
|
41
|
+
return [] if @hash['exports'].nil?
|
42
|
+
|
43
|
+
@hash['exports'].map { |e| create_export(e) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def linting
|
47
|
+
DEFAULT_LINTING_OPTIONS.merge(@hash['linting']&.transform_keys(&:to_sym) || {})
|
48
|
+
end
|
49
|
+
|
50
|
+
def version_options
|
51
|
+
DEFAULT_VERSION_OPTIONS.merge(@hash['version_options']&.transform_keys(&:to_sym) || {})
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def create_export(export)
|
57
|
+
name = export['name']
|
58
|
+
formatter = Formatters::FORMATTERS[export['formatter'].to_sym]
|
59
|
+
if formatter.nil?
|
60
|
+
raise Error, "Invalid formatter '#{export['formatter']}' for #{name}"
|
61
|
+
end
|
62
|
+
|
63
|
+
formatter.new(name, export['options'] || {})
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|