metasploit-version 0.1.2-java → 0.1.3-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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.travis.yml +10 -3
  4. data/CHANGELOG.md +6 -0
  5. data/CONTRIBUTING.md +10 -44
  6. data/Gemfile +12 -8
  7. data/RELEASING.md +86 -0
  8. data/Rakefile +5 -4
  9. data/UPGRADING.md +1 -0
  10. data/app/templates/.rspec.tt +2 -0
  11. data/app/templates/CHANGELOG.md.tt +18 -0
  12. data/app/templates/CONTRIBUTING.md.tt +122 -0
  13. data/app/templates/RELEASING.md.tt +99 -0
  14. data/app/templates/Rakefile.tt +7 -0
  15. data/app/templates/UPGRADING.md.tt +1 -0
  16. data/app/templates/lib/versioned/version.rb.tt +64 -0
  17. data/app/templates/spec/lib/versioned/version_spec.rb.tt +3 -0
  18. data/app/templates/spec/lib/versioned_spec.rb.tt +4 -0
  19. data/app/templates/spec/spec_helper.rb.tt +76 -0
  20. data/bin/metasploit-version +12 -0
  21. data/config/cucumber.yml +3 -0
  22. data/features/metasploit-version/install/add_development_dependency.feature +68 -0
  23. data/features/metasploit-version/install/bundle_install.feature +24 -0
  24. data/features/metasploit-version/install/changelog.feature +29 -0
  25. data/features/metasploit-version/install/conflict.feature +45 -0
  26. data/features/metasploit-version/install/contributing.feature +139 -0
  27. data/features/metasploit-version/install/namespace_spec/gem_version_constant.feature +154 -0
  28. data/features/metasploit-version/install/namespace_spec/namespace.feature +33 -0
  29. data/features/metasploit-version/install/namespace_spec/version_constant.feature +179 -0
  30. data/features/metasploit-version/install/rake_spec.feature +27 -0
  31. data/features/metasploit-version/install/releasing/ruby_versions.feature +50 -0
  32. data/features/metasploit-version/install/releasing/versioning.feature +138 -0
  33. data/features/metasploit-version/install/steps/gemspec_steps.rb +19 -0
  34. data/features/metasploit-version/install/upgrading.feature +19 -0
  35. data/features/metasploit-version/install/version.feature +11 -0
  36. data/features/metasploit-version/install/version/namespace.feature +157 -0
  37. data/features/metasploit-version/install/version/prerelease.feature +154 -0
  38. data/features/metasploit-version/install/version_spec/namespace.feature +32 -0
  39. data/features/metasploit-version/install/version_spec/testing/branch_from_master.feature +40 -0
  40. data/features/metasploit-version/install/version_spec/testing/branching_from_branch.feature +161 -0
  41. data/features/metasploit-version/install/version_spec/testing/merge_branch_to_master.feature +97 -0
  42. data/features/{shared/examples/metasploit/version/version_module/prerelease/git/step_definitions → step_definitions}/environment_variable_steps.rb +1 -1
  43. data/features/{shared/examples/metasploit/version/version_module/prerelease/git/step_definitions → step_definitions}/git_steps.rb +11 -3
  44. data/features/support/env.rb +15 -11
  45. data/lib/metasploit/version.rb +1 -0
  46. data/lib/metasploit/version/cli.rb +321 -0
  47. data/lib/metasploit/version/version.rb +2 -2
  48. data/metasploit-version.gemspec +2 -2
  49. data/spec/lib/metasploit/version/branch_spec.rb +1 -3
  50. data/spec/lib/metasploit/version/cli_spec.rb +514 -0
  51. data/spec/lib/metasploit/version/version_spec.rb +2 -4
  52. data/spec/lib/metasploit/version_spec.rb +2 -4
  53. data/spec/spec_helper.rb +63 -1
  54. data/spec/support/shared/examples/metasploit/version/version_module.rb +3 -1
  55. metadata +81 -7
@@ -0,0 +1,32 @@
1
+ Feature: metasploit-version install's 'version_spec.rb' generates proper namespace from gem name
2
+
3
+ The version_spec.rb file from metasploit-version will use the fully-qualified name for the Version module under
4
+ the gem's namespace with proper conversion of underscored and dashes in the gem name to camel case and separate
5
+ modules, respectively
6
+
7
+ Scenario Outline:
8
+ Given I successfully run `bundle gem <gem_name>`
9
+ And I cd to "<gem_name>"
10
+ And my git identity is configured
11
+ And I successfully run `git commit --message "bundle gem <gem_name>"`
12
+ And I unset the environment variable "TRAVIS_BRANCH"
13
+ And I set the environment variables to:
14
+ | variable | value |
15
+ | TRAVIS_PULL_REQUEST | false |
16
+ When I successfully run `metasploit-version install --force --no-bundle-install`
17
+ Then the file "<version_spec_rb_path>" should contain exactly:
18
+ """
19
+ RSpec.describe <fully_qualified_version_module> do
20
+ it_should_behave_like 'Metasploit::Version Version Module'
21
+ end
22
+
23
+ """
24
+
25
+ Examples:
26
+ | gem_name | version_spec_rb_path | fully_qualified_version_module |
27
+ | single | spec/lib/single/version_spec.rb | Single::Version |
28
+ | two_words | spec/lib/two_words/version_spec.rb | TwoWords::Version |
29
+ | parent-child | spec/lib/parent/child/version_spec.rb | Parent::Child::Version |
30
+ | two_words-child | spec/lib/two_words/child/version_spec.rb | TwoWords::Child::Version |
31
+ | parent-two_words | spec/lib/parent/two_words/version_spec.rb | Parent::TwoWords::Version |
32
+ | two_words-more_words | spec/lib/two_words/more_words/version_spec.rb | TwoWords::MoreWords::Version |
@@ -0,0 +1,40 @@
1
+ Feature: metasploit-version install's 'version_spec.rb' catches when PRERELEASE is missing when branching from master
2
+
3
+ The version_spec.rb fiel from metasploit-version will catch errors if the user fails to add the PRERELEASE constant in
4
+ version.rb when branching from master.
5
+
6
+ Background:
7
+ Given I successfully run `bundle gem versioned`
8
+ And I cd to "versioned"
9
+ And my git identity is configured
10
+ And I successfully run `git commit --message "bundle gem versioned"`
11
+ And I unset the environment variable "TRAVIS_BRANCH"
12
+ And I set the environment variables to:
13
+ | variable | value |
14
+ | TRAVIS_PULL_REQUEST | false |
15
+
16
+ Scenario: Installing metasploit-version on feature branch
17
+ Given I successfully run `git checkout -b feature/MSP-1234/metasploit-version`
18
+ And I successfully run `metasploit-version install --force --no-bundle-install`
19
+ Then I successfully run `rake spec`
20
+
21
+ Scenario: Branching from master without adding PRERELEASE
22
+ And I successfully run `metasploit-version install --force --no-bundle-install`
23
+ And I successfully run `rake spec`
24
+ And I successfully run `git add *`
25
+ And I successfully run `git commit --all --message "metasploit-version install"`
26
+ And I successfully run `git checkout -b feature/MSP-1337/super-cool`
27
+ Then the file "lib/versioned/version.rb" should not contain " PRERELEASE ="
28
+ When I run `rake spec`
29
+ Then the exit status should not be 0
30
+ And the output should contain:
31
+ """
32
+ expected Versioned::Version::PRERELEASE to be defined.
33
+ Add the following to Versioned::Version:
34
+ """
35
+ And the output should contain:
36
+ """
37
+ # The prerelease version, scoped to the {PATCH} version number.
38
+ PRERELEASE = super-cool
39
+ """
40
+ And the output should contain " 1 failure"
@@ -0,0 +1,161 @@
1
+ Feature: metasploit-version install's version_spec.rb catches errors with PRERELEASE when branching from another branch
2
+
3
+ The version_spec.rb file from metasploit-version will catch errors if the user fails to update the PRERELEASE
4
+ constant in version.rb to when going from one branch to another.
5
+
6
+ Background:
7
+ Given I successfully run `bundle gem double_branched`
8
+ And I cd to "double_branched"
9
+ And my git identity is configured
10
+ And I successfully run `git commit --message "bundle gem double_branched"`
11
+ And I unset the environment variable "TRAVIS_BRANCH"
12
+ And I set the environment variables to:
13
+ | variable | value |
14
+ | TRAVIS_PULL_REQUEST | false |
15
+ And I successfully run `metasploit-version install --force --no-bundle-install`
16
+ And I successfully run `rake spec`
17
+ And I successfully run `git add *`
18
+ And I successfully run `git commit --all --message "metasploit-version install"`
19
+ And I successfully run `git checkout -b feature/MSP-1337/super-cool`
20
+ And I overwrite "lib/double_branched/version.rb" with:
21
+ """
22
+ module DoubleBranched
23
+ # Holds components of {VERSION} as defined by {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0}.
24
+ module Version
25
+ #
26
+ # CONSTANTS
27
+ #
28
+
29
+ # The major version number.
30
+ MAJOR = 0
31
+ # The minor version number, scoped to the {MAJOR} version number.
32
+ MINOR = 0
33
+ # The patch version number, scoped to the {MAJOR} and {MINOR} version numbers.
34
+ PATCH = 1
35
+ # The prerelease version, scoped to the {MAJOR}, {MINOR}, and {PATCH} version numbers.
36
+ PRERELEASE = 'super-cool'
37
+
38
+ #
39
+ # Module Methods
40
+ #
41
+
42
+ # The full version string, including the {DoubleBranched::Version::MAJOR},
43
+ # {DoubleBranched::Version::MINOR}, {DoubleBranched::Version::PATCH}, and optionally, the
44
+ # `DoubleBranched::Version::PRERELEASE` in the
45
+ # {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
46
+ #
47
+ # @return [String] '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}' on master.
48
+ # '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}-PRERELEASE'
49
+ # on any branch other than master.
50
+ def self.full
51
+ version = "#{MAJOR}.#{MINOR}.#{PATCH}"
52
+
53
+ if defined? PRERELEASE
54
+ version = "#{version}-#{PRERELEASE}"
55
+ end
56
+
57
+ version
58
+ end
59
+
60
+ # The full gem version string, including the {DoubleBranched::Version::MAJOR},
61
+ # {DoubleBranched::Version::MINOR}, {DoubleBranched::Version::PATCH}, and optionally, the
62
+ # `DoubleBranched::Version::PRERELEASE` in the
63
+ # {http://guides.rubygems.org/specification-reference/#version RubyGems versioning} format.
64
+ #
65
+ # @return [String] '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}'
66
+ # on master. '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}.PRERELEASE'
67
+ # on any branch other than master.
68
+ def self.gem
69
+ full.gsub('-', '.pre.')
70
+ end
71
+ end
72
+
73
+ # (see Version.gem)
74
+ GEM_VERSION = Version.gem
75
+
76
+ # (see Version.full)
77
+ VERSION = Version.full
78
+ end
79
+
80
+ """
81
+ And I successfully run `rake spec`
82
+ And I successfully run `git checkout -b bug/MSP-666/needed-for-super-cool`
83
+
84
+ Scenario: With changing PRERELEASE
85
+ Given I overwrite "lib/double_branched/version.rb" with:
86
+ """
87
+ module DoubleBranched
88
+ # Holds components of {VERSION} as defined by {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0}.
89
+ module Version
90
+ #
91
+ # CONSTANTS
92
+ #
93
+
94
+ # The major version number.
95
+ MAJOR = 0
96
+ # The minor version number, scoped to the {MAJOR} version number.
97
+ MINOR = 0
98
+ # The patch version number, scoped to the {MAJOR} and {MINOR} version numbers.
99
+ PATCH = 1
100
+ # The prerelease version, scoped to the {MAJOR}, {MINOR}, and {PATCH} version numbers.
101
+ PRERELEASE = 'needed-for-super-cool'
102
+
103
+ #
104
+ # Module Methods
105
+ #
106
+
107
+ # The full version string, including the {DoubleBranched::Version::MAJOR},
108
+ # {DoubleBranched::Version::MINOR}, {DoubleBranched::Version::PATCH}, and optionally, the
109
+ # `DoubleBranched::Version::PRERELEASE` in the
110
+ # {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
111
+ #
112
+ # @return [String] '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}' on master.
113
+ # '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}-PRERELEASE'
114
+ # on any branch other than master.
115
+ def self.full
116
+ version = "#{MAJOR}.#{MINOR}.#{PATCH}"
117
+
118
+ if defined? PRERELEASE
119
+ version = "#{version}-#{PRERELEASE}"
120
+ end
121
+
122
+ version
123
+ end
124
+
125
+ # The full gem version string, including the {DoubleBranched::Version::MAJOR},
126
+ # {DoubleBranched::Version::MINOR}, {DoubleBranched::Version::PATCH}, and optionally, the
127
+ # `DoubleBranched::Version::PRERELEASE` in the
128
+ # {http://guides.rubygems.org/specification-reference/#version RubyGems versioning} format.
129
+ #
130
+ # @return [String] '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}'
131
+ # on master. '{DoubleBranched::Version::MAJOR}.{DoubleBranched::Version::MINOR}.{DoubleBranched::Version::PATCH}.PRERELEASE'
132
+ # on any branch other than master.
133
+ def self.gem
134
+ full.gsub('-', '.pre.')
135
+ end
136
+ end
137
+
138
+ # (see Version.gem)
139
+ GEM_VERSION = Version.gem
140
+
141
+ # (see Version.full)
142
+ VERSION = Version.full
143
+ end
144
+
145
+ """
146
+ Then I successfully run `rake spec`
147
+
148
+ Scenario: Without changing PRERELEASE
149
+ Given the file "lib/double_branched/version.rb" should contain:
150
+ """
151
+ # The prerelease version, scoped to the {MAJOR}, {MINOR}, and {PATCH} version numbers.
152
+ PRERELEASE = 'super-cool'
153
+ """
154
+ When I run `rake spec`
155
+ Then the exit status should not be 0
156
+ And the output should contain:
157
+ """
158
+ expected: "needed-for-super-cool"
159
+ got: "super-cool"
160
+ """
161
+ And the output should contain " 1 failure"
@@ -0,0 +1,97 @@
1
+ Feature: metasploit-version install's 'version_spec.rb' catches errors in version.rb when merging branch to master
2
+
3
+ The version_spec.rb file from metasploit-version will catch errors if the user fails to update the PRERELEASE
4
+ constant in version.rb to when going from a branch to master.
5
+
6
+ Background:
7
+ Given I successfully run `bundle gem branched`
8
+ And I cd to "branched"
9
+ And my git identity is configured
10
+ And I successfully run `git commit --message "bundle gem branched"`
11
+ And I successfully run `git checkout -b feature/MSP-1234/metasploit-version`
12
+ And I unset the environment variable "TRAVIS_BRANCH"
13
+ And I set the environment variables to:
14
+ | variable | value |
15
+ | TRAVIS_PULL_REQUEST | false |
16
+ And I successfully run `metasploit-version install --force --no-bundle-install`
17
+ And I successfully run `rake spec`
18
+ And I successfully run `git add *`
19
+ And I successfully run `git commit --all --message "metasploit-version install"`
20
+ And I successfully run `git checkout master`
21
+ And I successfully run `git merge feature/MSP-1234/metasploit-version`
22
+
23
+ Scenario: Merging branch to master without removing PRERELEASE
24
+ Given the file "lib/branched/version.rb" should contain:
25
+ """
26
+ # The prerelease version, scoped to the {MAJOR}, {MINOR}, and {PATCH} version numbers.
27
+ PRERELEASE = 'metasploit-version'
28
+ """
29
+ When I run `rake spec`
30
+ Then the exit status should not be 0
31
+ And the output should contain:
32
+ """
33
+ expected Branched::Version::PRERELEASE not to be defined on master
34
+ """
35
+ And the output should contain " 1 failure"
36
+
37
+ Scenario: Merging branch to master with removing PRERELEASE
38
+ Given I overwrite "lib/branched/version.rb" with:
39
+ """
40
+ module Branched
41
+ # Holds components of {VERSION} as defined by {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0}.
42
+ module Version
43
+ #
44
+ # CONSTANTS
45
+ #
46
+
47
+ # The major version number.
48
+ MAJOR = 0
49
+ # The minor version number, scoped to the {MAJOR} version number.
50
+ MINOR = 0
51
+ # The patch version number, scoped to the {MAJOR} and {MINOR} version numbers.
52
+ PATCH = 1
53
+
54
+ #
55
+ # Module Methods
56
+ #
57
+
58
+ # The full version string, including the {ImproperlyBranched::Version::MAJOR},
59
+ # {ImproperlyBranched::Version::MINOR}, {ImproperlyBranched::Version::PATCH}, and optionally, the
60
+ # `ImproperlyBranched::Version::PRERELEASE` in the
61
+ # {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
62
+ #
63
+ # @return [String] '{ImproperlyBranched::Version::MAJOR}.{ImproperlyBranched::Version::MINOR}.{ImproperlyBranched::Version::PATCH}' on master.
64
+ # '{ImproperlyBranched::Version::MAJOR}.{ImproperlyBranched::Version::MINOR}.{ImproperlyBranched::Version::PATCH}-PRERELEASE'
65
+ # on any branch other than master.
66
+ def self.full
67
+ version = "#{MAJOR}.#{MINOR}.#{PATCH}"
68
+
69
+ if defined? PRERELEASE
70
+ version = "#{version}-#{PRERELEASE}"
71
+ end
72
+
73
+ version
74
+ end
75
+
76
+ # The full gem version string, including the {ImproperlyBranched::Version::MAJOR},
77
+ # {ImproperlyBranched::Version::MINOR}, {ImproperlyBranched::Version::PATCH}, and optionally, the
78
+ # `ImproperlyBranched::Version::PRERELEASE` in the
79
+ # {http://guides.rubygems.org/specification-reference/#version RubyGems versioning} format.
80
+ #
81
+ # @return [String] '{ImproperlyBranched::Version::MAJOR}.{ImproperlyBranched::Version::MINOR}.{ImproperlyBranched::Version::PATCH}'
82
+ # on master. '{ImproperlyBranched::Version::MAJOR}.{ImproperlyBranched::Version::MINOR}.{ImproperlyBranched::Version::PATCH}.PRERELEASE'
83
+ # on any branch other than master.
84
+ def self.gem
85
+ full.gsub('-', '.pre.')
86
+ end
87
+ end
88
+
89
+ # (see Version.gem)
90
+ GEM_VERSION = Version.gem
91
+
92
+ # (see Version.full)
93
+ VERSION = Version.full
94
+ end
95
+
96
+ """
97
+ Then I successfully run `rake spec`
@@ -5,7 +5,7 @@ Given(/^I unset the environment variable "(.*?)"$/) do |variable|
5
5
  # ENV[variable] = nil and ENV.delete(variable) will not stop the parent process's environment variable from
