verto 0.6.1 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
4
  module DSL
3
5
  class Interpreter
@@ -6,15 +8,14 @@ module Verto
6
8
  # TODO: Wrap stacktrace
7
9
  Error = Class.new(Verto::ExitError)
8
10
 
9
- def evaluate(vertofile_content=nil, attributes: {}, &block)
11
+ def evaluate(vertofile_content = nil, attributes: {}, &block)
10
12
  with_attributes(attributes) do
11
- vertofile_content ? instance_eval(vertofile_content) : instance_eval(&block)
13
+ vertofile_content ? instance_eval(vertofile_content) : instance_eval(&block)
12
14
  end
15
+ rescue StandardError => e
16
+ raise e if e.is_a?(Verto::ExitError)
13
17
 
14
- rescue StandardError => error
15
- raise error if error.is_a?(Verto::ExitError)
16
-
17
- raise Error, error.message
18
+ raise Error, e.message
18
19
  end
19
20
 
20
21
  private
@@ -27,7 +28,7 @@ module Verto
27
28
 
28
29
  block.call
29
30
 
30
- attributes.each do |key, value|
31
+ attributes.each do |key, _value|
31
32
  instance_variable_set("@#{key}", nil)
32
33
  singleton_class.remove_method(key)
33
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
4
  module DSL
3
5
  module Syntax
@@ -55,17 +57,13 @@ module Verto
55
57
  end
56
58
 
57
59
  def sh!(command, output: :from_config)
58
- raise Verto::ExitError unless sh(command, output: output).success?
60
+ raise Verto::ExitError, command unless sh(command, output: output).success?
59
61
  end
60
62
 
61
63
  def command_options
62
64
  Verto.config.command_options
63
65
  end
64
66
 
65
- def on(moment, &block)
66
- Verto.config.hooks << Hook.new(moment: moment, &block)
67
- end
68
-
69
67
  def before(&block)
70
68
  Verto.config.hooks << Hook.new(moment: :before, &block)
71
69
  end
@@ -74,14 +72,48 @@ module Verto
74
72
  Verto.config.hooks << Hook.new(moment: :after, &block)
75
73
  end
76
74
 
75
+ def on(moment, &block)
76
+ deprecate('on', use: 'before_tag_creation')
77
+
78
+ Verto.config.hooks << Hook.new(moment: moment, &block)
79
+ end
80
+
77
81
  def before_command(command_name, &block)
82
+ deprecate('before_command', use: 'before_command_tag_up')
83
+
78
84
  Verto.config.hooks << Hook.new(moment: "before_#{command_name}", &block)
79
85
  end
80
86
 
81
87
  def after_command(command_name, &block)
88
+ deprecate('after_command', use: 'after_command_tag_up')
89
+
82
90
  Verto.config.hooks << Hook.new(moment: "after_#{command_name}", &block)
83
91
  end
84
92
 
93
+ def before_command_tag_up(&block)
94
+ Verto.config.hooks << Hook.new(moment: 'before_tag_up', &block)
95
+ end
96
+
97
+ def after_command_tag_up(&block)
98
+ Verto.config.hooks << Hook.new(moment: 'after_tag_up', &block)
99
+ end
100
+
101
+ def before_tag_creation(&block)
102
+ Verto.config.hooks << Hook.new(moment: 'before_tag_creation', &block)
103
+ end
104
+
105
+ def update_changelog(with: :merged_pull_requests_with_bracketed_labels, confirmation: true, filename: 'CHANGELOG.md')
106
+ permitted_moments = %w[before_tag_creation after_tag_up]
107
+ unless permitted_moments.include? Verto.current_moment.to_s
108
+ raise ExitError, 'update_changelog is only supported in before_tag_creation or after_command_tag_up'
109
+ end
110
+
111
+ UpdateChangelog.new.call(with: with,
112
+ new_version: new_version,
113
+ confirmation: confirmation,
114
+ filename: filename)
115
+ end
116
+
85
117
  def file(filepath)
86
118
  DSL::File.new(filepath)
87
119
  end
@@ -90,8 +122,9 @@ module Verto
90
122
  ENV[environment_name]
91
123
  end
92
124
 
125
+ # TODO: Use delegator
93
126
  def confirm(text)
94
- shell_basic.yes?("#{text} (y/n)")
127
+ CliHelpers.confirm(text)
95
128
  end
96
129
 
97
130
  def error(text)
