metasploit-version 0.1.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +32 -0
  4. data/.simplecov +60 -0
  5. data/.travis.yml +26 -0
  6. data/.yardopts +7 -0
  7. data/CONTRIBUTING.md +156 -0
  8. data/Gemfile +17 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +133 -0
  11. data/Rakefile +20 -0
  12. data/features/shared/examples/metasploit/version/gem_version_constant.feature +215 -0
  13. data/features/shared/examples/metasploit/version/version_constant.feature +183 -0
  14. data/features/shared/examples/metasploit/version/version_module.feature +275 -0
  15. data/features/shared/examples/metasploit/version/version_module/prerelease/git/branch.feature +234 -0
  16. data/features/shared/examples/metasploit/version/version_module/prerelease/git/detached_head.feature +97 -0
  17. data/features/shared/examples/metasploit/version/version_module/prerelease/git/master.feature +94 -0
  18. data/features/shared/examples/metasploit/version/version_module/prerelease/git/step_definitions/environment_variable_steps.rb +13 -0
  19. data/features/shared/examples/metasploit/version/version_module/prerelease/git/step_definitions/git_steps.rb +30 -0
  20. data/features/shared/examples/metasploit/version/version_module/prerelease/travis_ci/branch.feature +173 -0
  21. data/features/shared/examples/metasploit/version/version_module/prerelease/travis_ci/master.feature +90 -0
  22. data/features/shared/examples/metasploit/version/version_module/prerelease/travis_ci/pull_request.feature +99 -0
  23. data/features/shared/examples/metasploit/version/version_module/prerelease/travis_ci/tag.feature +277 -0
  24. data/features/support/env.rb +41 -0
  25. data/features/support/simplecov_setup.rb +12 -0
  26. data/lib/metasploit/version.rb +19 -0
  27. data/lib/metasploit/version/branch.rb +172 -0
  28. data/lib/metasploit/version/version.rb +57 -0
  29. data/metasploit-version.gemspec +41 -0
  30. data/spec/lib/metasploit/version/branch_spec.rb +660 -0
  31. data/spec/lib/metasploit/version/version_spec.rb +5 -0
  32. data/spec/lib/metasploit/version_spec.rb +6 -0
  33. data/spec/spec_helper.rb +13 -0
  34. data/spec/support/shared/examples/metasploit/version/gem_version_constant.rb +17 -0
  35. data/spec/support/shared/examples/metasploit/version/version_constant.rb +17 -0
  36. data/spec/support/shared/examples/metasploit/version/version_module.rb +226 -0
  37. metadata +173 -0