6
6
  # propagating to processes called by run_simple, so have to fake unsetting with blank values.
7
7
  if RUBY_PLATFORM == 'java'
8
- warn "Faking unsetting environment variable for JRuby by setting to blank string"
8
+ warn 'Faking unsetting environment variable for JRuby by setting to blank string'
9
9
  set_env(variable, '')
10
10
  else
11
11
  set_env(variable, nil)
@@ -1,6 +1,6 @@
1
1
  fail_on_error = true
2
2
 
3
- Given /^a git repository$/ do
3
+ Given(/^a git repository$/) do
4
4
  # git init will fail if account ident it not setup
5
5
  if ENV['TRAVIS'] == 'true'
6
6
  run_simple('git config --global user.email "cucumber@example.com"')
@@ -14,7 +14,7 @@ Given /^a git repository$/ do
14
14
  run_simple('git commit --message "Initial commit"', fail_on_error)
15
15
  end
16
16
 
17
- Given /^(\d+) commits$/ do |commits|
17
+ Given(/^(\d+) commits$/) do |commits|
18
18
  commits = commits.to_i
19
19
 
20
20
  commits.times do |commit|
@@ -25,6 +25,14 @@ Given /^(\d+) commits$/ do |commits|
25
25
  end
26
26
  end
27
27
 
