vump 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []