metasploit-version 0.1.2-java

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.
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