28
- Given /^a git checkout of "(.*?)"$/ do |treeish|
28
+ Given(/^a git checkout of "(.*?)"$/) do |treeish|
29
29
  run_simple("git checkout #{treeish}", fail_on_error)
30
+ end
31
+
32
+ Given(/^my git identity is configured$/) do
33
+ # git commit will fail if account ident is not setup
34
+ if ENV['TRAVIS'] == 'true'
35
+ run_simple('git config --local user.email "cucumber@example.com"')
36
+ run_simple('git config --local user.name "Cucumber"')
37
+ end
30
38
  end
@@ -1,5 +1,7 @@
1
- # Has to be the first file required so that all other files show coverage information
2
- require 'simplecov'
1
+ if RUBY_ENGINE == 'ruby'
2
+ # Has to be the first file required so that all other files show coverage information
3
+ require 'simplecov'
4
+ end
3
5
 
4
6
  #
5
7
  # Standard Library
@@ -15,8 +17,9 @@ require 'aruba/cucumber'
15
17
  # only does jruby customization if actually in JRuby
16
18
  require 'aruba/jruby'
17
19
 
18
- Before do |scenario|
19
- command_name = case scenario
20
+ if defined? SimpleCov
21
+ Before do |scenario|
22
+ command_name = case scenario
20
23
  when Cucumber::Ast::Scenario, Cucumber::Ast::ScenarioOutline