@@ -110,16 +143,12 @@ module Verto
110
143
  @executors ||= {
111
144
  from_config: Verto::SystemCommandExecutor.new,
112
145
  true => Verto::SystemCommandExecutor.new(stdout: $stdout, stderr: $stderr),
113
- false => Verto::SystemCommandExecutor.new(stdout: nil, stderr: nil),
146
+ false => Verto::SystemCommandExecutor.new(stdout: nil, stderr: nil)
114
147
  }
115
148
 
116
149
  @executors[output]
117
150
  end
118
151
 
119
- def shell_basic
120
- @shell_basic ||= Thor::Shell::Basic.new
121
- end
122
-
123
152
  def stderr
124
153
  Verto.stderr
125
154
  end
@@ -135,6 +164,10 @@ module Verto
135
164
 
136
165
  SemanticVersion.new(tag_version)
137
166
  end
167
+
168
+ def deprecate(current, use:)
169
+ warn "[DEPRECATED] `#{current}` is deprecated and will be removed in a future release, use `#{use}` instead"
170
+ end
138
171
  end
139
172
  end
140
173
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verto
4
+ module DSL
5
+ class UpdateChangelog
6
+ include Verto.import[:cli_helpers, :stdout,
7
+ executor: 'system_command_executor_without_output', changelog_format: 'changelog.format']
8
+
9
+ InvalidChangelogSource = Class.new(Verto::ExitError)
10
+
11
+ SOURCES = StrictHash.new(
12
+ {
13
+ merged_pull_requests_with_bracketed_labels: lambda do |executor|
14
+ executor.run(
15
+ %q(git log --oneline --decorate | grep -B 100 -m 1 "tag:" | grep "pull request" | awk '{print $1}' | xargs git show --format='%b' | grep -v Approved | grep -v "^$" | grep -E "^[[:space:]]*\[.*\]")
16
+ ).output.split("\n").map(&:strip)
17
+ end
18
+ },
19
+ default_proc: ->(hash, _) { raise InvalidChangelogSource, "Invalid CHANGELOG Source, avaliable options: '#{hash.keys.join(',')}'" }
20
+ )
21
+
22
+ def call(new_version:, confirmation: true, filename: 'CHANGELOG.md', with: :merged_pull_requests_with_bracketed_labels)
23
+ verify_file_presence!(filename)
24
+
25
+ stdout.puts separator
26
+ changelog_changes = format_changes(new_version, version_changes(with))
27
+
28
+ exit if confirmation && !cli_helpers.confirm("Create new Realease?\n" \
29
+ "#{separator}\n" \
30
+ "#{changelog_changes}" \
31
+ "#{separator}\n")
32
+ update_file(filename, changelog_changes)
33
+ end
34
+
35
+ private
36
+
37
+ def verify_file_presence!(filename)
38
+ return if Verto.project_path.join(filename).exist?
39
+
40
+ raise Verto::ExitError, "changelog file '#{filename}' doesnt exist"
41
+ end
42
+
43
+ def version_changes(with)
44
+ SOURCES[with].call(executor)
45
+ end
46
+
47
+ def update_file(filename, changelog_changes)
48
+ DSL::File.new(filename).prepend(changelog_changes)
49
+ end
50
+
51
+ def format_changes(new_version, version_changes)
52
+ Mustache.render(changelog_format, { new_version: new_version, version_changes: version_changes }) + "\n"
53
+ end
54
+
55
+ def separator
56
+ '---------------------------'
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
4
  class TagRepository
3
5
  include Verto.import[executor: 'system_command_executor_without_output']
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CliHelpers
4
+ class << self
5
+ def confirm(text)
6
+ shell_basic.yes?("#{text} (y/n)")
7
+ end
8
+
9
+ private
10
+
11
+ def shell_basic
12
+ @shell_basic ||= Thor::Shell::Basic.new
13
+ end
14
+ end
15
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
4
  class CommandOptions < Thor::CoreExt::HashWithIndifferentAccess
3
- alias_method :add, :merge!
5
+ alias add merge!
4
6
 
5
7
  def except(*keys)
6
- self.reject { |key, v| keys.include?(key) }
8
+ reject { |key, _v| keys.include?(key) }
7
9
  end
8
10
  end
9
11
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
4
  class SemanticVersion < Vseries::SemanticVersion
3
5
  DEFAULT_PRE_RELEASE_INITIAL_NUMBER = Verto.config.pre_release.initial_number
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class StrictHash < Hash
4
+ def initialize(hash, default_proc: nil)
5
+ super()
6
+ self.default_proc = default_proc if default_proc
7
+ merge!(hash)
8
+ end
9
+ end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'open3'
2
4
 
3
5
  module Verto
4
6
  class SystemCommandExecutor
