build_promotion_tool 0.1.1

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: 139604ea202fbd5bb530daf19d43f7c3e2a71b8d
4
+ data.tar.gz: e6363b9f29a86fc0319024c85c42a3306f091824
5
+ SHA512:
6
+ metadata.gz: f044c063bd5b9c59d47d889bd4bcfcba5dccd7b63c5979f582e307ed5b9f123d256abbee5301b75245d5ee5747321af9f27bfd522fb13d10a9da4df205c9704e
7
+ data.tar.gz: 68d5e39e0f435a0b37263f0217169a1045f0d7ac2ceb375ad38cb08af4261becd09a3eaae019d936ed917b1b3bb05a2e8140f89f9548fc6d87a9917ee19d6cf7
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.14.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in build_promotion_tool.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # BuildPromotionTool
2
+
3
+ The purpose of this tool is to automate semantic versioning updates to git tags. It will update the tag version number depending on the type of tag to be applied. The types of tags which can be applied are outlined in the config.yml file. A remote repository must exist in order to fetch all tags and to push new tags to the remote repository.
4
+
5
+ To apply the **first deploy tag (a develop or 'dev' tag)** , a search for all previously applied develop tags is conducted on the repository (local and remote). The tag version number is incremented, depending on the most recent develop tag version number, and on the type of version update selected (major, minor, or patch). Two develop tags cannot be applied to the same commit
6
+
7
+ To apply a **later tag type (such as stage or test)**, a tag of the preceding tag type must have been applied to the commit e.g. to apply a 'test' tag, a 'dev' tag must exist on the commit. The tag number applied will match that of the preceding tag type.
8
+
9
+ ## Installation
10
+
11
+ Add the following line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'build_promotion_tool'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle install
20
+
21
+ Or install it as:
22
+
23
+ $ gem install build_promotion_tool
24
+
25
+ ## Usage
26
+
27
+ __First Deploy Step: Dev Tag__
28
+ - Run:
29
+ ```
30
+ $ deploy dev
31
+ ```
32
+
33
+ - If no prior develop tag has been assigned, the user will be asked whether they would like to assign the first develop tag. If they select yes, first tag 'dev-v0.0.1' is applied.
34
+ - If previous develop tags have been applied, the latest develop tag is displayed and the user is asked whether they would like to do a _major, minor, or patch_ update. See: [Semantic Versioning](http://semver.org).
35
+ - The user inputs their choice, the user is shown the new tag (e.g. dev-v0.1.2) and is asked to confirm their choice and apply the tag.
36
+ - When the user selects yes to updating the tag, the tag version number is updated.
37
+ - The tag is then added to the repository and pushed to the remote.
38
+
39
+ __Later Deploy Steps: E.g. Test, Stage Tags__
40
+ - To see the list of tags which can be applied, the config.yml file should be reviewed
41
+ - For example run:
42
+ ```
43
+ $ deploy test
44
+ ```
45
+ - A tag can only be applied, if a tag of the preceding type has been applied. E.g. to apply a test tag, a develop tag must exist for this commit; to apply a stage tag, a test tag must exist for this commit. If it does not, an error message is displayed.
46
+ - If the preceding tag type exists for this commit, the user is shown the new tag (e.g. test-v0.1.2) and asked if they would like to apply it.
47
+ - If the user selects yes, then the tag is applied
48
+ - The tag is then added to the repository and pushed to the remote.
49
+
50
+ ## Development
51
+
52
+ After checking out the repo, run `bin/setup` to install dependencies.
53
+
54
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "build_promotion_tool"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
data/bin/deploy ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/build_promotion_tool'
4
+
5
+ BuildPromotionTool::Deploy.new
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'build_promotion_tool/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "build_promotion_tool"
8
+ spec.version = BuildPromotionTool::VERSION
9
+ spec.authors = ["Emily Woods"]
10
+ spec.email = ["emily.woods@theappbusiness.com"]
11
+
12
+ spec.summary = %q{Build promotion tool for updating and applying git tags}
13
+ spec.homepage = "https://github.com/KITSTABEmilyWoods/build-promotion-gem"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.executables = ["deploy"]
19
+ spec.require_paths = ["."]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.14"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.license = 'MIT'
24
+ end
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,20 @@
1
+ class Version
2
+ include Comparable
3
+ attr_accessor :major, :minor, :patch
4
+
5
+ def initialize(version_string)
6
+ array = version_string.split(".")
7
+ self.major = array[0].to_i
8
+ self.minor = array[1].to_i
9
+ self.patch = array[2].to_i
10
+ end
11
+
12
+ def ==(other)
13
+ other.class == self.class && other.major == self.major && other.minor == self.minor && other.patch == self.patch
14
+ end
15
+
16
+ def <=>(other)
17
+ return nil if self.class != other.class
18
+ [self.major, self.minor, self.patch] <=> [other.major, other.minor, other.patch]
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ require 'yaml'
2
+ filepath = File.join(File.dirname(__FILE__), "config.yml")
3
+ CONFIG = YAML.load_file(filepath)
4
+
5
+ module Config
6
+ def self.tag_types
7
+ CONFIG.fetch('tags')
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ tags:
2
+
3
+ first_deploy_step: dev
4
+
5
+ all_tags:
6
+ - dev
7
+ - test
8
+ - stage
@@ -0,0 +1,88 @@
1
+ require_relative '../generator/develop_tag_generator'
2
+ require_relative '../generator/other_tag_generator'
3
+ require_relative '../helper/git_helper'
4
+ require_relative '../helper/user_comms_helper'
5
+
6
+ class DeployController
7
+
8
+ attr_accessor :environ, :tag_types, :git_helper, :user_comms, :develop_tag_generator, :other_tag_generator
9
+
10
+ def initialize(environ, git_helper, user_comms, develop_tag_generator, other_tag_generator, tag_types)
11
+ self.environ = environ
12
+ self.tag_types = tag_types
13
+ self.git_helper = git_helper
14
+ self.user_comms = user_comms
15
+ self.develop_tag_generator = develop_tag_generator
16
+ self.other_tag_generator = other_tag_generator
17
+ end
18
+
19
+ def environment_choice
20
+ environ.downcase
21
+ @tags_for_this_commit = git_helper.get_tags_for_this_commit
22
+ dev_tag = tag_types['first_deploy_step']
23
+ all_tags = tag_types['all_tags']
24
+
25
+ case environ
26
+ when dev_tag
27
+ if other_tag_generator.tag_exists?(dev_tag, @tags_for_this_commit)
28
+ @user_comms.error_commit_has_dev_tag
29
+ return
30
+ end
31
+
32
+ unless develop_tag_generator.develop_tag_exists?
33
+ @user_comms.tell_user_no_develop_tags
34
+ apply_tag(develop_tag_generator.first_tag)
35
+ else
36
+ to_increment = increment_choice
37
+ next_tag = develop_tag_generator.next_develop_tag(to_increment)
38
+ apply_tag(next_tag)
39
+ end
40
+
41
+ else
42
+ if all_tags.include? environ
43
+ last_tag_index = all_tags.index(environ) - 1
44
+ last_tag_type = all_tags[last_tag_index]
45
+ select_next_tag(last_tag_type, environ)
46
+ else
47
+ @user_comms.error_incorrect_environ
48
+ return
49
+ end
50
+
51
+ end
52
+ @user_comms.say_thank_you
53
+ end
54
+
55
+ private
56
+
57
+ def select_next_tag(last_tag_type, next_tag_type)
58
+ if !other_tag_generator.tag_exists?(last_tag_type, @tags_for_this_commit)
59
+ @user_comms.tell_user_no_tag(last_tag_type)
60
+ elsif other_tag_generator.tag_exists?(next_tag_type, @tags_for_this_commit)
61
+ @user_comms.tell_user_already_a_tag(next_tag_type)
62
+ else
63
+ apply_tag(other_tag_generator.next_tag(last_tag_type, next_tag_type, @tags_for_this_commit))
64
+ end
65
+ end
66
+
67
+ def increment_choice
68
+ loop do
69
+ @user_comms.ask_increment_type
70
+ @to_increment = @user_comms.user_increment_choice
71
+ break if ['major', 'minor', 'patch'].include? @to_increment
72
+ end
73
+ @to_increment
74
+ end
75
+
76
+ def apply_tag(next_tag)
77
+ @user_comms.ask_permissison_to_apply(next_tag)
78
+ loop do
79
+ answer = @user_comms.user_reply_y_or_n
80
+ if answer == "y"
81
+ git_helper.apply_tag(next_tag)
82
+ git_helper.push_tag_to_remote(next_tag)
83
+ end
84
+ @user_comms.say_no_tag_applied if answer =="n"
85
+ break if ['y', 'n'].include? answer
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '../comparator/version'
2
+
3
+ class DevelopTagGenerator
4
+ def initialize(tags)
5
+ @tags = tags
6
+ end
7
+
8
+ def first_tag
9
+ "dev-v0.0.1"
10
+ end
11
+
12
+ def next_develop_tag(to_increment)
13
+ last_version = biggest_version
14
+ case to_increment
15
+ when "major"
16
+ "dev-v#{last_version.major + 1}.0.0"
17
+ when "minor"
18
+ "dev-v#{last_version.major}.#{last_version.minor + 1}.0"
19
+ when "patch"
20
+ "dev-v#{last_version.major}.#{last_version.minor}.#{last_version.patch + 1}"
21
+ end
22
+ end
23
+
24
+ def develop_tag_exists?
25
+ @tags.any? { |tag| /^dev-v\d+.\d+.\d*$/ =~ tag }
26
+ end
27
+
28
+ private
29
+
30
+ def biggest_version
31
+ @tags.select { |tag| /^dev-v\d+.\d+.\d*$/ =~ tag }
32
+ .map { |tag| tag.split("-v")[1] }
33
+ .map { |version_string| Version.new(version_string) }
34
+ .max
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../comparator/version'
2
+
3
+ class OtherTagGenerator
4
+
5
+ def tag_exists?(check_tag_type, tags_for_this_commit)
6
+ tags_for_this_commit.any? {|tag| /^#{check_tag_type}-v\d+.\d+.\d*$/ =~ tag}
7
+ end
8
+
9
+ def next_tag(previous_tag_type, next_tag_type, tags_for_this_commit)
10
+ tags_for_this_commit.select {|tag| /^#{previous_tag_type}-v\d+.\d+.\d*$/ =~ tag}
11
+ .map {|tag| tag.sub(previous_tag_type, next_tag_type)}
12
+ .map {|tag| tag.sub(/\n/, "")}
13
+ .first
14
+ end
15
+
16
+ end
@@ -0,0 +1,23 @@
1
+ class GitHelper
2
+
3
+ def fetch_tags
4
+ `git fetch --tags`
5
+ end
6
+
7
+ def all_tags
8
+ `git tag -l`.lines
9
+ end
10
+
11
+ def get_tags_for_this_commit
12
+ `git tag --points-at HEAD`.lines
13
+ end
14
+
15
+ def apply_tag(tag)
16
+ `git tag #{tag}`
17
+ end
18
+
19
+ def push_tag_to_remote(tag)
20
+ `git push origin #{tag}`
21
+ end
22
+
23
+ end
@@ -0,0 +1,76 @@
1
+ require_relative '../config'
2
+
3
+ class UserCommsHelper
4
+ all_tags = Config.tag_types['all_tags']
5
+ ERROR_INITIALISE_WITH_STRING_IO = "Initialise with StringIO objects"
6
+ TELL_USER_NO_DEVELOP_TAGS = "No develop tags exist for this repository"
7
+ ASK_USER_INCREMENT_TYPE = "Would you like to do a major, minor, or patch increment?"
8
+ ERROR_SELECT_ACCEPTED_INCREMENT_TYPE = "Error: please select major, minor or patch update"
9
+ ERROR_NEXT_TAG_NOT_ASSIGNED = "Next tag has not been assigned"
10
+ ERROR_SELECT_Y_OR_N = "Error: please select y/n"
11
+ ERROR_INCORRECT_ENVIRON = "Error: please select to apply one of the following tags: #{all_tags}\
12
+ \n e.g. ruby deploy.rb #{all_tags.first} \n"
13
+ ERROR_COMMIT_HAS_DEV_TAG = "Error: a develop tag has already been applied to this commit"
14
+
15
+ def initialize(stdout, stdin)
16
+ @stdout = stdout if stdout.respond_to?(:puts)
17
+ @stdin = stdin if stdin.respond_to?(:gets)
18
+ raise ERROR_INITIALISE_WITH_STRING_IO if @stdout.nil? || @stdin.nil?
19
+ end
20
+
21
+ def tell_user_no_develop_tags
22
+ @stdout.puts TELL_USER_NO_DEVELOP_TAGS
23
+ end
24
+
25
+ def ask_increment_type
26
+ @stdout.puts ASK_USER_INCREMENT_TYPE
27
+ end
28
+
29
+ def user_increment_choice
30
+ increment_choice = @stdin.gets.chomp().downcase
31
+ if increment_choice == "major" || increment_choice == "minor" || increment_choice == "patch"
32
+ return increment_choice
33
+ else
34
+ @stdout.puts ERROR_SELECT_ACCEPTED_INCREMENT_TYPE
35
+ end
36
+ end
37
+
38
+ def ask_permissison_to_apply(next_tag)
39
+ raise ERROR_NEXT_TAG_NOT_ASSIGNED if next_tag.nil?
40
+ @stdout.puts "Do you want to apply tag: #{next_tag}? - y/n"
41
+ end
42
+
43
+ def user_reply_y_or_n
44
+ user_choice = @stdin.gets.chomp().downcase
45
+ if user_choice == "y" || user_choice == "n"
46
+ return user_choice
47
+ else
48
+ @stdout.puts ERROR_SELECT_Y_OR_N
49
+ end
50
+ end
51
+
52
+ def say_thank_you
53
+ @stdout.puts "Thank you!"
54
+ end
55
+
56
+ def say_no_tag_applied
57
+ @stdout.puts "No tag applied"
58
+ end
59
+
60
+ def error_incorrect_environ
61
+ @stdout.puts ERROR_INCORRECT_ENVIRON
62
+ end
63
+
64
+ def error_commit_has_dev_tag
65
+ @stdout.puts ERROR_COMMIT_HAS_DEV_TAG
66
+ end
67
+
68
+ def tell_user_no_tag(tag_type)
69
+ @stdout.puts "Error: there are no previous #{tag_type} tags on this commit"
70
+ end
71
+
72
+ def tell_user_already_a_tag(tag_type)
73
+ @stdout.puts "Error: There is already a #{tag_type} tag on this commit"
74
+ end
75
+
76
+ end
@@ -0,0 +1,180 @@
1
+ require 'rspec'
2
+ require_relative '../controller/deploy_controller.rb'
3
+
4
+ describe 'DeployController' do
5
+
6
+ let(:develop_tag_generator) {spy('develop_tag_generator')}
7
+ let(:git_helper) { spy('git_helper') }
8
+ let(:user_comms) { spy('user_comms') }
9
+ let(:other_tag_generator) { spy('other_tag_generator') }
10
+ let(:tag_types) { { "first_deploy_step" => 'dev', "all_tags" => ['dev', 'test', 'stage'] } }
11
+
12
+ describe 'environment_choice' do
13
+
14
+ subject(:deploy) {DeployController.new('dev', git_helper, user_comms, develop_tag_generator, other_tag_generator,tag_types)}
15
+
16
+ before(:each) do
17
+ allow(git_helper).to receive(:get_tags_for_this_commit)
18
+ tag_types['first_deploy_step']
19
+ end
20
+
21
+ describe 'dev_tag' do
22
+ context 'when the user request to apply a new develop tag with patch increment' do
23
+ before(:each) do
24
+ @dev_tag = 'dev-v0.1.2'
25
+ allow(other_tag_generator).to receive(:tag_exists?).and_return(false)
26
+ allow(develop_tag_generator).to receive(:develop_tag_exists?).and_return(true)
27
+
28
+ allow(user_comms).to receive(:ask_increment_type)
29
+ allow(user_comms).to receive(:user_increment_choice).and_return('patch')
30
+ allow(develop_tag_generator).to receive(:next_develop_tag).and_return(@dev_tag)
31
+ allow(user_comms).to receive(:ask_permissison_to_apply)
32
+ end
33
+
34
+ context 'when they say yes to applying the tag' do
35
+ before(:each) do
36
+ allow(user_comms).to receive(:user_reply_y_or_n).and_return('y')
37
+ end
38
+
39
+ it "asks the user's perimission to apply tag dev-v0.1.2" do
40
+ deploy.environment_choice
41
+ expect(user_comms).to have_received(:ask_permissison_to_apply).with(@dev_tag)
42
+ end
43
+
44
+ it 'receives the next tag to apply' do
45
+ deploy.environment_choice
46
+ expect(git_helper).to have_received(:apply_tag).with(@dev_tag)
47
+ end
48
+
49
+ it 'pushes next tag to the remote' do
50
+ deploy.environment_choice
51
+ expect(git_helper).to have_received(:push_tag_to_remote).with(@dev_tag)
52
+ end
53
+
54
+ it "says 'thank you' to the user" do
55
+ deploy.environment_choice
56
+ expect(user_comms).to have_received(:say_thank_you)
57
+ end
58
+ end
59
+
60
+ context 'when they say no to applying the tag' do
61
+ before(:each) do
62
+ allow(user_comms).to receive(:user_reply_y_or_n).and_return('n')
63
+ end
64
+
65
+ it'says that no tag has been applied' do
66
+ deploy.environment_choice
67
+ expect(user_comms).to have_received(:say_no_tag_applied)
68
+ end
69
+
70
+ it "says 'thank you' to the user" do
71
+ deploy.environment_choice
72
+ expect(user_comms).to have_received(:say_thank_you)
73
+ end
74
+ end
75
+
76
+ context 'when there is already a develop tag on the commit'do
77
+ before(:each) do
78
+ allow(other_tag_generator).to receive(:tag_exists?).and_return(true)
79
+ end
80
+
81
+ it "tells the user that there is already at dev tag on the commit" do
82
+ deploy.environment_choice
83
+ expect(user_comms).to have_received(:error_commit_has_dev_tag)
84
+ end
85
+ end
86
+
87
+ context 'when there are no tags on the repository'do
88
+ before(:each) do
89
+ @dev_tag = 'dev-v0.0.1'
90
+ allow(other_tag_generator).to receive(:tag_exists?).and_return(false)
91
+ allow(develop_tag_generator).to receive(:develop_tag_exists?).and_return(false)
92
+
93
+ allow(user_comms).to receive(:tell_user_no_develop_tags)
94
+ allow(develop_tag_generator).to receive(:first_tag).and_return(@dev_tag)
95
+
96
+ allow(user_comms).to receive(:ask_permissison_to_apply)
97
+ allow(user_comms).to receive(:user_reply_y_or_n).and_return('y')
98
+ end
99
+
100
+ it "asks the user's permission to apply the first tag" do
101
+ deploy.environment_choice
102
+ expect(user_comms).to have_received(:ask_permissison_to_apply).with(@dev_tag)
103
+ end
104
+
105
+ it "applies the first tag" do
106
+ deploy.environment_choice
107
+ expect(git_helper).to have_received(:apply_tag).with(@dev_tag)
108
+ end
109
+
110
+ it "pushes the first tag" do
111
+ deploy.environment_choice
112
+ expect(git_helper).to have_received(:push_tag_to_remote).with(@dev_tag)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ describe 'else' do
119
+ before(:each) do
120
+ @tags_for_this_commit = ['dev-v0.1.1', 'dev-v0.2.0']
121
+ allow(git_helper).to receive(:get_tags_for_this_commit).and_return(@tags_for_this_commit)
122
+ @all_tags = tag_types['all_tags']
123
+ end
124
+
125
+ context ' when the user would like to apply a test tag'do
126
+
127
+ subject(:deploy) {DeployController.new('test', git_helper, user_comms, develop_tag_generator, other_tag_generator, tag_types)}
128
+
129
+ context 'when there is a develop tag, dev-v0.1.5 on the commit' do
130
+ before(:each) do
131
+ @test_tag = 'test-v0.1.5'
132
+
133
+ allow(@all_tags).to receive(:include?).and_return(true)
134
+ allow(@all_tags).to receive(:index).and_return(1)
135
+
136
+ allow(other_tag_generator).to receive(:tag_exists?).with('dev', @tags_for_this_commit).and_return(true)
137
+ allow(other_tag_generator).to receive(:tag_exists?).with('test', @tags_for_this_commit).and_return(false)
138
+
139
+ allow(other_tag_generator).to receive(:next_tag).and_return(@test_tag)
140
+
141
+ allow(user_comms).to receive(:ask_permissison_to_apply)
142
+ allow(user_comms).to receive(:user_reply_y_or_n).and_return('y')
143
+ end
144
+
145
+ context 'when the user says yes to applying the next tag' do
146
+ before(:each) do
147
+ allow(user_comms).to receive(:user_reply_y_or_n).and_return('y')
148
+ end
149
+
150
+ it 'asks permission to apply test tag, test-v0.1.5' do
151
+ deploy.environment_choice
152
+ expect(user_comms).to have_received(:ask_permissison_to_apply).with(@test_tag)
153
+ end
154
+
155
+ it 'applies a test tag, test-v0.1.5' do
156
+ deploy.environment_choice
157
+ expect(git_helper).to have_received(:push_tag_to_remote).with(@test_tag)
158
+ end
159
+ end
160
+
161
+ context 'when the user says no to applying the next tag' do
162
+ before(:each) do
163
+ allow(user_comms).to receive(:user_reply_y_or_n).and_return('n')
164
+ end
165
+
166
+ it 'asks permission to apply test tag, test-v0.1.5' do
167
+ deploy.environment_choice
168
+ expect(user_comms).to have_received(:ask_permissison_to_apply).with(@test_tag)
169
+ end
170
+
171
+ it 'says no tag has been applied' do
172
+ deploy.environment_choice
173
+ expect(user_comms).to have_received(:say_no_tag_applied)
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,81 @@
1
+ require 'rspec'
2
+ require_relative '../generator/develop_tag_generator'
3
+
4
+ describe 'DevelopTagGenerator' do
5
+ describe 'develop_tag_exists' do
6
+ context 'When there are no tags' do
7
+ subject(:develop_tag_generator) { DevelopTagGenerator.new([]) }
8
+
9
+ it 'says that there are no develop tags' do
10
+ expect(develop_tag_generator.develop_tag_exists?).to eql(false)
11
+ end
12
+ end
13
+
14
+ context 'When there is a develop tag' do
15
+ subject(:develop_tag_generator) { DevelopTagGenerator.new(['dev-v0.1.1']) }
16
+
17
+ it 'says there is a develop tag' do
18
+ expect(develop_tag_generator.develop_tag_exists?).to eql(true)
19
+ end
20
+ end
21
+
22
+ context 'When there is a tag kind of like dev-v0.1.1' do
23
+ subject(:develop_tag_generator) { DevelopTagGenerator.new(['dev-v0.1.1fjasjafsjaf']) }
24
+
25
+ it "says there isn't a develop tag" do
26
+ expect(develop_tag_generator.develop_tag_exists?).to eql(false)
27
+ end
28
+ end
29
+
30
+ context 'When there is a test tag' do
31
+ subject(:develop_tag_generator) { DevelopTagGenerator.new(['test-v0.1.1']) }
32
+
33
+ it "says there isn't a develop tag" do
34
+ expect(develop_tag_generator.develop_tag_exists?).to eql(false)
35
+ end
36
+ end
37
+
38
+ context 'When there are multiple tags and one develop tag' do
39
+ subject(:develop_tag_generator) { DevelopTagGenerator.new(['test-v0.1.1', 'stage-v0.0.1', 'hello', 'dev-v0.0.1']) }
40
+
41
+ it 'says there is a develop tag' do
42
+ expect(develop_tag_generator.develop_tag_exists?).to eql(true)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'first_tag' do
48
+ subject(:develop_tag_generator) { DevelopTagGenerator.new([]) }
49
+
50
+ context 'When the first develop tag is required' do
51
+ it 'says the first develop tag is dev-v0.0.1' do
52
+ expect(develop_tag_generator.first_tag).to match('dev-v0.0.1')
53
+ end
54
+
55
+ it 'says the first develop tag is not blank' do
56
+ expect(develop_tag_generator.first_tag).not_to match(" ")
57
+ end
58
+ end
59
+ end
60
+
61
+ describe 'next_develop_tag' do
62
+ context 'When there are multiple tags' do
63
+ subject(:develop_tag_generator) { DevelopTagGenerator.new(['hello', 'test-v0.0.1', 'dev-v0.0.1', 'dev-v1.1.1', 'dev-v0.0.1']) }
64
+
65
+ it 'returns the next version for major update' do
66
+ next_tag = develop_tag_generator.next_develop_tag("major")
67
+ expect(next_tag).to eq("dev-v2.0.0")
68
+ end
69
+
70
+ it 'returns the next version for minor update' do
71
+ next_tag = develop_tag_generator.next_develop_tag("minor")
72
+ expect(next_tag).to eq("dev-v1.2.0")
73
+ end
74
+
75
+ it 'returns the next version for patch update' do
76
+ next_tag = develop_tag_generator.next_develop_tag("patch")
77
+ expect(next_tag).to eq("dev-v1.1.2")
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,84 @@
1
+ require 'rspec'
2
+ require_relative '../generator/other_tag_generator'
3
+
4
+ describe 'OtherTagGenerator' do
5
+ subject(:other_tag_generator) { OtherTagGenerator.new }
6
+
7
+ describe 'tag_exists?' do
8
+ before(:each) do
9
+ @check_tag_type = 'dev'
10
+ end
11
+
12
+ context 'when there are no develop tags on the commit but there are other tags' do
13
+ it 'says there are no develop tag' do
14
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['test-v1.1.1', 'test-v1.2.1'])).to eql(false)
15
+ end
16
+ end
17
+
18
+ context 'when there are no tags on the commit' do
19
+ it 'says there are no develop tag' do
20
+ expect(other_tag_generator.tag_exists?(@check_tag_type, [])).to eql(false)
21
+ end
22
+ end
23
+
24
+ context 'when there is a develop tag on the commit' do
25
+ it 'says there is a develop tag' do
26
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['dev-v0.1.1'])).to eql(true)
27
+ end
28
+ end
29
+
30
+ context 'when there is both a develop and test tag on the commit' do
31
+ it 'says there is a develop tag' do
32
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['dev-v0.1.1', 'test-v0.1.1'])).to eql(true)
33
+ end
34
+ end
35
+
36
+ context 'when there is a tag kind of like deveop' do
37
+ it 'says there is a develop tag' do
38
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['dev-v0.1.1adljalal'])).to eql(false)
39
+ end
40
+ end
41
+
42
+ context 'when there is a different tag type' do
43
+ it 'says there is a develop tag' do
44
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['hello'])).to eql(false)
45
+ end
46
+ end
47
+
48
+ context 'when there are more than one dev tags' do
49
+ it 'says there is a develop tag' do
50
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['dev-v0.1.1', 'dev-v0.1.2'])).to eql(true)
51
+ end
52
+ end
53
+
54
+ context 'when there is already a test tag' do
55
+ before(:each) do
56
+ @check_tag_type = 'test'
57
+ end
58
+
59
+ it 'says there is a test tag' do
60
+ expect(other_tag_generator.tag_exists?(@check_tag_type, ['test-v0.1.1'])).to eql(true)
61
+ end
62
+ end
63
+ end
64
+
65
+ describe 'next_tag' do
66
+ before(:each) do
67
+ @previous_tag_type = 'dev'
68
+ @next_tag_type = 'test'
69
+ end
70
+
71
+ context 'when there is a develop tag: dev-v0.1.1' do
72
+ it 'returns a test tag: test-v0.1.1' do
73
+ expect(other_tag_generator.next_tag(@previous_tag_type, @next_tag_type, ['dev-v0.1.1'])).to eql('test-v0.1.1')
74
+ end
75
+ end
76
+
77
+ context 'when there are more than one dev tags' do
78
+ it 'returns the first' do
79
+ expect(other_tag_generator.next_tag(@previous_tag_type, @next_tag_type,['dev-v0.1.1', 'dev-v0.1.2', 'dev-v0.2.1'])).to eql('test-v0.1.1')
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,145 @@
1
+ require 'rspec'
2
+ require_relative '../helper/user_comms_helper.rb'
3
+
4
+ describe 'UserCommsHelper' do
5
+ let(:stdout) {spy('STDOUT')}
6
+ let(:stdin) {spy('STDIN')}
7
+
8
+ describe 'initialize' do
9
+ context 'when all class arguments received are null' do
10
+ it 'raises an error' do
11
+ expect { UserCommsHelper.new(nil, nil) }.to raise_error.with_message(UserCommsHelper::ERROR_INITIALISE_WITH_STRING_IO)
12
+ end
13
+ end
14
+
15
+ context 'when STDOUT is null but STDIN is not' do
16
+ it 'raises an error' do
17
+ expect { UserCommsHelper.new(nil, stdin) }.to raise_error.with_message(UserCommsHelper::ERROR_INITIALISE_WITH_STRING_IO)
18
+ end
19
+ end
20
+
21
+ context 'when STDIN is null but STDOUT is not' do
22
+ it 'raises an error' do
23
+ expect { UserCommsHelper.new(stdout, nil) }.to raise_error.with_message(UserCommsHelper::ERROR_INITIALISE_WITH_STRING_IO)
24
+ end
25
+ end
26
+ end
27
+
28
+ subject(:user_comms) { UserCommsHelper.new(stdout, stdin) }
29
+
30
+ describe 'tell_user_no_develop_tags' do
31
+ context 'when there are no develop tags in the repository' do
32
+ it 'outputs a response that there are no develop tags' do
33
+ user_comms.tell_user_no_develop_tags
34
+ expect(stdout).to have_received(:puts).with(UserCommsHelper::TELL_USER_NO_DEVELOP_TAGS)
35
+ end
36
+ end
37
+
38
+ describe 'ask_user_to_increment' do
39
+ context 'when the user is asked to select an increment choice' do
40
+ it "outputs 'major, minor, or patch?' to the console" do
41
+ user_comms.ask_increment_type
42
+ expect(stdout).to have_received(:puts).with(UserCommsHelper::ASK_USER_INCREMENT_TYPE)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'user_increment_choice' do
48
+ before(:each) do
49
+ allow(stdin).to receive(:gets).and_return("major")
50
+ end
51
+
52
+ context 'when the user inputs their increment choice as major' do
53
+ it "should accept the user's input as 'major'" do
54
+ expect(user_comms.user_increment_choice).to eq("major")
55
+ end
56
+
57
+ it "should not return minor as a response" do
58
+ expect(user_comms.user_increment_choice).not_to eql("minor")
59
+ end
60
+ end
61
+
62
+ context "when the user inputs a choice which is not major, minor, or patch" do
63
+ it "returns an error asking the user to choose major, minor, or patch" do
64
+ allow(stdin).to receive(:gets).and_return("hello")
65
+ user_comms.user_increment_choice
66
+ expect(stdout).to have_received(:puts).with(UserCommsHelper::ERROR_SELECT_ACCEPTED_INCREMENT_TYPE)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe 'ask_permissison_to_apply' do
72
+ context 'when asked permission to apply tag: dev-v1.1.1' do
73
+ before(:each) do
74
+ @next_tag = "dev-v1.1.1"
75
+ end
76
+
77
+ it 'asks if user would like to apply the next tag' do
78
+ user_comms.ask_permissison_to_apply(@next_tag)
79
+ expect(stdout).to have_received(:puts).with("Do you want to apply tag: #{@next_tag}? - y/n")
80
+ end
81
+ end
82
+
83
+ context 'when a null value is received for the next tag' do
84
+ before(:each) do
85
+ @next_tag = nil
86
+ end
87
+
88
+ it 'raises an exception if no value assigned to tag' do
89
+ expect{user_comms.ask_permissison_to_apply(@next_tag)}.to raise_error.with_message(UserCommsHelper::ERROR_NEXT_TAG_NOT_ASSIGNED)
90
+ end
91
+ end
92
+ end
93
+
94
+ describe 'user_reply_y_or_n' do
95
+ context "when the user inputs their choice as yes 'y'" do
96
+ it "should accept the user's input as 'y'" do
97
+ allow(stdin).to receive(:gets).and_return("y")
98
+ expect(user_comms.user_reply_y_or_n).to eq("y")
99
+ end
100
+
101
+ it "should not accept the user's input as negative, 'n'" do
102
+ allow(stdin).to receive(:gets).and_return("y")
103
+ expect(user_comms.user_reply_y_or_n).not_to eql("n")
104
+ end
105
+ end
106
+
107
+ context "when the user inputs their choice as something other than 'y' or 'n'" do
108
+ it "returns an error telling the user that they need to input yes or no" do
109
+ allow(stdin).to receive(:gets).and_return('u')
110
+ user_comms.user_reply_y_or_n
111
+ expect(stdout).to have_received(:puts).with(UserCommsHelper::ERROR_SELECT_Y_OR_N)
112
+ end
113
+ end
114
+ end
115
+
116
+ describe 'tell_user_no_tag'do
117
+ context 'when the there are no develop tags on the commit' do
118
+ @tag_type = 'develop'
119
+ it 'tells the user that there is no develop tag' do
120
+ user_comms.tell_user_no_tag(@tag_type)
121
+ expect(stdout).to have_received(:puts).with("Error: there are no previous #{@tag_type} tags on this commit")
122
+ end
123
+ end
124
+ end
125
+
126
+ describe 'tell_user_already_a_tag'do
127
+ context 'when there is already a test tag on the commit' do
128
+ @tag_type = 'test'
129
+ it 'tells the user that there is already a test tag' do
130
+ user_comms.tell_user_already_a_tag(@tag_type)
131
+ expect(stdout).to have_received(:puts).with("Error: There is already a #{@tag_type} tag on this commit")
132
+ end
133
+ end
134
+ end
135
+
136
+ describe 'say_thank_you' do
137
+ context 'when the user has made a decision' do
138
+ it 'outputs thank you' do
139
+ user_comms.say_thank_you
140
+ expect(stdout).to have_received(:puts).with("Thank you!")
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,39 @@
1
+ require 'rspec'
2
+ require_relative '../comparator/version'
3
+
4
+ def expectBigger(smaller, bigger)
5
+ expect(smaller <=> bigger).to eql(-1)
6
+ expect(bigger <=> smaller).to eql(1)
7
+ expect(smaller <=> smaller).to eql(0)
8
+ expect(bigger <=> bigger).to eql(0)
9
+ end
10
+
11
+ describe 'Version' do
12
+ it 'initializes with version string' do
13
+ version = Version.new("1.1.2")
14
+ expect(version.major).to eql(1)
15
+ expect(version.minor).to eql(1)
16
+ expect(version.patch).to eql(2)
17
+ end
18
+
19
+ it 'compares' do
20
+ version1 = Version.new("1.1.2")
21
+ version2 = Version.new("1.1.3")
22
+ version3 = Version.new("1.2.1")
23
+ version4 = Version.new("1.2.3")
24
+ version5 = Version.new("4.1.1")
25
+ version6 = Version.new("4.2.1")
26
+
27
+ expectBigger(version1, version2)
28
+ expectBigger(version2, version3)
29
+ expectBigger(version3, version4)
30
+ expectBigger(version4, version5)
31
+ expectBigger(version5, version6)
32
+ expectBigger(version2, version6)
33
+ end
34
+
35
+ it 'does not compare with strings' do
36
+ version1 = Version.new("1.1.2")
37
+ expect(version1 <=> "hello").to eql(nil)
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module BuildPromotionTool
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "./build_promotion_tool/version"
2
+ require_relative "./build_promotion_tool/config.rb"
3
+ require_relative './build_promotion_tool/controller/deploy_controller'
4
+
5
+ module BuildPromotionTool
6
+ class Deploy
7
+ include Config
8
+
9
+ user_comms = UserCommsHelper.new(STDOUT, STDIN)
10
+ git_helper = GitHelper.new
11
+ git_helper.fetch_tags
12
+ tags = git_helper.all_tags
13
+ tags.select {|tag| /^dev|test|stage-v\d+.\d+.\d*$/ =~ tag}
14
+ develop_tag_generator = DevelopTagGenerator.new(tags)
15
+ if ARGV[0].nil?
16
+ user_comms.error_incorrect_environ
17
+ else
18
+ deploy = DeployController.new(ARGV[0], git_helper, user_comms, develop_tag_generator, OtherTagGenerator.new, Config.tag_types)
19
+ deploy.environment_choice
20
+ end
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: build_promotion_tool
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Emily Woods
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description:
42
+ email:
43
+ - emily.woods@theappbusiness.com
44
+ executables:
45
+ - deploy
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".travis.yml"
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/deploy
56
+ - bin/setup
57
+ - build_promotion_tool.gemspec
58
+ - lib/build_promotion_tool.rb
59
+ - lib/build_promotion_tool/.rspec
60
+ - lib/build_promotion_tool/comparator/version.rb
61
+ - lib/build_promotion_tool/config.rb
62
+ - lib/build_promotion_tool/config.yml
63
+ - lib/build_promotion_tool/controller/deploy_controller.rb
64
+ - lib/build_promotion_tool/generator/develop_tag_generator.rb
65
+ - lib/build_promotion_tool/generator/other_tag_generator.rb
66
+ - lib/build_promotion_tool/helper/git_helper.rb
67
+ - lib/build_promotion_tool/helper/user_comms_helper.rb
68
+ - lib/build_promotion_tool/spec/deploy_spec.rb
69
+ - lib/build_promotion_tool/spec/develop_spec.rb
70
+ - lib/build_promotion_tool/spec/other_tag_spec.rb
71
+ - lib/build_promotion_tool/spec/user_comms_spec.rb
72
+ - lib/build_promotion_tool/spec/version_spec.rb
73
+ - lib/build_promotion_tool/version.rb
74
+ homepage: https://github.com/KITSTABEmilyWoods/build-promotion-gem
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - "."
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.5.1
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Build promotion tool for updating and applying git tags
98
+ test_files: []