21
24
  "#{scenario.feature.title} #{scenario.name}"
22
25
  when Cucumber::Ast::OutlineTable::ExampleRow
@@ -25,15 +28,16 @@ Before do |scenario|
25
28
  "#{scenario_outline.feature.title} #{scenario_outline.name} #{scenario.name}"
26
29
  else
27
30
  raise TypeError, "Don't know how to extract command name from #{scenario.class}"
28
- end
31
+ end
29
32
 
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
+ # Used in simplecov_setup so that each scenario has a different name and their coverage results are merged instead
34
+ # of overwriting each other as 'Cucumber Features'
35
+ set_env('SIMPLECOV_COMMAND_NAME', command_name)
33
36
 
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
+ simplecov_setup_pathname = Pathname.new(__FILE__).expand_path.parent.join('simplecov_setup')
38
+ # set environment variable so child processes will merge their coverage data with parent process's coverage data.
39
+ set_env('RUBYOPT', "-r#{simplecov_setup_pathname} #{ENV['RUBYOPT']}")
40
+ end
37
41
  end
38
42
 
39
43
  Before do
@@ -15,5 +15,6 @@ module Metasploit
15
15
  # Namespace for this gem.
16
16
  module Version
17
17
  autoload :Branch, 'metasploit/version/branch'