@@ -0,0 +1,41 @@
1
+ # Has to be the first file required so that all other files show coverage information
2
+ require 'simplecov'
3
+
4
+ #
5
+ # Standard Library
6
+ #
7
+
8
+ require 'pathname'
9
+
10
+ #
11
+ # Gems
12
+ #
13
+
14
+ require 'aruba/cucumber'
15
+ # only does jruby customization if actually in JRuby
16
+ require 'aruba/jruby'
17
+
18
+ Before do |scenario|
19
+ command_name = case scenario
20
+ when Cucumber::Ast::Scenario, Cucumber::Ast::ScenarioOutline
21
+ "#{scenario.feature.title} #{scenario.name}"
22
+ when Cucumber::Ast::OutlineTable::ExampleRow
23
+ scenario_outline = scenario.scenario_outline
24
+
25
+ "#{scenario_outline.feature.title} #{scenario_outline.name} #{scenario.name}"
26
+ else
27
+ raise TypeError, "Don't know how to extract command name from #{scenario.class}"
28
+ end
29
+
30
+ # Used in simplecov_setup so that each scenario has a different name and their coverage results are merged instead
31
+ # of overwriting each other as 'Cucumber Features'
32
+ set_env('SIMPLECOV_COMMAND_NAME', command_name)
33
+
34
+ simplecov_setup_pathname = Pathname.new(__FILE__).expand_path.parent.join('simplecov_setup')
35
+ # set environment variable so child processes will merge their coverage data with parent process's coverage data.
36
+ set_env('RUBYOPT', "-r#{simplecov_setup_pathname} #{ENV['RUBYOPT']}")
37
+ end
38
+
39
+ Before do
40
+ @aruba_timeout_seconds = 10 * 60
41
+ end
@@ -0,0 +1,12 @@
1
+ # @note this file is loaded in env.rb to setup simplecov using RUBYOPTs for child processes
2
+
3
+ require 'simplecov'
4
+
5
+ require 'pathname'
6
+
7
+ root = Pathname(__FILE__).expand_path.parent.parent.parent
8
+
9
+ SimpleCov.command_name(ENV['SIMPLECOV_COMMAND_NAME'])
10
+ SimpleCov.root(root)
11
+ load root.join('.simplecov')
12
+
@@ -0,0 +1,19 @@
1
+ #
2
+ # Standard Library
3
+ #
4
+
5
+ require 'pathname'
6
+
7
+ #
8
+ # Project
9
+ #
10
+
11
+ require 'metasploit/version/version'
12
+
13
+ # Namespace used across all metasploit gems
14
+ module Metasploit
15
+ # Namespace for this gem.
16
+ module Version
17
+ autoload :Branch, 'metasploit/version/branch'
18
+ end
19
+ end
@@ -0,0 +1,172 @@
1
+ require 'metasploit/version'
2
+
3
+ # Regular expressions for parsing the branch name into its component parts
4
+ module Metasploit::Version::Branch
5
+ #
6
+ # CONSTANTS
7
+ #
8
+
9
+ # Regular expression that matches, but does not capture an optional prefix of `ref/remotes` for when a branch name is
10
+ # fully qualified on Jenkins. Remote name after `ref/remotes` is captured in `:remote` group.
11
+ JENKINS_PREFIX_REGEXP = %r{(?:ref/remotes/(?<remote>[^/]+)/)?}
12
+
13
+ # Matches runs of alphanumeric characters that are valid in prerelease segments. Prerelease segments must be
14
+ # separated by `.` or `-`.
15
+ PRERELEASE_SEGMENT_REGEXP = /[0-9a-zA-Z]+/
16
+
17
+ # Version pattern allowed by Rubygems for pre-release: runs of alphanumeric characters separated by `.` or `-`.
18
+ # Group is captured to `:prerelease` name.
19
+ PRERELEASE_REGEXP = /(?<prerelease>#{PRERELEASE_SEGMENT_REGEXP}([-.]#{PRERELEASE_SEGMENT_REGEXP})*)/
20
+
21
+ # Regular expression that matches exactly a staging branch. It may
22
+ # {JENKINS_PREFIX_REGEXP optionally start with `ref/remotes`}, followed by a type of `staging`, no story ID, and a
23
+ # {PRERELEASE_REGEXP pre-release name}.
24
+ #
25
+ # @example Staging Branch
26
+ # 'staging/long-running'
27
+ #
28
+ # @example Staging Branch on Jenkins
29
+ # 'ref/remotes/origin/staging/long-running'
30
+ STAGING_REGEXP = %r{
31
+ \A
32
+ #{JENKINS_PREFIX_REGEXP}
33
+ (?<type>staging)
34
+ /
35
+ #{PRERELEASE_REGEXP}
36
+ \z
37
+ }x
38
+
39
+ # Regular expression that matches exactly a chore, feature or bug branch. It may
40
+ # {JENKINS_PREFIX_REGEXP optionally start with `ref/remotes`}, followed by a type of `staging`, story ID, and a
41
+ # {PRERELEASE_REGEXP pre-release name}.
42
+ #
43
+ # @example Bug Branch
44
+ # 'bug/MSP-666/nasty'
45
+ #
46
+ # @example Bug Branch on Jenkins
47
+ # 'ref/remotes/origin/bug/MSP-666/nasty'
48
+ #
49
+ # @example Chore Branch
50
+ # 'chore/MSP-1234/recurring'
51
+ #
52
+ # @example Chore Branch on Jenkins
53
+ # 'ref/remotes/origin/chore/MSP-1234/recurring'
54
+ #
55
+ # @example Feature Branch
56
+ # 'feature/MSP-31337/cool'
57
+ #
58
+ # @example Feature Branch on Jenkins
59
+ # 'ref/remotes/origin/feature/MSP-31337/cool'
60
+ #
61
+ STORY_REGEXP = %r{
62
+ \A
63
+ #{JENKINS_PREFIX_REGEXP}
64
+ (?<type>bug|chore|feature)
65
+ /
66
+ (?<story>[^/]+)
67
+ /
68
+ #{PRERELEASE_REGEXP}
69
+ \z
70
+ }x
71
+
72
+ # Regular expression that matches separator used between {PRERELEASE_SEGMENT_REGEXP prerelease segments} for gem
73
+ # versions and tag versions.
74
+ VERSION_PRERELEASE_SEGMENT_SEPARATOR_REGEXP = /\.pre\./
75
+
76
+ # Regular expression that exactly matches a release or pre-release version tag prefixed with `v` and followed by
77
+ # the major, minor, and patch numbers separated by '.' with an optional prerelease version suffix.
78
+ #
79
+ # @example Releease Tag
80
+ # 'v1.2.3'
81
+ #
82
+ # @example Prerelease Tag
83
+ # 'v1.2.3.pre.cool'
84
+ #
85
+ VERSION_REGEXP = %r{
86
+ \A
87
+ v(?<major>\d+)
88
+ \.
89
+ (?<minor>\d+)
90
+ \.
91
+ (?<patch>\d+)
92
+ (?:
93
+ #{VERSION_PRERELEASE_SEGMENT_SEPARATOR_REGEXP}
94
+ (?<gem_version_prerelease>
95
+ #{PRERELEASE_SEGMENT_REGEXP}
96
+ (#{VERSION_PRERELEASE_SEGMENT_SEPARATOR_REGEXP}#{PRERELEASE_SEGMENT_REGEXP})*
97
+ )
98
+ )?
99
+ \z
100
+ }x
101
+
102
+ # The current branch name from travis-ci or git.
103
+ #
104
+ # @return [String]
105
+ def self.current
106
+ branch = ENV['TRAVIS_BRANCH']
107
+
108
+ if branch.nil? || branch.empty?
109
+ branch = `git rev-parse --abbrev-ref HEAD`.strip
110
+ end
111
+
112
+ branch
113
+ end
114
+
115
+ # Parses the branch
116
+ #
117
+ # @param branch [String] the branch name
118
+ # @return ['HEAD'] if `branch` is 'HEAD' (such as in a detached head state for git)
119
+ # @return ['master'] if `branch` is `master`
120
+ # @return [Hash{type: 'staging', prerelease: String}] if a staging branch
121
+ # @return [Hash{type: String, story: String, prerelease: String}] if not a staging branch
122
+ # @return [Hash{major: Integer, minor: Integer, patch: Integer, prerelease: String}]
123
+ # @return [nil] if `branch` does not match any of the formats
124
+ def self.parse(branch)
125
+ if ['HEAD', 'master'].include? branch
126
+ branch
127
+ else
128
+ match = branch.match(STAGING_REGEXP)
129
+
130
+ if match
131
+ {
132
+ prerelease: match[:prerelease],
133
+ type: match[:type]
134
+ }
135
+ else
136
+ match = branch.match(STORY_REGEXP)
137
+
138
+ if match
139
+ {
140
+ prerelease: match[:prerelease],
141
+ story: match[:story],
142
+ type: match[:type]
143
+ }
144
+ else
145
+ match = branch.match(VERSION_REGEXP)
146
+
147
+ if match
148
+ prerelease = prerelease(match[:gem_version_prerelease])
149
+
150
+ {
151
+ major: match[:major].to_i,
152
+ minor: match[:minor].to_i,
153
+ patch: match[:patch].to_i,
154
+ prerelease: prerelease
155
+ }
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ # Replaces `.pre.` in `gem_version_prerelease` with `-` to undo conversion to rubygems 1.8.6 compatible pre-release
163
+ # version.
164
+ #
165
+ # @return [String] unless `gem_version_prerelease` is `nil`.
166
+ # @return [nil] if `gem_version_prerelease` is `nil`.
167
+ def self.prerelease(gem_version_prerelease)
168
+ unless gem_version_prerelease.nil?
169
+ gem_version_prerelease.gsub('.pre.', '-')
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,57 @@
1
+ module Metasploit
2
+ module Version
3
+ # Holds components of {VERSION} as defined by {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0}.
4
+ module Version
5
+ #
6
+ # Constants
7
+ #
8
+
9
+ # The major version number.
10
+ MAJOR = 0
11
+ # The minor version number, scoped to the {MAJOR} version number.
12
+ MINOR = 1
13
+ # The patch number, scoped to the {MINOR} version number.
14
+ PATCH = 2
15
+
16
+ #
17
+ # Module Methods
18
+ #
19
+
20
+ # The full version string, including the {Metasploit::Version::Version::MAJOR},
21
+ # {Metasploit::Version::Version::MINOR}, {Metasploit::Version::Version::PATCH}, and optionally, the
22
+ # `Metasploit::Version::Version::PRERELEASE` in the
23
+ # {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
24
+ #
25
+ # @return [String] '{Metasploit::Version::Version::MAJOR}.{Metasploit::Version::Version::MINOR}.{Metasploit::Version::Version::PATCH}' on master.
26
+ # '{Metasploit::Version::Version::MAJOR}.{Metasploit::Version::Version::MINOR}.{Metasploit::Version::Version::PATCH}-PRERELEASE'
27
+ # on any branch other than master.
28
+ def self.full
29
+ version = "#{MAJOR}.#{MINOR}.#{PATCH}"
30
+
31
+ if defined? PRERELEASE
32
+ version = "#{version}-#{PRERELEASE}"
33
+ end
34
+
35
+ version
36
+ end
37
+
38
+ # The full gem version string, including the {Metasploit::Version::Version::MAJOR},
39
+ # {Metasploit::Version::Version::MINOR}, {Metasploit::Version::Version::PATCH}, and optionally, the
40
+ # `Metasploit::Version::Version::PRERELEASE` in the
41
+ # {http://guides.rubygems.org/specification-reference/#version RubyGems versioning} format.
42
+ #
43
+ # @return [String] '{Metasploit::Version::Version::MAJOR}.{Metasploit::Version::Version::MINOR}.{Metasploit::Version::Version::PATCH}'
44
+ # on master. '{Metasploit::Version::Version::MAJOR}.{Metasploit::Version::Version::MINOR}.{Metasploit::Version::Version::PATCH}.PRERELEASE'
45
+ # on any branch other than master.
46
+ def self.gem
47
+ full.gsub('-', '.pre.')
48
+ end
49
+ end
50
+
51
+ # (see Version.gem)
52
+ GEM_VERSION = Version.gem
53
+
54
+ # (see Version.full)
55
+ VERSION = Version.full
56
+ end
57
+ end
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'metasploit/version/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'metasploit-version'
8
+ spec.version = Metasploit::Version::GEM_VERSION
9
+ spec.authors = ['Luke Imhoff']
10
+ spec.email = ['luke_imhoff@rapid7.com']
11
+ spec.summary = 'Semantic versioning helpers and shared examples'
12
+ spec.description = "Metasploit::Version::Full for deriving String VERSION from constants in Version module and " \
13
+ "shared examples: 'Metasploit::Version VERSION constant' to check VERSION and " \
14
+ "'Metasploit::Version Version Module' to check Version."
15
+ spec.homepage = 'https://github.com/rapid7/metasploit-version'
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.5"
24
+ spec.add_development_dependency 'metasploit-yard', '~> 1.0'
25
+ spec.add_development_dependency "rake"
26
+
27
+
28
+ if RUBY_PLATFORM =~ /java/
29
+ # markdown library for YARD to enable proper parsing of README.md and CONTRIBUTING.md
30
+ spec.add_development_dependency 'kramdown'
31
+
32
+ spec.platform = Gem::Platform::JAVA
33
+ else
34
+ # markdown library for YARD to enable proper parsing of README.md and CONTRIBUTING.md
35
+ spec.add_development_dependency 'redcarpet'
36
+
37
+ spec.platform = Gem::Platform::RUBY
38
+ end
39
+
40
+ spec.add_runtime_dependency 'rspec'
41
+ end
@@ -0,0 +1,660 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metasploit::Version::Branch do
4
+ context 'CONSTANTS' do
5
+ context 'JENKINS_PREFIX_REGEXP' do
6
+ subject(:jenkins_prefix_regexp) {
7
+ described_class::JENKINS_PREFIX_REGEXP
8
+ }
9
+
10
+ it "matches 'ref/remotes/' by itself" do
11
+ expect(jenkins_prefix_regexp).to match('ref/remotes/')
12
+ end
13
+
14
+ it "matches 'ref/remotes/' prefix" do
15
+ expect(jenkins_prefix_regexp).to match('ref/remotes/remote-name')
16
+ end
17
+
18
+ it 'matches nothing' do
19
+ expect(jenkins_prefix_regexp).to match('')
20
+ end
21
+ end
22
+
23
+ context 'PRERELEASE_REGEXP' do
24
+ subject(:prerelease_regexp) {
25
+ described_class::PRERELEASE_REGEXP
26
+ }
27
+
28
+ it 'matches a single segment' do
29
+ expected_prerelease = 'singlesegment'
30
+ match = prerelease_regexp.match(expected_prerelease)
31
+
32
+ expect(match).not_to be_nil
33
+ expect(match[:prerelease]).to eq(expected_prerelease)
34
+ end
35
+
36
+ it "matches segments separated by '-'" do
37
+ expected_prerelease = 'first-second'
38
+ match = prerelease_regexp.match(expected_prerelease)
39
+
40
+ expect(match).not_to be_nil
41
+ expect(match[:prerelease]).to eq(expected_prerelease)
42
+ end
43
+
44
+ it "matches segmented separated by '.'" do
45
+ expected_prerelease = 'first.second'
46
+ match = prerelease_regexp.match(expected_prerelease)
47
+
48
+ expect(match).not_to be_nil
49
+ expect(match[:prerelease]).to eq(expected_prerelease)
50
+ end
51
+
52
+ it "matches segmented separated by a mix of '.' and '-'" do
53
+ expected_prerelease = 'first.second-third'
54
+ match = prerelease_regexp.match(expected_prerelease)
55
+
56
+ expect(match).not_to be_nil
57
+ expect(match[:prerelease]).to eq(expected_prerelease)
58
+ end
59
+ end
60
+
61
+ context 'PRERELEASE_SEGMENT_REGEXP' do
62
+ subject(:prerelease_segment_regexp) {
63
+ described_class::PRERELEASE_SEGMENT_REGEXP
64
+ }
65
+
66
+ it 'does not match an empty string' do
67
+ expect(prerelease_segment_regexp).not_to match('')
68
+ end
69
+
70
+ it 'matches 0-9, a-z, and A-Z' do
71
+ ranges = [
72
+ '0'..'9',
73
+ 'a'..'z',
74
+ 'A'..'Z'
75
+ ]
76
+ string = ranges.map(&:to_a).map(&:join).join
77
+
78
+ expect(prerelease_segment_regexp).to match(string)
79
+ end
80
+ end
81
+
82
+ context 'STAGING_REGEXP' do
83
+ subject(:staging_regexp) {
84
+ described_class::STAGING_REGEXP
85
+ }
86
+
87
+ it 'matches staging branch' do
88
+ expect(staging_regexp).to match('staging/long-running')
89
+ end
90
+
91
+ it 'does not match bug branch' do
92
+ expect(staging_regexp).not_to match('bug/MSP-1234/nasty')
93
+ end
94
+
95
+ it 'does not match chore branch' do
96
+ expect(staging_regexp).not_to match('chore/MSP-1234/repeating')
97
+ end
98
+
99
+ it 'does not match feature branch' do
100
+ expect(staging_regexp).not_to match('feature/MSP-1234/new-feature')
101
+ end
102
+
103
+ it 'does not match pre-release tag' do
104
+ expect(staging_regexp).not_to match('v1.2.3.pre.release')
105
+ end
106
+
107
+ it 'does not match release tag' do
108
+ expect(staging_regexp).not_to match('v1.2.3')
109
+ end
110
+ end
111
+
112
+ context 'STORY_REGEXP' do
113
+ subject(:story_regexp) {
114
+ described_class::STORY_REGEXP
115
+ }
116
+
117
+ it 'does not match staging branch' do
118
+ expect(story_regexp).not_to match('staging/long-running')
119
+ end
120
+
121
+ context 'type' do
122
+ context 'bug' do
123
+ let(:type) {
124
+ 'bug'
125
+ }
126
+
127
+ context 'with story' do
128
+ it 'matches' do
129
+ expect(story_regexp).to match("#{type}/MSP-1234/nasty")
130
+ end
131
+ end
132
+
133
+ context 'without story' do
134
+ it 'does not match' do
135
+ expect(story_regexp).not_to match("#{type}/nasty")
136
+ end
137
+ end
138
+ end
139
+
140
+ context 'chore' do
141
+ let(:type) {
142
+ 'chore'
143
+ }
144
+
145
+ context 'with story' do
146
+ it 'matches' do
147
+ expect(story_regexp).to match("#{type}/MSP-1234/repeating")
148
+ end
149
+ end
150
+
151
+ context 'without story' do
152
+ it 'does not match' do
153
+ expect(story_regexp).not_to match("#{type}/repeating")
154
+ end
155
+ end
156
+ end
157
+
158
+ context 'feature' do
159
+ let(:type) {
160
+ 'feature'
161
+ }
162
+
163
+ context 'with story' do
164
+ it 'matches' do
165
+ expect(story_regexp).to match("#{type}/MSP-1234/cool")
166
+ end
167
+ end
168
+
169
+ context 'without story' do
170
+ it 'does not match' do
171
+ expect(story_regexp).not_to match("#{type}/cool")
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ it 'does not match pre-release tag' do
178
+ expect(story_regexp).not_to match('v1.2.3.pre.release')
179
+ end
180
+
181
+ it 'does not match release tag' do
182
+ expect(story_regexp).not_to match('v1.2.3')
183
+ end
184
+ end
185
+
186
+ context 'VERSION_PRERELEASE_SEGMENT_SEPARATOR_REGEXP' do
187
+ subject(:version_prerelease_segment_separator_regexp) {
188
+ described_class::VERSION_PRERELEASE_SEGMENT_SEPARATOR_REGEXP
189
+ }
190
+
191
+ it { is_expected.to match('.pre.') }
192
+
193
+ it "escapes '.' around 'pre'" do
194
+ expect(version_prerelease_segment_separator_regexp).not_to match('aprea')
195
+ end
196
+ end
197
+
198
+ context 'VERSION_REGEXP' do
199
+ subject(:version_regexp) {
200
+ described_class::VERSION_REGEXP
201
+ }
202
+
203
+ it "does not match tag without 'v' prefix" do
204
+ expect(version_regexp).not_to match('1.2.3')
205
+ end
206
+
207
+ it 'matches release tag' do
208
+ expect(version_regexp).to match('v1.2.3')
209
+ end
210
+
211
+ it 'matches prerelease tag' do
212
+ expect(version_regexp).to match('v1.2.3.pre.release')
213
+ end
214
+
215
+ it 'does not match staging branch' do
216
+ expect(version_regexp).not_to match('staging/long-running')
217
+ end
218
+
219
+ it 'does not match bug branch' do
220
+ expect(version_regexp).not_to match('bug/MSP-1234/nasty')
221
+ end
222
+
223
+ it 'does not match chore branch' do
224
+ expect(version_regexp).not_to match('chore/MSP-1234/recurring')
225
+ end
226
+
227
+ it 'does not match feature branch' do
228
+ expect(version_regexp).not_to match('feature/MSP-1234/cool')
229
+ end
230
+ end
231
+ end
232
+
233
+ context 'current' do
234
+ subject(:current) {
235
+ described_class.current
236
+ }
237
+
238
+ around(:each) do |example|
239
+ env_before = ENV.to_hash
240
+
241
+ begin
242
+ example.run
243
+ ensure
244
+ ENV.replace(env_before)
245
+ end
246
+ end
247
+
248
+ context 'with TRAVIS_BRANCH' do
249
+ before(:each) do
250
+ ENV['TRAVIS_BRANCH'] = travis_branch
251
+ end
252
+
253
+ context 'that is empty' do
254
+ let(:travis_branch) {
255
+ ''
256
+ }
257
+
258
+ it 'parses git abbreviated ref' do
259
+ expect(current).to eq(`git rev-parse --abbrev-ref HEAD`.strip)
260
+ end
261
+ end
262
+
263
+ context 'that is not empty' do
264
+ let(:travis_branch) {
265
+ 'feature/MSP-1234/travis-ci'
266
+ }
267
+
268
+ it 'is TRAVIS_BRANCH' do
269
+ expect(current).to eq(travis_branch)
270
+ end
271
+ end
272
+ end
273
+
274
+ context 'without TRAVIS_BRANCH' do
275
+ before(:each) do
276
+ ENV.delete('TRAVIS_BRANCH')
277
+ end
278
+
279
+ it 'parses git abbreviated ref' do
280
+ expect(current).to eq(`git rev-parse --abbrev-ref HEAD`.strip)
281
+ end
282
+ end
283
+ end
284
+
285
+ context 'parse' do
286
+ subject(:parse) {
287
+ described_class.parse(branch)
288
+ }
289
+
290
+ context 'with HEAD' do
291
+ let(:branch) {
292
+ 'HEAD'
293
+ }
294
+
295
+ it { is_expected.to eq('HEAD') }
296
+ end
297
+
298
+ context 'with master' do
299
+ let(:branch) {
300
+ 'master'
301
+ }
302
+
303
+ it { is_expected.to eq('master') }
304
+ end
305
+
306
+ context 'with staging branch' do
307
+ #
308
+ # Shared examples
309
+ #
310
+
311
+ shared_examples_for 'staging branch' do
312
+ it { is_expected.to be_a(Hash) }
313
+
314
+ context '[:prerelease]' do
315
+ subject(:prerelease) {
316
+ parse[:prerelease]
317
+ }
318
+
319
+ it "is name after 'staging/'" do
320
+ expect(prerelease).to eq(expected_prerelease)
321
+ end
322
+ end
323
+
324
+ context '[:type]' do
325
+ subject(:type) {
326
+ parse[:type]
327
+ }
328
+
329
+ it { is_expected.to eq(expected_type) }
330
+ end
331
+ end
332
+
333
+ #
334
+ # lets
335
+ #
336
+
337
+ let(:branch) {
338
+ "#{jenkins_prefix}#{expected_type}/#{expected_prerelease}"
339
+ }
340
+
341
+ let(:expected_prerelease) {
342
+ 'long-running'
343
+ }
344
+
345
+ let(:expected_type) {
346
+ 'staging'
347
+ }
348
+
349
+ context 'with Jenkins prefix' do
350
+ let(:jenkins_prefix) {
351
+ 'ref/remotes/origin/'
352
+ }
353
+
354
+ it_should_behave_like 'staging branch'
355
+ end
356
+
357
+ context 'without Jenkins prefix' do
358
+ let(:jenkins_prefix) {
359
+ ''
360
+ }
361
+
362
+ it_should_behave_like 'staging branch'
363
+ end
364
+ end
365
+
366
+ context 'with story branch' do
367
+ shared_examples_for 'story branch' do
368
+ context 'with story' do
369
+ shared_examples_for 'with story' do
370
+ it { should be_a Hash }
371
+
372
+ context '[:prerelease]' do
373
+ subject(:prerelease) {
374
+ parse[:prerelease]
375
+ }
376
+
377
+ it "is name after last '/'" do
378
+ expect(prerelease).to eq(expected_prerelease)
379
+ end
380
+ end
381
+
382
+ context '[:story]' do
383
+ subject(:story) {
384
+ parse[:story]
385
+ }
386
+
387
+ it 'is middle name' do
388
+ expect(story).to eq(expected_story)
389
+ end
390
+ end
391
+
392
+ context '[:type]' do
393
+ subject(:type) {
394
+ parse[:type]
395
+ }
396
+
397
+ it { is_expected.to eq(expected_type) }
398
+ end
399
+ end
400
+
401
+ let(:expected_story) {
402
+ 'MSP-1234'
403
+ }
404
+
405
+ let(:branch) {
406
+ "#{jenkins_prefix}#{expected_type}/#{expected_story}/#{expected_prerelease}"
407
+ }
408
+
409
+ context 'with Jenkins prefix' do
410
+ let(:jenkins_prefix) {
411
+ 'ref/remotes/upstream/'
412
+ }
413
+
414
+ it_should_behave_like 'with story'
415
+ end
416
+
417
+ context 'without Jenkins prefix' do
418
+ let(:jenkins_prefix) {
419
+ ''
420
+ }
421
+
422
+ it_should_behave_like 'with story'
423
+ end
424
+ end
425
+
426
+ context 'without story' do
427
+ let(:branch) {
428
+ "#{expected_type}/#{expected_prerelease}"
429
+ }
430
+
431
+ it { is_expected.to be_nil }
432
+ end
433
+ end
434
+
435
+ context 'for a bug' do
436
+ let(:expected_prerelease) {
437
+ 'nasty'
438
+ }
439
+
440
+ let(:expected_type) {
441
+ 'bug'
442
+ }
443
+
444
+ it_should_behave_like 'story branch'
445
+ end
446
+
447
+ context 'for a chore' do
448
+ let(:expected_prerelease) {
449
+ 'recurring'
450
+ }
451
+
452
+ let(:expected_type) {
453
+ 'chore'
454
+ }
455
+
456
+ it_should_behave_like 'story branch'
457
+ end
458
+
459
+ context 'for a bug' do
460
+ let(:expected_prerelease) {
461
+ 'cool-new'
462
+ }
463
+
464
+ let(:expected_type) {
465
+ 'feature'
466
+ }
467
+
468
+ it_should_behave_like 'story branch'
469
+ end
470
+ end
471
+
472
+ context 'with version tag' do
473
+ let(:expected_major) {
474
+ 10
475
+ }
476
+
477
+ let(:expected_minor) {
478
+ 20
479
+ }
480
+
481
+ let(:expected_patch) {
482
+ 30
483
+ }
484
+
485
+ context 'for pre-release' do
486
+ let(:branch) {
487
+ "v#{expected_major}.#{expected_minor}.#{expected_patch}.pre.early.pre.release"
488
+ }
489
+
490
+ it { is_expected.to be_a Hash }
491
+
492
+ context '[:major]' do
493
+ subject(:major) {
494
+ parse[:major]
495
+ }
496
+
497
+ it { is_expected.to be_an Integer }
498
+
499
+ it 'is first number in dotted version' do
500
+ expect(major).to eq(expected_major)
501
+ end
502
+ end
503
+
504
+ context '[:minor]' do
505
+ subject(:minor) {
506
+ parse[:minor]
507
+ }
508
+
509
+ it { is_expected.to be_an Integer }
510
+
511
+ it 'is second number in dotted version' do
512
+ expect(minor).to eq(expected_minor)
513
+ end
514
+ end
515
+
516
+ context '[:patch]' do
517
+ subject(:patch) {
518
+ parse[:patch]
519
+ }
520
+
521
+ it { is_expected.to be_an Integer }
522
+
523
+ it 'is third number in dotted version' do
524
+ expect(patch).to eq(expected_patch)
525
+ end
526
+ end
527
+
528
+ context '[:prerelease]' do
529
+ subject(:prerelease) {
530
+ parse[:prerelease]
531
+ }
532
+
533
+ it "converts '.pre.' separators from prerelease back to '-'" do
534
+ expect(prerelease).to eq('early-release')
535
+ end
536
+ end
537
+ end
538
+
539
+ context 'for release' do
540
+ let(:branch) {
541
+ "v#{expected_major}.#{expected_minor}.#{expected_patch}"
542
+ }
543
+
544
+ it { is_expected.to be_a Hash }
545
+
546
+ context '[:major]' do
547
+ subject(:major) {
548
+ parse[:major]
549
+ }
550
+
551
+ it { is_expected.to be_an Integer }
552
+
553
+ it 'is first number in dotted version' do
554
+ expect(major).to eq(expected_major)
555
+ end
556
+ end
557
+
558
+ context '[:minor]' do
559
+ subject(:minor) {
560
+ parse[:minor]
561
+ }
562
+
563
+ it { is_expected.to be_an Integer }
564
+
565
+ it 'is second number in dotted version' do
566
+ expect(minor).to eq(expected_minor)
567
+ end
568
+ end
569
+
570
+ context '[:patch]' do
571
+ subject(:patch) {
572
+ parse[:patch]
573
+ }
574
+
575
+ it { is_expected.to be_an Integer }
576
+
577
+ it 'is third number in dotted version' do
578
+ expect(patch).to eq(expected_patch)
579
+ end
580
+ end
581
+
582
+ context '[:prerelease]' do
583
+ subject(:prerelease) {
584
+ parse[:prerelease]
585
+ }
586
+
587
+ it { is_expected.to be_nil }
588
+ end
589
+ end
590
+ end
591
+
592
+ context 'with malformed bug branch' do
593
+ let(:branch) {
594
+ 'bug/without-story'
595
+ }
596
+
597
+ it { is_expected.to be_nil }
598
+ end
599
+
600
+ context 'with malformed chore branch' do
601
+ let(:branch) {
602
+ 'chore/without-story'
603
+ }
604
+
605
+ it { is_expected.to be_nil }
606
+ end
607
+
608
+ context 'with malformed feature branch' do
609
+ let(:branch) {
610
+ 'feature/without-story'
611
+ }
612
+
613
+ it { is_expected.to be_nil }
614
+ end
615
+
616
+ context 'with malformed version tag' do
617
+ let(:branch) {
618
+ '1.2.3.pre.without.pre.v'
619
+ }
620
+
621
+ it { is_expected.to be_nil }
622
+ end
623
+ end
624
+
625
+ context 'prerelease' do
626
+ subject(:prerelease) {
627
+ described_class.prerelease(gem_version_prerelease)
628
+ }
629
+
630
+ context 'with nil' do
631
+ let(:gem_version_prerelease) {
632
+ nil
633
+ }
634
+
635
+ it { is_expected.to be_nil }
636
+ end
637
+
638
+ context 'without nil' do
639
+ context "with '.pre.'" do
640
+ let(:gem_version_prerelease) {
641
+ 'second.pre.early.pre.release'
642
+ }
643
+
644
+ it "replaces '.pre.' with '-'" do
645
+ expect(prerelease).to eq('second-early-release')
646
+ end
647
+ end
648
+
649
+ context "without '.pre.'" do
650
+ let(:gem_version_prerelease) {
651
+ 'prerelease'
652
+ }
653
+
654
+ it 'is unchanged' do
655
+ expect(prerelease).to eq(gem_version_prerelease)
656
+ end
657
+ end
658
+ end
659
+ end
660
+ end