5
7
  include Verto.import['project.path', 'stdout', 'stderr']
6
8
 
7
- class Result < Struct.new(:output, :error, :result)
9
+ Result = Struct.new(:output, :error, :result) do
8
10
  def success?
9
11
  result.success?
10
12
  end
@@ -16,7 +18,7 @@ module Verto
16
18
  Error = Class.new(StandardError)
17
19
 
18
20
  def run(command)
19
- stderr.puts running_log(command, path) if stderr
21
+ stderr&.puts running_log(command, path)
20
22
 
21
23
  Open3.popen3(command, chdir: path.to_s) do |_, stdout, stderr, wait_thread|
22
24
  @output = stdout.read
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TagFilter
2
- REALEASE_ONLY = /\d+\.\d+\.\d+$/
3
- PRE_REALEASE_ONLY = /\d+\.\d+\.\d+-.*\d+/
4
+ REALEASE_ONLY = /\d+\.\d+\.\d+$/.freeze
5
+ PRE_REALEASE_ONLY = /\d+\.\d+\.\d+-.*\d+/.freeze
4
6
 
5
7
  FILTERS = {
6
8
  release_only: REALEASE_ONLY,
7
9
  pre_release_only: PRE_REALEASE_ONLY,
8
10
  all: nil
9
- }
11
+ }.freeze
10
12
 
11
13
  def self.for(tag_key)
12
14
  FILTERS[tag_key.to_sym] if tag_key
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
4
  class Template
3
5
  def self.render(template_name, to:)
@@ -1,36 +1,40 @@
1
- verto_version '0.6.1'
1
+ verto_version '0.10.1'
2
2
 
3
3
  config {
4
4
  # version.prefix = 'v' # Adds a version_prefix
5
5
  # pre_release.initial_number = 0 # Configures pre_release initial number, defaults to 1
6
6
  # project.path = "#{project_path}" # Configures a custom project path
7
+ # git.pull_before_tag_creation = true # Pull Changes before tag creation
8
+ # git.push_after_tag_creation = true # Push changes after tag creation
9
+
10
+ ## CHANGELOG FORMAT
11
+ ## Verto uses Mustache template rendering to render changelog updates, the default value is:
12
+ ##
13
+ ## ## {{new_version}} - #{Time.now.strftime('%d/%m/%Y')}
14
+ ## {{#version_changes}}
15
+ ## * {{.}}
16
+ ## {{/version_changes}}
17
+ ##
18
+ ## A custom format can be specified, eg:
19
+ # changelog.format = <<~CHANGELOG
20
+ # ## {{new_version}}
21
+ # {{#version_changes}}
22
+ # * {{.}}
23
+ # {{/version_changes}}
24
+ # CHANGELOG
7
25
  }
8
26
 