18
+ autoload :CLI, 'metasploit/version/cli'
18
19
  end
19
20
  end
@@ -0,0 +1,321 @@
1
+ #
2
+ # Standard library
3
+ #
4
+
5
+ require 'pathname'
6
+
7
+ #
8
+ # Gems
9
+ #
10
+
11
+ require 'thor'
12
+
13
+ #
14
+ # Project
15
+ #
16
+
17
+ require 'metasploit/version'
18
+ require 'metasploit/version/version'
19
+
20
+ # Command-line interface for `metasploit-version`. Used to run commands for managing the semantic version of a project.
21
+ class Metasploit::Version::CLI < Thor
22
+ include Thor::Actions
23
+
24
+ #
25
+ # CONSTANTS
26
+ #
27
+
28
+ # Name of this gem, for use in other projects that call `metasploit-version install`.
29
+ GEM_NAME = 'metasploit-version'
30
+ # Matches pre-existing development dependency on metasploit-version for updating.
31
+ DEVELOPMENT_DEPENDENCY_REGEXP = /spec\.add_development_dependency\s+(?<quote>"|')#{GEM_NAME}\k<quote>/
32
+
33
+ #
34
+ # Class options
35
+ #
36
+
37
+ class_option :force,
38
+ default: false,
39
+ desc: 'Force overwriting conflicting files',
40
+ type: :boolean
41
+ class_option :skip,
42
+ default: false,
43
+ desc: 'Skip conflicting files',
44
+ type: :boolean
45
+
46
+ #
47
+ # Configuration
48
+ #
49
+
50
+ root = Pathname.new(__FILE__).parent.parent.parent.parent
51
+ source_root root.join('app', 'templates')
52
+
53
+ #
54
+ # Commands
55
+ #
56
+
57
+ desc 'install',
58
+ 'Install metasploit-version and sets up files'
59
+ long_desc(
60
+ "Adds 'metasploit-version' as a development dependency in this project's gemspec OR updates the semantic version requirement; " \
61
+ "adds semantic versioning version.rb file."
62
+ )
63
+ option :major,
64
+ banner: 'MAJOR',
65
+ default: 0,
66
+ desc: 'Major version number',
67
+ type: :numeric
68
+ option :minor,
69
+ banner: 'MINOR',
70
+ default: 0,
71
+ desc: 'Minor version number, scoped to MAJOR version number.',
72
+ type: :numeric
73
+ option :patch,
74
+ banner: 'PATCH',
75
+ default: 1,
76
+ desc: 'Patch version number, scoped to MAJOR and MINOR version numbers.',
77
+ type: :numeric
78
+ option :bundle_install,
79
+ default: true,
80
+ desc: '`bundle install` after adding `metasploit-version` as a development dependency so you can ' \
81
+ 'immediately run `rake spec` afterwards. Use `--no-bundle-install` if you want to add other gems to ' \
82
+ 'the gemspec or Gemfile before installing or you\'re just rerunning install to update the templated ' \
83
+ 'files and the dependencies are already in your bundle.',
84
+ type: :boolean
85
+ option :github_owner,
86
+ default: 'rapid7',
87
+ desc: 'The owner of the github repo for this gem. Used to generate links in CONTRIBUTING.md',
88
+ type: :string
89
+ option :ruby_versions,
90
+ default: ['jruby', 'ruby-2.1'],
91
+ desc: 'Ruby versions that the gem should be released for on rubygems.org as part of CONTRIBUTING.md',
92
+ type: :array
93
+ # Adds 'metasploit-version' as a development dependency in this project's gemspec.
94
+ #
95
+ # @return [void]
96
+ def install
97
+ ensure_development_dependency
98
+ template('lib/versioned/version.rb.tt', "lib/#{namespaced_path}/version.rb")
99
+ install_bundle
100
+ template('CHANGELOG.md.tt', 'CHANGELOG.md')
101
+ template('CONTRIBUTING.md.tt', 'CONTRIBUTING.md')
102
+ template('RELEASING.md.tt', 'RELEASING.md')
103
+ template('UPGRADING.md.tt', 'UPGRADING.md')
104
+ setup_rspec
105
+ end
106
+
107
+ private
108
+
109
+ # Capitalizes words by converting the first character of `word` to upper case.
110
+ #
111
+ # @param word [String] a lower case string
112
+ # @return [String]
113
+ def capitalize(word)
114
+ word[0, 1].upcase + word[1 .. -1]
115
+ end
116
+
117
+ # The line injected into the gemspec by {#ensure_development_dependency}
118
+ #
119
+ # @return [String]
120
+ def development_dependency_line
121
+ " spec.add_development_dependency '#{GEM_NAME}', '#{version_requirement}'\n"
122
+ end
123
+
124
+ # Ensures that the {#gemspec_path} contains a development dependency on {GEM_NAME}.
125
+ #
126
+ # Adds `spec.add_development_dependency 'metasploit_version', '~> <semantic version requirement>'` if {#gemspec_path}
127
+ # does not have such an entry. Otherwise, updates the `<semantic version requirement>` to match this version of
128
+ # `metasploit-version`.
129
+ #
130
+ # @return [void]
131
+ # @raise (see #gemspec_path)
132
+ def ensure_development_dependency
133
+ path = gemspec_path
134
+ gem_specification = Gem::Specification.load(path)
135
+
136
+ metasploit_version = gem_specification.dependencies.find { |dependency|
137
+ dependency.name == GEM_NAME
138
+ }
139
+
140
+ lines = []
141
+
142
+ if metasploit_version
143
+ if metasploit_version.requirements_list.include? '>= 0'
144
+ shell.say "Adding #{GEM_NAME} as a development dependency to "
145
+ else
146
+ shell.say "Updating #{GEM_NAME} requirements in "
147
+ end
148
+
149
+ shell.say path
150
+
151
+ File.open(path) do |f|
152
+ f.each_line do |line|
153
+ match = line.match(DEVELOPMENT_DEPENDENCY_REGEXP)
154
+
155
+ if match
156
+ lines << development_dependency_line
157
+ else
158
+ lines << line
159
+ end
160
+ end
161
+ end
162
+ else
163
+ end_index = nil
164
+ lines = []
165
+
166
+ open(path) do |f|
167
+ line_index = 0
168
+
169
+ f.each_line do |line|
170
+ lines << line
171
+
172
+ if line =~ /^\s*end\s*$/
173
+ end_index = line_index
174
+ end
175
+
176
+ line_index += 1
177
+ end
178
+ end
179
+
180
+ lines.insert(end_index, development_dependency_line)
181
+ end
182
+
183
+ File.open(path, 'w') do |f|
184
+ lines.each do |line|
185
+ f.write(line)
186
+ end
187
+ end
188
+ end
189
+
190
+ # The name of the gemspec in the current working directory.
191
+ #
192
+ # @return [String] relative path to the current working directory's gemspec.
193
+ # @raise [SystemExit] if no gemspec is found
194
+ def gemspec_path
195
+ unless instance_variable_defined? :@gemspec
196
+ path = "#{name}.gemspec"
197
+
198
+ unless File.exist?(path)
199
+ shell.say 'No gemspec found'
200
+ exit 1
201
+ end
202
+
203
+ @gemspec_path = path
204
+ end
205
+
206
+ @gemspec_path
207
+ end
208
+
209
+ # The URL of the github repository. Used to calculate the fork and issues URL in `CONTRIBUTING.md`.
210
+ #
211
+ # @return [String] https url to github repository
212
+ def github_url
213
+ @github_url ||= "https://github.com/#{options[:github_owner]}/#{name}"
214
+ end
215
+
216
+ # `bundle install` if the :bundle_install options is `true`
217
+ #
218
+ # @return [void]
219
+ def install_bundle
220
+ if options[:bundle_install]
221
+ system('bundle', 'install')
222
+ end
223
+ end
224
+
225
+ # The name of the gem.
226
+ #
227
+ # @return [String] name of the gem. Assumed to be the name of the pwd as it should match the repository name.
228
+ def name
229
+ @name ||= File.basename(Dir.pwd)
230
+ end
231
+
232
+ # The fully-qualified namespace for the gem.
233
+ #
234
+ # @param [String]
235
+ def namespace_name
236
+ @namespace_name ||= namespaces.join('::')
237
+ end
238
+
239
+ # List of `Module#name`s making up the {#namespace_name the fully-qualifed namespace for the gem}.
240
+ #
241
+ # @return [Array<String>]
242
+ def namespaces
243
+ unless instance_variable_defined? :@namespaces
244
+ underscored_words = name.split('_')
245
+ capitalized_underscored_words = underscored_words.map { |underscored_word|
246
+ capitalize(underscored_word)
247
+ }
248
+ capitalized_hyphenated_name = capitalized_underscored_words.join
249
+ hyphenated_words = capitalized_hyphenated_name.split('-')
250
+
251
+ @namespaces = hyphenated_words.map { |hyphenated_word|
252
+ capitalize(hyphenated_word)
253
+ }
254
+ end
255
+
256
+ @namespaces
257
+ end
258
+
259
+ # The relative path of the gem under `lib`.
260
+ #
261
+ # @return [String] Format of `[<parent>/]*<child>`
262
+ def namespaced_path
263
+ @namespaced_path ||= name.tr('-', '/')
264
+ end
265
+
266
+ # The prerelease version.
267
+ #
268
+ # @return [nil] if on master or HEAD
269
+ # @return [String] if on a branch
270
+ def prerelease
271
+ unless instance_variable_defined? :@prerelease
272
+ branch = Metasploit::Version::Branch.current
273
+ parsed = Metasploit::Version::Branch.parse(branch)
274
+
275
+ if parsed.is_a? Hash
276
+ prerelease = parsed[:prerelease]
277
+
278
+ if prerelease
279
+ @prerelease = prerelease
280
+ end
281
+ end
282
+ end
283
+
284
+ @prerelease
285
+ end
286
+
287
+ # Generates `.rspec`, `Rakefile`, `version_spec.rb`, `<namespace>_spec.rb` and `spec/spec_helper.rb`
288
+ #
289
+ # @return [void]
290
+ def setup_rspec
291
+ template('.rspec.tt', '.rspec')
292
+ template('Rakefile.tt', 'Rakefile')
293
+ template('spec/lib/versioned/version_spec.rb.tt', "spec/#{version_path.sub(/\.rb$/, '_spec.rb')}")
294
+ template('spec/lib/versioned_spec.rb.tt', "spec/lib/#{namespaced_path}_spec.rb")
295
+ template('spec/spec_helper.rb.tt', 'spec/spec_helper.rb')
296
+ end
297
+
298
+ # Path to the `version.rb` for the gem.
299
+ #
300
+ # @return [String]
301
+ def version_path
302
+ @version_path ||= "lib/#{namespaced_path}/version.rb"
303
+ end
304
+
305
+ # The version requirement on the `metasploit-version` development dependency in {#development_dependency_line}.
306
+ #
307
+ # @return [String]
308
+ def version_requirement
309
+ if defined? Metasploit::Version::Version::PRERELEASE
310
+ # require exactly this pre-release in case there are multiple prereleases for the same
311
+ # version number due to parallel branches.
312
+ "= #{Metasploit::Version::GEM_VERSION}"
313
+ elsif Metasploit::Version::Version::MAJOR < 1
314
+ # can only allow the PATCH to wiggle pre-1.0.0
315
+ "~> #{Metasploit::Version::Version::MAJOR}.#{Metasploit::Version::Version::MINOR}.#{Metasploit::Version::Version::PATCH}"
316
+ else
317
+ # can allow the MINOR to wiggle 1.0.0+
318
+ "~> #{Metasploit::Version::Version::MAJOR}.#{Metasploit::Version::Version::MINOR}"
319
+ end
320
+ end
321
+ end