version-manager 0.0.9 → 0.1.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/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +5 -0
- data/README.md +1 -0
- data/Rakefile +5 -2
- data/exe/manver +1 -0
- data/lib/version-manager.rb +10 -6
- data/lib/version-manager/action_manager.rb +34 -0
- data/lib/version-manager/cli.rb +9 -23
- data/lib/version-manager/{make.rb → release_manager.rb} +8 -6
- data/lib/version-manager/release_version.rb +11 -10
- data/lib/version-manager/vcs.rb +9 -3
- data/lib/version-manager/vcs/git.rb +30 -19
- data/lib/version-manager/version.rb +2 -1
- data/lib/version-manager/version_storage.rb +5 -8
- data/spec/features/git_bumping_version_action_spec.rb +97 -0
- data/spec/features/git_latest_version_action_spec.rb +44 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/git_repository.rb +63 -0
- data/spec/support/repository_matchers.rb +18 -0
- data/spec/support/shared_settings.rb +59 -0
- data/version-manager.gemspec +13 -1
- metadata +56 -8
- data/.ruby-version +0 -1
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3860c7e4394f7d49d1c467cabb0fe944f0d049f3
|
4
|
+
data.tar.gz: a8c9694661eca4f788d28a7c991d9b41f1c874aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eebd799dc897df1e401c74a80a01ff12fca1cce18d37f8a6037df74c1a7e3c7f2aa01bc45f5e572ba3616a70b4ee23d6fdbc1fcac07f1d7279c23c9dd3caf782
|
7
|
+
data.tar.gz: 4492d44cce10b4249c2fd543d11ebea4b154d8e2db06ed3f6f9ac9c0d77913356e36df2e4d132165799644ee5365b8321ce0d2cc9dd8e66fd7d83aed4e81cf05
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
data/exe/manver
CHANGED
data/lib/version-manager.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# rubocop:disable Style/FileName
|
2
|
+
# frozen_string_literal: true
|
1
3
|
require 'docopt'
|
2
4
|
require 'git'
|
3
5
|
require 'pathname'
|
@@ -10,10 +12,12 @@ module VersionManager
|
|
10
12
|
DEFAULTS = {
|
11
13
|
vcs: {
|
12
14
|
name: 'git',
|
13
|
-
default_commit_message: ->
|
15
|
+
default_commit_message: ->(version) { "Bumped to version #{version}" },
|
14
16
|
options: {
|
15
17
|
remote: 'origin',
|
16
|
-
master_branch: 'master'
|
18
|
+
master_branch: 'master',
|
19
|
+
dir: ROOT_DIR,
|
20
|
+
version_name: ->(version) { "release-#{version.short_version}" }
|
17
21
|
}
|
18
22
|
},
|
19
23
|
authorized_branches: {
|
@@ -24,9 +28,8 @@ module VersionManager
|
|
24
28
|
storage: {
|
25
29
|
filename: 'VERSION',
|
26
30
|
filepath: ROOT_DIR
|
27
|
-
}
|
28
|
-
|
29
|
-
}
|
31
|
+
}
|
32
|
+
}.freeze
|
30
33
|
|
31
34
|
def self.options
|
32
35
|
@options ||= DEFAULTS.dup
|
@@ -43,6 +46,7 @@ require_relative 'version-manager/vcs/git'
|
|
43
46
|
require_relative 'version-manager/version'
|
44
47
|
require_relative 'version-manager/cli'
|
45
48
|
|
49
|
+
require_relative 'version-manager/action_manager'
|
50
|
+
require_relative 'version-manager/release_manager'
|
46
51
|
require_relative 'version-manager/release_version'
|
47
52
|
require_relative 'version-manager/version_storage'
|
48
|
-
require_relative 'version-manager/make.rb'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module VersionManager
|
3
|
+
class ActionManager
|
4
|
+
def initialize(options)
|
5
|
+
@options = options
|
6
|
+
@vcs = VCS.build(options[:vcs])
|
7
|
+
@storage = VersionStorage.new(vcs, options[:storage])
|
8
|
+
@release_manager = ReleaseManager.new(vcs, storage, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def checkout_to_latest_version
|
12
|
+
version = storage.latest_version
|
13
|
+
return false unless version
|
14
|
+
vcs.switch_branch(VCS.branch_name(version, options.dig(:vcs, :options)))
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def release_new_version(release_type, confirmation_func, retrieve_initial_version_func)
|
19
|
+
release_manager.validate!(release_type)
|
20
|
+
version = release_type == :patch ? storage.current_version : storage.latest_version
|
21
|
+
if version
|
22
|
+
new_version = version.public_send("bump_#{release_type}")
|
23
|
+
return unless confirmation_func.call(new_version)
|
24
|
+
else
|
25
|
+
version = retrieve_initial_version_func.call
|
26
|
+
end
|
27
|
+
release_manager.public_send("#{release_type}!", version)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :vcs, :storage, :release_manager, :options
|
33
|
+
end
|
34
|
+
end
|
data/lib/version-manager/cli.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module VersionManager
|
2
3
|
class CLI
|
3
4
|
def initialize(exec_name: __FILE__)
|
4
5
|
@exec_name = exec_name
|
6
|
+
@action_manager = ActionManager.new(VersionManager.options)
|
5
7
|
end
|
6
8
|
|
7
9
|
def start
|
@@ -21,7 +23,7 @@ module VersionManager
|
|
21
23
|
DOCOPT
|
22
24
|
|
23
25
|
begin
|
24
|
-
parse_options(Docopt
|
26
|
+
parse_options(Docopt.docopt(doc))
|
25
27
|
rescue StandardError => e
|
26
28
|
puts e.message
|
27
29
|
end
|
@@ -29,7 +31,7 @@ module VersionManager
|
|
29
31
|
|
30
32
|
private
|
31
33
|
|
32
|
-
attr_reader :exec_name
|
34
|
+
attr_reader :exec_name, :action_manager
|
33
35
|
|
34
36
|
def parse_options(options)
|
35
37
|
puts VersionManager::VERSION if options['--version']
|
@@ -41,34 +43,18 @@ module VersionManager
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def checkout_to_latest_version
|
44
|
-
|
45
|
-
|
46
|
-
return puts 'There are no any versions.' unless version
|
47
|
-
VCS.build.switch_branch(version.branch)
|
46
|
+
return if action_manager.checkout_to_latest_version
|
47
|
+
puts 'There are no any versions.'
|
48
48
|
end
|
49
49
|
|
50
50
|
def make_release(release_type)
|
51
|
-
|
52
|
-
|
53
|
-
make = Make.new(VCS.build, storage)
|
54
|
-
make.validate!(release_type)
|
55
|
-
|
56
|
-
version = release_type == :patch ? storage.current_version : storage.latest_version
|
57
|
-
if version
|
58
|
-
new_version = version.public_send("bump_#{release_type}")
|
59
|
-
return unless Ask.confirm("You are going to upgrade version to #{new_version}. Do it?", default: false)
|
60
|
-
else
|
61
|
-
version = retrieve_initial_version
|
62
|
-
end
|
63
|
-
|
64
|
-
make.public_send("#{release_type}!", version)
|
51
|
+
action_manager.release_new_version(release_type, method(:confirm_new_version), method(:retrieve_initial_version))
|
65
52
|
rescue VersionManager::VersionStorage::WrongLatestVersionError => e
|
66
53
|
puts "There is inappropriate version #{e.version} in your local/remote repository. Please remove it"
|
67
54
|
end
|
68
55
|
|
69
|
-
def
|
70
|
-
|
71
|
-
VersionStorage.new(VCS.build, storage_options)
|
56
|
+
def confirm_new_version(new_version)
|
57
|
+
Ask.confirm("You are going to upgrade version to #{new_version}. Do it?", default: false)
|
72
58
|
end
|
73
59
|
|
74
60
|
def retrieve_initial_version
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module VersionManager
|
2
|
-
class
|
3
|
+
class ReleaseManager
|
3
4
|
class BranchIsNotUpToDateError < StandardError
|
4
5
|
def message
|
5
6
|
'Remote branch and local one are different. You need to update your branch or push your changes'
|
@@ -12,9 +13,10 @@ module VersionManager
|
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
def initialize(vcs, version_storage)
|
16
|
+
def initialize(vcs, version_storage, options)
|
16
17
|
@vcs = vcs
|
17
18
|
@version_storage = version_storage
|
19
|
+
@options = options
|
18
20
|
end
|
19
21
|
|
20
22
|
def validate!(release_type)
|
@@ -40,15 +42,15 @@ module VersionManager
|
|
40
42
|
|
41
43
|
private
|
42
44
|
|
43
|
-
attr_reader :vcs, :version_storage
|
45
|
+
attr_reader :vcs, :version_storage, :options
|
44
46
|
|
45
47
|
def appropriate_branch_for?(action)
|
46
|
-
authorized_mask =
|
48
|
+
authorized_mask = options[:authorized_branches][action.to_sym]
|
47
49
|
!authorized_mask || !vcs.current_branch.match(authorized_mask).nil?
|
48
50
|
end
|
49
51
|
|
50
52
|
def default_strategy(version)
|
51
|
-
vcs.create_branch!(version
|
53
|
+
vcs.create_branch!(version)
|
52
54
|
vcs.commit(version_storage.store(version), default_commit_message(version))
|
53
55
|
vcs.add_tag(version.to_s, default_commit_message(version))
|
54
56
|
vcs.push_tag(version.to_s)
|
@@ -56,7 +58,7 @@ module VersionManager
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def default_commit_message(version)
|
59
|
-
message =
|
61
|
+
message = options[:vcs][:default_commit_message]
|
60
62
|
message.respond_to?(:call) ? message.call(version) : message.to_s
|
61
63
|
end
|
62
64
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module VersionManager
|
2
3
|
class ReleaseVersion
|
3
4
|
include Comparable
|
@@ -19,28 +20,28 @@ module VersionManager
|
|
19
20
|
recalculate_parts
|
20
21
|
end
|
21
22
|
|
22
|
-
def
|
23
|
+
def to_s
|
23
24
|
res = parts.map(&:to_i).join('.')
|
24
25
|
[res, special].compact.join('--')
|
25
26
|
end
|
26
|
-
alias_method :to_s, :to_str
|
27
27
|
|
28
28
|
def short_version
|
29
29
|
[major, minor].map(&:to_i).join('.')
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
32
|
+
def <=>(other)
|
33
|
+
parts.zip(other.parts)
|
34
|
+
.map { |this, other_part| this <=> other_part }
|
35
|
+
.find { |res| res != 0 } || 0
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
parts.zip(
|
38
|
-
map { |this, other| this <=> other }.
|
39
|
-
find { |res| res != 0 } || 0
|
38
|
+
def -(other)
|
39
|
+
self.class.new(parts.zip(other.parts).map { |x, y| x - y })
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
42
|
+
def bump(release_type)
|
43
|
+
raise ArgumentError, 'Unknown release type' unless %i(major minor patch).include?(release_type.to_sym)
|
44
|
+
public_send("bump_#{release_type}")
|
44
45
|
end
|
45
46
|
|
46
47
|
def bump_major
|
data/lib/version-manager/vcs.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module VersionManager
|
2
3
|
module VCS
|
3
4
|
class BranchAlreadyExistsError < StandardError
|
@@ -20,9 +21,14 @@ module VersionManager
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
def self.
|
24
|
-
|
25
|
-
|
24
|
+
def self.branch_name(version, vcs_options)
|
25
|
+
version = ReleaseVersion.new(version) if version.is_a?(String)
|
26
|
+
vcs_options[:version_name].call(version)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.build(vcs_options)
|
30
|
+
case vcs_options[:name]
|
31
|
+
when 'git' then VersionManager::VCS::Git.new(vcs_options[:options])
|
26
32
|
else raise UnsupportedVCSError
|
27
33
|
end
|
28
34
|
end
|
@@ -1,33 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module VersionManager
|
2
3
|
module VCS
|
3
4
|
class Git
|
4
5
|
def initialize(options)
|
5
6
|
@options = options
|
6
|
-
@git = ::Git.open(
|
7
|
+
@git = ::Git.open(options[:dir], options)
|
7
8
|
end
|
8
9
|
|
9
|
-
def create_branch!(
|
10
|
-
|
11
|
-
|
10
|
+
def create_branch!(branch)
|
11
|
+
branch = branch_name(branch)
|
12
|
+
raise VersionManager::VCS::BranchAlreadyExistsError, branch if branch_exists?(branch)
|
13
|
+
checkout(branch)
|
12
14
|
end
|
13
15
|
|
14
|
-
def checkout(
|
15
|
-
git.branch(branch_name).checkout
|
16
|
+
def checkout(branch)
|
17
|
+
git.branch(branch_name(branch)).checkout
|
16
18
|
end
|
17
19
|
|
18
|
-
def switch_branch(
|
19
|
-
git.lib.send(:command, 'checkout', branch_name)
|
20
|
+
def switch_branch(branch) # checkout moves commits to new branch
|
21
|
+
git.lib.send(:command, 'checkout', branch_name(branch))
|
20
22
|
end
|
21
23
|
|
22
24
|
def show_file(branch, filepath)
|
23
|
-
|
25
|
+
relative_filepath = Pathname.new(filepath).relative_path_from(Pathname.new(options[:dir])).to_s
|
26
|
+
git.object("#{remote}/#{branch_name(branch)}:#{relative_filepath}").contents
|
24
27
|
rescue StandardError
|
25
28
|
nil
|
26
29
|
end
|
27
30
|
|
28
31
|
def commit(filepath, message)
|
29
32
|
git.lib.send(:command, 'add', filepath)
|
30
|
-
git.lib.send(:command, 'commit', "-m #{message}", '-o',
|
33
|
+
git.lib.send(:command, 'commit', "-m #{message}", '-o', filepath)
|
31
34
|
end
|
32
35
|
|
33
36
|
def add_tag(tag_name, message)
|
@@ -52,22 +55,26 @@ module VersionManager
|
|
52
55
|
end
|
53
56
|
|
54
57
|
def state_actual?
|
55
|
-
head =
|
58
|
+
head = git_remote['branches'][git.current_branch]
|
56
59
|
remote_head = find_remote_branch(git.current_branch).last
|
57
60
|
return unless remote_head
|
58
61
|
head[:sha] == remote_head[:sha]
|
59
62
|
end
|
60
63
|
|
61
64
|
def remote_branch_names
|
62
|
-
|
65
|
+
git_remote['remotes'].keys
|
63
66
|
end
|
64
67
|
|
65
68
|
private
|
66
69
|
|
67
70
|
attr_reader :git, :options
|
68
71
|
|
72
|
+
def branch_name(version)
|
73
|
+
VCS.branch_name(version, options)
|
74
|
+
end
|
75
|
+
|
69
76
|
def branch_exists?(branch_name)
|
70
|
-
branches =
|
77
|
+
branches = git_remote['branches'].keys + git_remote['remotes'].keys
|
71
78
|
branches.any? { |b| b.split('/').last == branch_name }
|
72
79
|
end
|
73
80
|
|
@@ -75,16 +82,20 @@ module VersionManager
|
|
75
82
|
options[:master_branch]
|
76
83
|
end
|
77
84
|
|
78
|
-
def remote
|
79
|
-
options[:remote]
|
80
|
-
end
|
81
|
-
|
82
85
|
def remote_master_branch_name
|
83
|
-
"#{
|
86
|
+
"#{remote}/#{master_branch_name}"
|
84
87
|
end
|
85
88
|
|
86
89
|
def find_remote_branch(branch_name)
|
87
|
-
|
90
|
+
remote_branch_names.find { |remote| branch_name == remote.split('/').last }
|
91
|
+
end
|
92
|
+
|
93
|
+
def remote
|
94
|
+
options[:remote]
|
95
|
+
end
|
96
|
+
|
97
|
+
def git_remote
|
98
|
+
::Git.ls_remote(options[:dir])
|
88
99
|
end
|
89
100
|
end
|
90
101
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module VersionManager
|
2
3
|
class VersionStorage
|
3
4
|
class WrongLatestVersionError < StandardError
|
@@ -38,7 +39,7 @@ module VersionManager
|
|
38
39
|
|
39
40
|
def version_from_file(version)
|
40
41
|
return unless version
|
41
|
-
file_content = vcs.show_file(version
|
42
|
+
file_content = vcs.show_file(version, full_path) if version
|
42
43
|
ReleaseVersion.new(file_content) if file_content && ReleaseVersion.valid?(file_content)
|
43
44
|
end
|
44
45
|
|
@@ -48,10 +49,6 @@ module VersionManager
|
|
48
49
|
ReleaseVersion.new(branch_name) if branch_name.include?('release-') && ReleaseVersion.valid?(branch_name)
|
49
50
|
end
|
50
51
|
|
51
|
-
def relative_path
|
52
|
-
Pathname.new(full_path).relative_path_from(Pathname.new(ROOT_DIR)).to_s
|
53
|
-
end
|
54
|
-
|
55
52
|
def full_path
|
56
53
|
File.expand_path(File.join(filepath, filename))
|
57
54
|
end
|
@@ -62,9 +59,9 @@ module VersionManager
|
|
62
59
|
return prev_last_version unless last_version
|
63
60
|
diff = last_version - prev_last_version
|
64
61
|
is_appropriate = diff.major == 1
|
65
|
-
is_appropriate ||= diff.major
|
66
|
-
is_appropriate ||= diff.major
|
67
|
-
raise WrongLatestVersionError
|
62
|
+
is_appropriate ||= diff.major.zero? && diff.minor == 1
|
63
|
+
is_appropriate ||= diff.major.zero? && diff.minor.zero? && diff.patch == 1
|
64
|
+
raise WrongLatestVersionError, last_version unless is_appropriate
|
68
65
|
last_version
|
69
66
|
end
|
70
67
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rubocop:disable Metrics/BlockLength
|
3
|
+
RSpec.describe 'bumping version action' do
|
4
|
+
include_context 'shared settings'
|
5
|
+
let(:repo) { Test::GitRepository.new(root_dir, options) }
|
6
|
+
|
7
|
+
context 'when repository does not contain any versions' do
|
8
|
+
let(:initial_version) { VersionManager::ReleaseVersion.new('1.0.0') }
|
9
|
+
before { repo.init }
|
10
|
+
it 'retrieves an initial version' do
|
11
|
+
retrieve_initial_version_func = ->() { initial_version }
|
12
|
+
release_new_version(:major, default_confirmation_func, retrieve_initial_version_func)
|
13
|
+
|
14
|
+
expect(repo).to have_version(initial_version.bump_major)
|
15
|
+
expect(repo).to have_tag(initial_version.bump_major)
|
16
|
+
expect(repo).to have_branch(release_name(initial_version.bump_major))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when initial version is presented' do
|
21
|
+
let(:initial_version) { VersionManager::ReleaseVersion.new('1.0.0') }
|
22
|
+
let(:current_version) { initial_version.bump_major }
|
23
|
+
before do
|
24
|
+
repo.init
|
25
|
+
retrieve_initial_version_func = ->() { initial_version }
|
26
|
+
release_new_version(:major, default_confirmation_func, retrieve_initial_version_func)
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when current branch is a master branch' do
|
30
|
+
before { repo.checkout_to_master_branch }
|
31
|
+
it 'bumped major version' do
|
32
|
+
release_new_version(:major)
|
33
|
+
expect(repo).to have_version(current_version.bump_major)
|
34
|
+
expect(repo).to have_tag(current_version.bump_major)
|
35
|
+
expect(repo).to have_branch(release_name(current_version.bump_major))
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'bumped minor version' do
|
39
|
+
release_new_version(:minor)
|
40
|
+
expect(repo).to have_version(current_version.bump_minor)
|
41
|
+
expect(repo).to have_tag(current_version.bump_minor)
|
42
|
+
expect(repo).to have_branch(release_name(current_version.bump_minor))
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not bump patch version' do
|
46
|
+
expect { release_new_version(:patch) }.to(
|
47
|
+
raise_error(VersionManager::ReleaseManager::ForbiddenBranchError)
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when current branch is different from a master branch' do
|
53
|
+
it 'does not bump major version' do
|
54
|
+
expect { release_new_version(:major) }.to(
|
55
|
+
raise_error(VersionManager::ReleaseManager::ForbiddenBranchError)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'does not bump minor version' do
|
60
|
+
expect { release_new_version(:minor) }.to(
|
61
|
+
raise_error(VersionManager::ReleaseManager::ForbiddenBranchError)
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'bumped patch version' do
|
66
|
+
release_new_version(:patch)
|
67
|
+
expect(repo).to have_version(current_version.bump_patch)
|
68
|
+
expect(repo).to have_tag(current_version.bump_patch)
|
69
|
+
expect(repo).to have_branch(release_name(current_version.bump_patch))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when repository is not up to date' do
|
75
|
+
let(:initial_version) { VersionManager::ReleaseVersion.new('1.0.0') }
|
76
|
+
let(:current_version) { initial_version.bump_major }
|
77
|
+
before do
|
78
|
+
repo.init
|
79
|
+
retrieve_initial_version_func = ->() { initial_version }
|
80
|
+
release_new_version(:major, default_confirmation_func, retrieve_initial_version_func)
|
81
|
+
repo.checkout_to_master_branch
|
82
|
+
repo.add_and_commit_changes
|
83
|
+
end
|
84
|
+
|
85
|
+
%i(major minor patch).each do |version_type|
|
86
|
+
it "does not bump #{version_type} version" do
|
87
|
+
expect { release_new_version(version_type) }.to(
|
88
|
+
raise_error(VersionManager::ReleaseManager::BranchIsNotUpToDateError)
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
after(:each) do
|
95
|
+
repo.teardown if tmp_dir?
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rubocop:disable Metrics/BlockLength
|
3
|
+
RSpec.describe 'latest version action' do
|
4
|
+
include_context 'shared settings'
|
5
|
+
let(:repo) { Test::GitRepository.new(root_dir, options) }
|
6
|
+
|
7
|
+
def checkout_to_latest_version
|
8
|
+
VersionManager::ActionManager.new(options).checkout_to_latest_version
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'when a repository does not contain any versions' do
|
12
|
+
before { repo.init }
|
13
|
+
it 'do nothing' do
|
14
|
+
expect(checkout_to_latest_version).to be_falsy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when a repository has several releases' do
|
19
|
+
let(:initial_version) { VersionManager::ReleaseVersion.new('1.0.0') }
|
20
|
+
let(:current_version) { @current_version }
|
21
|
+
before do
|
22
|
+
repo.init
|
23
|
+
@current_version = initial_version
|
24
|
+
retrieve_initial_version_func = ->() { initial_version }
|
25
|
+
(1..10).to_a.sample.times do
|
26
|
+
release_type = %i(major minor).sample
|
27
|
+
@current_version = @current_version.bump(release_type)
|
28
|
+
release_new_version(release_type, default_confirmation_func, retrieve_initial_version_func)
|
29
|
+
repo.checkout_to_master_branch
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'checkouts to latest version' do
|
34
|
+
expect(checkout_to_latest_version).to be_truthy
|
35
|
+
expect(repo).to have_version(current_version)
|
36
|
+
expect(repo).to have_tag(current_version)
|
37
|
+
expect(repo).to have_branch(release_name(current_version))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
after(:each) do
|
42
|
+
repo.teardown if tmp_dir?
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
begin
|
3
|
+
require 'byebug'
|
4
|
+
rescue LoadError
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'securerandom'
|
9
|
+
|
10
|
+
require 'version-manager'
|
11
|
+
|
12
|
+
require_relative 'support/git_repository'
|
13
|
+
require_relative 'support/shared_settings'
|
14
|
+
require_relative 'support/repository_matchers'
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.order = :random
|
18
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Test
|
3
|
+
class GitRepository
|
4
|
+
def initialize(root_dir, options)
|
5
|
+
@options = options
|
6
|
+
@root_dir = root_dir
|
7
|
+
end
|
8
|
+
|
9
|
+
def init
|
10
|
+
@remote_dir = File.join(@root_dir, 'remote')
|
11
|
+
@remote = Git.init(@remote_dir, bare: true)
|
12
|
+
@local = Git.clone(@remote_dir, 'local', path: @root_dir)
|
13
|
+
@local2 = Git.clone(@remote_dir, 'local2', path: @root_dir)
|
14
|
+
|
15
|
+
initial_commit(@local)
|
16
|
+
@local
|
17
|
+
end
|
18
|
+
|
19
|
+
def checkout_to_master_branch
|
20
|
+
@local.lib.send(:command, 'checkout', @options.dig(:vcs, :options, :master_branch))
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_local_branch_version
|
24
|
+
path = File.join(@options[:storage][:filepath], @options[:storage][:filename])
|
25
|
+
File.open(path).read
|
26
|
+
end
|
27
|
+
|
28
|
+
def current_local_tag
|
29
|
+
@local.tags.last&.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def current_local_branch
|
33
|
+
@local.branches.to_a.last&.name
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_and_commit_changes
|
37
|
+
add_random_changes(@local)
|
38
|
+
@local.add
|
39
|
+
@local.commit('some changes')
|
40
|
+
end
|
41
|
+
|
42
|
+
def teardown
|
43
|
+
FileUtils.rm_f(@remote_dir)
|
44
|
+
FileUtils.rm_f(@local.dir.path)
|
45
|
+
FileUtils.rm_f(@local2.dir.path)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def initial_commit(repo)
|
51
|
+
add_random_changes(repo)
|
52
|
+
repo.add
|
53
|
+
repo.commit('initial commit')
|
54
|
+
repo.push
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_random_changes(repo)
|
58
|
+
File.open(File.join(repo.dir.path, SecureRandom.urlsafe_base64), 'w') do |f|
|
59
|
+
f << SecureRandom.urlsafe_base64
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec::Matchers.define :have_version do |version|
|
3
|
+
match do |repo|
|
4
|
+
repo.current_local_branch_version == version.to_s
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec::Matchers.define :have_tag do |version|
|
9
|
+
match do |repo|
|
10
|
+
repo.current_local_tag == version.to_s
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec::Matchers.define :have_branch do |version|
|
15
|
+
match do |repo|
|
16
|
+
repo.current_local_branch == version.to_s
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rubocop:disable Metrics/BlockLength
|
3
|
+
RSpec.shared_context 'shared settings' do
|
4
|
+
let(:root_dir) { Dir.mktmpdir }
|
5
|
+
let(:tmp_dir?) { true }
|
6
|
+
let(:repo_dir) { File.join(root_dir, 'local') }
|
7
|
+
|
8
|
+
let(:vcs) { 'git' }
|
9
|
+
let(:default_commit_message) do
|
10
|
+
->(version) { "Bumped to version #{version}" }
|
11
|
+
end
|
12
|
+
let(:vcs_opts) do
|
13
|
+
{
|
14
|
+
name: vcs,
|
15
|
+
default_commit_message: default_commit_message,
|
16
|
+
options: {
|
17
|
+
remote: 'origin',
|
18
|
+
master_branch: 'master',
|
19
|
+
dir: repo_dir,
|
20
|
+
version_name: ->(version) { "release-#{version.short_version}" }
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:authorized_branches_opts) do
|
26
|
+
{
|
27
|
+
major: '^\bmaster\b$',
|
28
|
+
minor: '^\bmaster\b$',
|
29
|
+
patch: '^\brelease-[a-zA-Z0-9.]*$\b$'
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:storage_opts) do
|
34
|
+
{
|
35
|
+
filename: 'VERSION',
|
36
|
+
filepath: repo_dir
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:options) do
|
41
|
+
{
|
42
|
+
vcs: vcs_opts,
|
43
|
+
authorized_branches: authorized_branches_opts,
|
44
|
+
storage: storage_opts
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:default_confirmation_func) { ->(_new_version) { true } }
|
49
|
+
|
50
|
+
def release_new_version(release_type, confirmation_func = default_confirmation_func, retrieve_init_version_func = nil)
|
51
|
+
VersionManager::ActionManager
|
52
|
+
.new(options)
|
53
|
+
.release_new_version(release_type, confirmation_func, retrieve_init_version_func)
|
54
|
+
end
|
55
|
+
|
56
|
+
def release_name(version)
|
57
|
+
VersionManager::VCS.branch_name(version, options.dig(:vcs, :options))
|
58
|
+
end
|
59
|
+
end
|
data/version-manager.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'version-manager/version'
|
@@ -6,7 +7,7 @@ require 'version-manager/version'
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
8
|
spec.name = 'version-manager'
|
8
9
|
spec.version = VersionManager::VERSION
|
9
|
-
spec.authors = ['
|
10
|
+
spec.authors = ['Ilya Solo']
|
10
11
|
spec.email = ['ilya.i.solo@gmail.com']
|
11
12
|
|
12
13
|
spec.summary = 'Versioning lib (with Git support)'
|
@@ -18,9 +19,20 @@ Gem::Specification.new do |spec|
|
|
18
19
|
spec.bindir = 'exe'
|
19
20
|
spec.require_paths = ['lib']
|
20
21
|
|
22
|
+
spec.required_ruby_version = '>= 2.3'
|
23
|
+
|
21
24
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
22
25
|
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
|
27
|
+
# Testing
|
28
|
+
spec.add_development_dependency 'rspec'
|
29
|
+
spec.add_development_dependency 'simplecov'
|
30
|
+
spec.add_development_dependency 'rubocop'
|
31
|
+
|
32
|
+
# Command line utils
|
23
33
|
spec.add_dependency 'docopt', '~> 0.5'
|
24
34
|
spec.add_dependency 'inquirer', '~> 0.2'
|
35
|
+
|
36
|
+
# Other
|
25
37
|
spec.add_dependency 'git', '~> 1.3'
|
26
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: version-manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Ilya Solo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,48 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.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: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: docopt
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,22 +131,28 @@ extensions: []
|
|
89
131
|
extra_rdoc_files: []
|
90
132
|
files:
|
91
133
|
- ".gitignore"
|
92
|
-
- ".
|
134
|
+
- ".rspec"
|
135
|
+
- ".rubocop.yml"
|
93
136
|
- Gemfile
|
94
137
|
- LICENSE
|
95
138
|
- README.md
|
96
139
|
- Rakefile
|
97
|
-
- bin/console
|
98
|
-
- bin/setup
|
99
140
|
- exe/manver
|
100
141
|
- lib/version-manager.rb
|
142
|
+
- lib/version-manager/action_manager.rb
|
101
143
|
- lib/version-manager/cli.rb
|
102
|
-
- lib/version-manager/
|
144
|
+
- lib/version-manager/release_manager.rb
|
103
145
|
- lib/version-manager/release_version.rb
|
104
146
|
- lib/version-manager/vcs.rb
|
105
147
|
- lib/version-manager/vcs/git.rb
|
106
148
|
- lib/version-manager/version.rb
|
107
149
|
- lib/version-manager/version_storage.rb
|
150
|
+
- spec/features/git_bumping_version_action_spec.rb
|
151
|
+
- spec/features/git_latest_version_action_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
- spec/support/git_repository.rb
|
154
|
+
- spec/support/repository_matchers.rb
|
155
|
+
- spec/support/shared_settings.rb
|
108
156
|
- version-manager.gemspec
|
109
157
|
homepage: https://github.com/isolo/version-manager
|
110
158
|
licenses:
|
@@ -118,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
166
|
requirements:
|
119
167
|
- - ">="
|
120
168
|
- !ruby/object:Gem::Version
|
121
|
-
version: '
|
169
|
+
version: '2.3'
|
122
170
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
171
|
requirements:
|
124
172
|
- - ">="
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.3.1
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "version/manager"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start
|