9
27
  context(branch('master')) {
10
- before_command('tag_up') {
11
- git!('pull origin master')
28
+ before_command_tag_up {
12
29
  command_options.add(filter: 'release_only')
13
30
  }
14
31
 
15
- on('before_tag_creation') {
16
-
17
- version_changes = ""
18
- # Uncomment to get Merged PRs Titles as changes to add in CHANGELOG.
19
- # version_changes = sh(
20
- # %q#git log --oneline --decorate | grep -B 100 -m 1 "tag:" | grep "pull request" | awk '{print $1}' | xargs git show --format='%b' | grep -v Approved | grep -v "^$" | grep -E "^[[:space:]]*\[.*\]" | sed 's/^[[:space:]]*\(.*\)/ * \1/'#, output: false
21
- # ).output
22
-
23
- puts "---------------------------"
24
- version_changes = "## #{new_version} - #{Time.now.strftime('%d/%m/%Y')}\n#{version_changes}\n"
25
- exit unless confirm("Create new Realease?\n" \
26
- "---------------------------\n" \
27
- "#{version_changes}" \
28
- "---------------------------\n"
29
- )
30
-
31
- # CHANGELOG
32
- file('CHANGELOG.md').prepend(version_changes)
33
- git('add CHANGELOG.md')
32
+ before_tag_creation {
33
+ # Uncomment to update CHANGELOG file
34
+ # update_changelog(with: :merged_pull_requests_with_bracketed_labels,
35
+ # confirmation: true,
36
+ # filename: 'CHANGELOG.md')
37
+ # git('add CHANGELOG.md')
34
38
 
35
39
  # Uncomment to update the version in other files, like package.json
36
40
  # file('package.json').replace(/"(\d+)\.(\d+)\.(\d+)(-?.*)"/, %Q{"#{new_version}"})
@@ -38,34 +42,28 @@ context(branch('master')) {
38
42
 
39
43
  git('commit -m "Updates CHANGELOG"')
40
44
  }
41
-
42
- after_command('tag_up') {
43
- git('push --tags')
44
- git('push origin master')
45
- }
46
45
  }
47
46
 
48
47
  # Uncomment to get a specific pre_release proccess, like a staging or qa branch
49
48
  # context(branch('staging')) {
50
- # before_command('tag_up') {
49
+ # before_command_tag_up {
51
50
  # git!('pull origin staging')
52
51
  # command_options.add(pre_release: 'rc')
53
52
  # }
54
53
  #
55
- # on('before_tag_creation') {
54
+ # before_tag_creation {
56
55
  # file('package.json').replace(/"(\d+)\.(\d+)\.(\d+)(-?.*)"/, %Q{"#{new_version}"}) # Atualiza versão do package.json
57
56
  # git('add package.json')
58
57
  # git('commit --allow-empty -m "Staging Release"')
59
58
  # }
60
59
 
61
- # after_command('tag_up') {
62
- # git('push --tags')
63
- # git('push origin staging')
60
+ # after_command_tag_up {
61
+ # sh('some command')
64
62
  # }
65
63
  #}
66
64
 
67
65
  # Uncomment to block tag creation in other branchs
68
66
  #context(!branch('master', 'staging')) {
69
- # error "Tags only can be created in master or staging branch"
67
+ # error 'Tags only can be created in master or staging branch'
70
68
  # exit
71
69
  #}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Verto
2
- VERSION = "0.6.1"
4
+ VERSION = '0.10.1'
3
5
  end
@@ -1,40 +1,44 @@
1
- lib = File.expand_path("lib", __dir__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "verto/version"
5
+ require 'verto/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = "verto"
8
+ spec.name = 'verto'
7
9
  spec.version = Verto::VERSION
8
- spec.authors = ["Carlos Atkinson"]
9
- spec.email = ["carlos.atks@gmail.com"]
10
-
11
- spec.summary = %q{Verto helps you to versionate your project}
12
- spec.homepage = "https://github.com/catks/verto"
13
- spec.license = "MIT"
10
+ spec.authors = ['Carlos Atkinson']
11
+ spec.email = ['carlos.atks@gmail.com']
14
12
 
13
+ spec.summary = 'Verto helps you to versionate your project'
14
+ spec.homepage = 'https://github.com/catks/verto'
15
+ spec.license = 'MIT'
15
16
 
16
- # spec.metadata["homepage_uri"] = spec.homepage
17
- # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
18
- # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/catks/verto'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/catks/verto/blob/master/CHANGELOG.md'
19
20
 
20
21
  # Specify which files should be added to the gem when it is released.
21
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
24
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
25
  end
25
- spec.bindir = "exe"
26
+ spec.bindir = 'exe'
26
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
- spec.require_paths = ["lib"]
28
+ spec.require_paths = ['lib']
29
+ spec.required_ruby_version = '~> 2.5'
28
30
 
29
- spec.add_dependency "thor", "~> 1.0.1"
30
- spec.add_dependency "dry-configurable", "~> 0.8"
31
- spec.add_dependency "dry-container", "~> 0.7"
32
- spec.add_dependency "dry-auto_inject", "~> 0.7"
33
- spec.add_dependency "vseries", "~> 0.2"
31
+ spec.add_dependency 'dry-auto_inject', '~> 0.7'
32
+ spec.add_dependency 'dry-configurable', '~> 0.8'
33
+ spec.add_dependency 'dry-container', '~> 0.7'
34
+ spec.add_dependency 'mustache', '~> 1.1.1'
35
+ spec.add_dependency 'thor', '~> 1.0.1'
36
+ spec.add_dependency 'vseries', '~> 0.2'
34
37
 
35
- spec.add_development_dependency "byebug"
36
- spec.add_development_dependency "bundler", "~> 2.0"
37
- spec.add_development_dependency "rake", "~> 13.0"
38
- spec.add_development_dependency "rspec", "~> 3.0"
39
- spec.add_development_dependency "simplecov", "~> 0.18.0"
38
+ spec.add_development_dependency 'bundler', '~> 2.0'
39
+ spec.add_development_dependency 'byebug'
40
+ spec.add_development_dependency 'rake', '~> 13.0'
41
+ spec.add_development_dependency 'rspec', '~> 3.0'
42
+ spec.add_development_dependency 'rubocop'
43
+ spec.add_development_dependency 'simplecov', '~> 0.17.0'
40
44
  end