vump 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: aec555f8504102bf24f667af29270bd3bbddda7e
4
+ data.tar.gz: eb683df338dd18f371f592927ec89bf61e16550b
5
+ SHA512:
6
+ metadata.gz: 25671712156e0c878b307250f177112fec08583d4114762d399d1f9c22f64e9f5d0eda4a2f8f1b842760ed1cfa5a1f96791fd515513cde42617090a06dff977a
7
+ data.tar.gz: f9502e799488ae0d16d15a0fe13afaa425fdb6de8829ae8574d8f9f8db433acb688a334fc241b82be2aa85860d65ed7acaa879bd565ade11b0d0555dbadfbb16
data/README.adoc ADDED
@@ -0,0 +1,41 @@
1
+ = vump: Semantic version bumper
2
+ Jaroslav Šmolík <grissius@gmail.com>
3
+ :semver: https://semver.org/[semver]
4
+ :git: https://git-scm.com/[git]
5
+
6
+ CLI tool to easily manage projects using {semver} and automate menial version raising.
7
+
8
+ == Introduction
9
+
10
+ When working on a project with version management, increasing a version is a mundane, boring task. It might consist of as much as following steps:
11
+
12
+ * modify `VERSION` file
13
+ * modify package file version
14
+ * update changelog (e.g. if using keepachangelog move unreleased to this version, start new unreleased, update footnote)
15
+ * create a commit
16
+ * tag a commit
17
+ * double check previous steps, because you might have forgotten any of them
18
+
19
+ Which is exhausting. If following any standards at all, like {semver}, keepachagnelog etc, it does not require any human input, but to decide which version to increase.
20
+
21
+ == Usage
22
+ In root of project directory, choose which version (from {semver}) to bump, and supply it as a sole argument.
23
+ ```
24
+ vump <major|minor|patch>
25
+ ```
26
+
27
+ TIP: You can use any discriminative prefixes such as `maj`, `min`, or even `ma`, `mi` and `p`.
28
+
29
+ === What it does
30
+ The program loads all modules, each being responsible for a single file it understands.
31
+ Each module checks if the file exists and if so, it will read the last version.
32
+ The versions across modules must match and are bumped as desired and written back into files.
33
+
34
+ After all file modules are done, {git} module adds all modified files and creates a tagged commit, if {git} is used in the project.
35
+
36
+ WARNING: As the interface implies, your project must follow the {semver} specifiaction.
37
+
38
+ === Options
39
+ `vump --version`:: Print program version
40
+ `vump --verbose patch`, `vump -v patch`:: Print debug logs
41
+ `vump --silent patch`, `vump -s patch`:: Print only warning and error logs
data/bin/vump ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/cli'
4
+
5
+ Vump::CLI.start(ARGV)
data/lib/cli.rb ADDED
@@ -0,0 +1,65 @@
1
+ require File.expand_path('vump/version', __dir__)
2
+ require File.expand_path('vump/meta', __dir__)
3
+ require File.expand_path('vump', __dir__)
4
+ require 'optparse'
5
+
6
+ # Root module for package Vump
7
+ module Vump
8
+ # CLI module for package Vump
9
+ module CLI
10
+ # Parse CLI arguemnts
11
+ #
12
+ # @param [Array[String]] _ arguments (not used now)
13
+ # OptionParser parses ARGV
14
+ # @return [Array[String], Array[String]] options and args
15
+ def self.parse_argv(_)
16
+ options = {}
17
+ args = OptionParser.new do |opt|
18
+ opt.on('-h', '--help') { options[:help] = true }
19
+ opt.on('--version') { options[:version] = true }
20
+ opt.on('-v', '--verbose') { options[:verbose] = true }
21
+ opt.on('-s', '--silent') { options[:silent] = true }
22
+ end.parse!
23
+ [options, args]
24
+ end
25
+
26
+ # Tets if CLI arguments are valid.
27
+ #
28
+ # @param [Array[String]] args CLI args
29
+ # @return true if all valid
30
+ def self.valid_args(args)
31
+ if args.length != 1
32
+ Vump.logger.error "Wrong number of args. Got #{args.length}, expected 1"
33
+ false
34
+ elsif !/^(ma|mi|p)/i.match(args.first)
35
+ Vump.logger.error 'Unknown version to bump. <major|minor|patch>'
36
+ false
37
+ else
38
+ true
39
+ end
40
+ end
41
+
42
+ def self.setup(options)
43
+ Vump.logger.level = Logger::INFO
44
+ if options[:verbose]
45
+ Vump.logger.level = Logger::DEBUG
46
+ elsif options[:silent]
47
+ Vump.logger.level = Logger::UNKNOWN
48
+ end
49
+ end
50
+
51
+ # Main CLI command
52
+ def self.start(argv)
53
+ options, args = parse_argv(argv)
54
+ if options[:version]
55
+ puts "vump #{Vump::VERSION}"
56
+ elsif valid_args(args)
57
+ Vump.orchestrate(args)
58
+ else
59
+ puts 'Error: invalid version part to bump.' unless args.empty?
60
+ puts Vump::SUMMARY if options[:help]
61
+ puts 'vump <major|minor|patch>'
62
+ end
63
+ end
64
+ end
65
+ end
data/lib/vump/meta.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Vump
2
+ # Brief summary of the package
3
+ SUMMARY = 'Raise version version in root of semver project.'.freeze
4
+ end
@@ -0,0 +1,48 @@
1
+ require 'json'
2
+ require 'date'
3
+ require 'keepachangelog'
4
+ require_relative '../read_write_version_module'
5
+ require_relative '../monkey/keepachangelog'
6
+
7
+ module Vump
8
+ module VersionModule
9
+ # [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
10
+ class KeepAChangeLog < ReadWriteVersionModule
11
+ def self.name
12
+ 'CHANGELOG.md'
13
+ end
14
+
15
+ def path
16
+ @base + '/CHANGELOG.md'
17
+ end
18
+
19
+ def scrape(str)
20
+ Keepachangelog::MarkdownParser
21
+ .parse(str)['versions']
22
+ .keys
23
+ .reject { |v| v == 'Unreleased' }
24
+ .first
25
+ end
26
+
27
+ def compose(new_version)
28
+ content = Keepachangelog::MarkdownParser.parse(@read_contents)
29
+ content = release_changelog(content, new_version)
30
+ parser = Keepachangelog::Parser.new
31
+ parser.parsed_content = content
32
+ parser.to_md + "\n"
33
+ end
34
+
35
+ def release_changelog(changelog, new_version)
36
+ versions = changelog['versions']
37
+ # inherit all from unreleased
38
+ versions[new_version] = versions['Unreleased']
39
+ .clone
40
+ # update date
41
+ versions[new_version]['date'] = Date.today.to_s
42
+ # reset unreleased
43
+ versions['Unreleased']['changes'] = {}
44
+ changelog
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ require 'json'
2
+ require_relative '../read_write_version_module'
3
+
4
+ module Vump
5
+ module VersionModule
6
+ # Npm version module for package.json
7
+ class Npm < ReadWriteVersionModule
8
+ def self.name
9
+ 'package.json'
10
+ end
11
+
12
+ def path
13
+ @base + '/package.json'
14
+ end
15
+
16
+ def scrape(str)
17
+ JSON.parse(str)['version']
18
+ end
19
+
20
+ def compose(new_version)
21
+ json = JSON.parse(@read_contents)
22
+ json['version'] = new_version
23
+ JSON.pretty_generate(json) + "\n"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+ require_relative 'npm'
3
+
4
+ module Vump
5
+ module VersionModule
6
+ # Npm version module for package.json
7
+ class NpmLock < Npm
8
+ def path
9
+ @base + '/package-lock.json'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../read_write_version_module'
2
+
3
+ module Vump
4
+ module VersionModule
5
+ # Module for VERSION file
6
+ class VersionFile < ReadWriteVersionModule
7
+ def self.name
8
+ 'VERSION'
9
+ end
10
+
11
+ def path
12
+ @base + '/VERSION'
13
+ end
14
+
15
+ def scrape(str)
16
+ str.strip
17
+ end
18
+
19
+ def compose(new_version)
20
+ new_version + "\n"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ require 'keepachangelog'
2
+
3
+ # Monkey library patch
4
+ module Keepachangelog
5
+ # Monkey library patch
6
+ class MarkdownPrinter
7
+ # Add tag prefix
8
+ def anchor(v, i)
9
+ from_v = i == v.length - 1 ? first_commit : 'v' + v[i + 1]
10
+ to_v = Gem::Version.correct?(v[i]) ? 'v' + v[i] : 'HEAD'
11
+ "[#{v[i]}]: #{options[:url]}/compare/#{from_v}...#{to_v}"
12
+ end
13
+
14
+ # Add newline after empty section
15
+ def version(header, content)
16
+ chnages = content['changes']
17
+ [
18
+ version_header(header, content['date']),
19
+ chnages.empty? ? '' : chnages.map { |k, v| section(k, v) }
20
+ ]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,43 @@
1
+ module Vump
2
+ # Read write version module archetype
3
+ class ReadWriteVersionModule
4
+ def initialize(base)
5
+ @base = base
6
+ end
7
+
8
+ def read
9
+ name = self.class.name
10
+ if File.file?(path)
11
+ @read_contents = File.read(path)
12
+ ver = scrape(@read_contents)
13
+ Vump.logger.debug("#{name} read `#{ver}` from `#{path}`")
14
+ else
15
+ Vump.logger.debug("#{name} could not find `#{path}`")
16
+ end
17
+ ver
18
+ end
19
+
20
+ def write(new_version)
21
+ name = self.class.name
22
+ File.write(path, compose(new_version))
23
+ Vump.logger.debug("#{name} bumped to `#{new_version}` in `#{path}`")
24
+ Vump.logger.info("#{name} successfully bumped!")
25
+ end
26
+
27
+ def self.name
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def path
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def scrape(_str)
36
+ raise NotImplementedError
37
+ end
38
+
39
+ def compose(_new_version)
40
+ raise NotImplementedError
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,55 @@
1
+ module Vump
2
+ # Representation of version notation according to https://semver.org/
3
+ class Semver
4
+ def initialize(string = nil)
5
+ @pre = @build = false
6
+ @major = @minor = @patch = 0
7
+ load string if string
8
+ end
9
+
10
+ def load(string)
11
+ # <numeral>[-<sufix>]
12
+ version, sufix = string
13
+ .match(/([\d\.]+)(?:\-)?(.*)?/)
14
+ .captures
15
+ # <sufix>:= [<pre>][+<build>]
16
+ @pre, @build = sufix.split('+', 2).map { |s| s.empty? ? false : s }
17
+ # <numeral>:= <major>.<minor>.<patch>
18
+ @major, @minor, @patch = version
19
+ .match(/(\d+)\.(\d+)\.(\d+)/)
20
+ .captures
21
+ .map(&:to_i)
22
+ end
23
+
24
+ def reset(what)
25
+ levels = %i[@build @pre @patch @minor @major]
26
+ # tag to false, version to 0
27
+ reset_to = %i[@build @pre].include?(what) ? false : 0
28
+ instance_variable_set(what, reset_to)
29
+ # reset lesser sections
30
+ reset levels[levels.index(what) - 1] if levels.index(what) != 0
31
+ end
32
+
33
+ def bump_patch
34
+ reset :@pre
35
+ @patch += 1
36
+ end
37
+
38
+ def bump_minor
39
+ reset :@patch
40
+ @minor += 1
41
+ end
42
+
43
+ def bump_major
44
+ reset :@minor
45
+ @major += 1
46
+ end
47
+
48
+ def to_s
49
+ str = "#{@major}.#{@minor}.#{@patch}"
50
+ str << "-#{@pre}" if @pre
51
+ str << "+#{@build}" if @build
52
+ str
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,4 @@
1
+ module Vump
2
+ # Package version
3
+ VERSION = File.read(File.expand_path('../../VERSION', __dir__)).strip.freeze
4
+ end
data/lib/vump.rb ADDED
@@ -0,0 +1,66 @@
1
+ require File.expand_path('vump/semver/semver', __dir__)
2
+ Dir[File.expand_path('vump/semver/module/*.rb', __dir__)]
3
+ .each { |file| require file }
4
+ require 'logger'
5
+
6
+ # Root package module
7
+ module Vump
8
+ @@logger = Logger.new(STDOUT)
9
+ @@logger.formatter = proc do |severity, _datetime, _progname, msg|
10
+ "#{severity}: #{msg}\n"
11
+ end
12
+
13
+ def self.logger
14
+ @@logger
15
+ end
16
+
17
+ def self.bump(what, version)
18
+ case what
19
+ when /^ma/i
20
+ version.bump_major
21
+ when /^mi/i
22
+ version.bump_minor
23
+ when /^p/i
24
+ version.bump_patch
25
+ end
26
+ version
27
+ end
28
+
29
+ def self.modules(base = Dir.pwd)
30
+ modules_versions = Vump::VersionModule
31
+ .constants
32
+ .map { |m| Vump::VersionModule.const_get(m) }
33
+ .select { |m| m.is_a? Class }
34
+ .map { |m| m.new(base) }
35
+ .map { |m| [m, m.read] }
36
+ .select { |_m, v| v }
37
+ # "unzip"
38
+ modules_versions.empty? ? [[], []] : modules_versions.transpose
39
+ end
40
+
41
+ # Format CLI output
42
+ #
43
+ # @param [Array[String]] args CLI args
44
+ # @return [String] output
45
+ def self.orchestrate(args)
46
+ v_modules, current_versions = modules
47
+ if current_versions.uniq.length > 1
48
+ Vump.logger.error 'Different versions detected. Quitting.'
49
+ else
50
+ new_version = bump(args.first, Vump::Semver.new(current_versions.first))
51
+ v_modules.each { |m| m.write(new_version.to_s) }
52
+ git(v_modules, new_version)
53
+ end
54
+ end
55
+
56
+ def self.git(modules, release_version)
57
+ return unless File.exist?(Dir.pwd + '/.git')
58
+ modules.each { |m| `git add #{m.path}` }
59
+ `git commit -m "Release #{release_version}"` unless modules.empty?
60
+ `git tag "v#{release_version}"`
61
+ end
62
+
63
+ # Module containing all worker modules to be executed on bump
64
+ module VersionModule
65
+ end
66
+ end
data/vump.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ require File.expand_path('lib/vump/version', __dir__)
2
+ require File.expand_path('lib/vump/meta', __dir__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'vump'
6
+ s.version = Vump::VERSION
7
+ s.homepage = 'https://github.com/grissius/vump'
8
+ s.license = 'MIT'
9
+ s.author = 'Jaroslav Šmolík'
10
+ s.email = 'grissius@gmail.com'
11
+
12
+ s.summary = Vump::SUMMARY
13
+ s.description = <<-DESCRIPTION
14
+ Semantic version bumper. CLI tool to easily manage projects using semver and automate menial version raising.
15
+ DESCRIPTION
16
+
17
+ s.files = Dir['bin/*', 'lib/**/*', '*.gemspec', 'LICENSE*', 'README*']
18
+ s.executables = Dir['bin/*'].map { |f| File.basename(f) }
19
+ s.has_rdoc = 'yard'
20
+
21
+ s.required_ruby_version = '>= 2.2'
22
+
23
+ s.add_runtime_dependency 'keepachangelog', '~> 0.5.3'
24
+
25
+ s.add_development_dependency 'rake', '~> 12.0'
26
+ s.add_development_dependency 'rspec', '~> 3.6'
27
+ s.add_development_dependency 'yard', '~> 0.9'
28
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vump
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jaroslav Šmolík
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-01-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: keepachangelog
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ description: " Semantic version bumper. CLI tool to easily manage projects using
70
+ semver and automate menial version raising.\n"
71
+ email: grissius@gmail.com
72
+ executables:
73
+ - vump
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - README.adoc
78
+ - bin/vump
79
+ - lib/cli.rb
80
+ - lib/vump.rb
81
+ - lib/vump/meta.rb
82
+ - lib/vump/semver/module/keepachangelog.rb
83
+ - lib/vump/semver/module/npm.rb
84
+ - lib/vump/semver/module/npm_lock.rb
85
+ - lib/vump/semver/module/version_file.rb
86
+ - lib/vump/semver/monkey/keepachangelog.rb
87
+ - lib/vump/semver/read_write_version_module.rb
88
+ - lib/vump/semver/semver.rb
89
+ - lib/vump/version.rb
90
+ - vump.gemspec
91
+ homepage: https://github.com/grissius/vump
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '2.2'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.6.13
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Raise version version in root of semver project.
115
+ test_files: []