story_branch 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 601d26c296267a0ad82258cb4978d82a538e88b6
4
- data.tar.gz: 3b667d1a51fb3a1a8ad509fb98a956c241e8edc2
3
+ metadata.gz: 658c404de733ae5763ff79161139eb48e746ed74
4
+ data.tar.gz: 2403a2c29aed765c73e6527358b9a484c7c60b7c
5
5
  SHA512:
6
- metadata.gz: c1cdef1c858ccbfca16e4a79f98712eabfae71aa08aa6b8faed758eded648eae82df1c8d4ff7ec1af79b4f2ce8d9661f00cd0347048d14d18ac67adba7b5a130
7
- data.tar.gz: 4a75f85aeea2b9a293378c5e05f0c258079c8d748f8bd553719372fe02aaf6d02e9e2d2a422024338641fd34287e8742a86383a516906fd933da1a70c0003b0c
6
+ metadata.gz: 35190816ff350d0b1cd2225caf3939a4eef48e08bb697c1db631e7320043a042d53dbeb0512340ae36b22c6aedb2a887f8e68b31b5b7ca74b2f014b0bfc35e89
7
+ data.tar.gz: cc011af10bb4a8bcedc68130a99e4173f7c6f4beda8415a5e15882cd179d422b0f4dc269fac390b275f125779320d4a6cd9972603e8aef952ba12e859de1d675
data/.circleci/config.yml CHANGED
@@ -2,34 +2,50 @@ version: 2
2
2
  jobs:
3
3
  build:
4
4
  docker:
5
+ # specify the version you desire here
5
6
  - image: circleci/ruby:2.4.1-node-browsers
6
- working_directory: ~/story_branch
7
+
8
+ # Specify service dependencies here if necessary
9
+ # CircleCI maintains a library of pre-built images
10
+ # documented at https://circleci.com/docs/2.0/circleci-images/
11
+ # - image: circleci/postgres:9.4
12
+
13
+ working_directory: ~/repo
14
+
7
15
  steps:
8
16
  - checkout
17
+
18
+ # Download and cache dependencies
9
19
  - restore_cache:
10
20
  keys:
21
+ - v1-dependencies-{{ checksum "Gemfile.lock" }}
22
+ # fallback to using the latest cache if no exact match is found
11
23
  - v1-dependencies-
24
+
12
25
  - run:
13
26
  name: install dependencies
14
27
  command: |
28
+ gem install bundler
15
29
  bundle install --jobs=4 --retry=3 --path vendor/bundle
30
+
16
31
  - save_cache:
17
32
  paths:
18
33
  - ./vendor/bundle
19
34
  key: v1-dependencies-{{ checksum "Gemfile.lock" }}
20
35
 
36
+ # run tests!
21
37
  - run:
22
38
  name: run tests
23
39
  command: |
24
40
  mkdir -p /tmp/test-results
25
-
26
41
  TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
27
42
 
28
- bundle exec rspec --format documentation \
29
- --format RspecJunitFormatter \
30
- --out /tmp/test-results/rspec.xml \
31
- -- $(sed -e 's/\n/\\n/' -e 's/ /\ /' <<< "${TEST_FILES}")
43
+ bundle exec rspec --format progress \
44
+ --format RspecJunitFormatter \
45
+ --out /tmp/test-results/rspec.xml \
46
+ $TEST_FILES
32
47
 
48
+ # collect reports
33
49
  - store_test_results:
34
50
  path: /tmp/test-results
35
51
  - store_artifacts:
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in story_branch.gemspec
6
8
  gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- story_branch (0.3.0)
4
+ story_branch (0.3.1)
5
5
  blanket_wrapper (~> 3.0)
6
6
  git (~> 1.2)
7
7
  levenshtein-ffi (~> 1.0)
@@ -22,9 +22,9 @@ GEM
22
22
  diff-lcs (1.3)
23
23
  equatable (0.5.0)
24
24
  fakefs (0.14.2)
25
- ffi (1.9.23)
25
+ ffi (1.9.25)
26
26
  git (1.4.0)
27
- hitimes (1.2.6)
27
+ hitimes (1.3.0)
28
28
  httparty (0.16.2)
29
29
  multi_xml (>= 0.5.2)
30
30
  levenshtein-ffi (1.1.0)
@@ -49,6 +49,8 @@ GEM
49
49
  rspec-mocks (3.0.4)
50
50
  rspec-support (~> 3.0.0)
51
51
  rspec-support (3.0.4)
52
+ rspec_junit_formatter (0.4.1)
53
+ rspec-core (>= 2, < 4, != 2.12.0)
52
54
  strings (0.1.1)
53
55
  unicode-display_width (~> 1.3.0)
54
56
  unicode_utils (~> 1.4.0)
@@ -76,7 +78,7 @@ GEM
76
78
  wisper (~> 2.0.0)
77
79
  tty-screen (0.6.4)
78
80
  tty-which (0.3.0)
79
- unicode-display_width (1.3.0)
81
+ unicode-display_width (1.3.3)
80
82
  unicode_utils (1.4.0)
81
83
  wisper (2.0.0)
82
84
 
@@ -88,6 +90,7 @@ DEPENDENCIES
88
90
  fakefs (~> 0.14)
89
91
  rake (~> 10.0)
90
92
  rspec (~> 3.0)
93
+ rspec_junit_formatter
91
94
  story_branch!
92
95
 
93
96
  BUNDLED WITH
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
data/exe/git-finish CHANGED
@@ -1,3 +1,4 @@
1
+ # rubocop:disable Style/FrozenStringLiteralComment
1
2
  #!/usr/bin/env ruby
2
3
 
3
4
  `story_branch finish`
data/exe/git-start CHANGED
@@ -1,3 +1,4 @@
1
+ # rubocop:disable Style/FrozenStringLiteralComment
1
2
  #!/usr/bin/env ruby
2
3
 
3
4
  `story_branch start`
data/exe/git-story CHANGED
@@ -1,3 +1,4 @@
1
+ # rubocop:disable Style/FrozenStringLiteralComment
1
2
  #!/usr/bin/env ruby
2
3
 
3
4
  `story_branch create`
data/exe/git-unstart CHANGED
@@ -1,3 +1,4 @@
1
+ # rubocop:disable Style/FrozenStringLiteralComment
1
2
  #!/usr/bin/env ruby
2
3
 
3
4
  `story_branch unstart`
data/exe/story_branch CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  lib_path = File.expand_path('../lib', __dir__)
5
- $:.unshift(lib_path) if !$:.include?(lib_path)
5
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
6
6
  require 'story_branch/cli'
7
7
 
8
8
  Signal.trap('INT') do
data/lib/story_branch.rb CHANGED
@@ -1,5 +1,8 @@
1
+ # rubocop:disable Style/FrozenStringLiteralComment
1
2
  require 'story_branch/version'
3
+ # rubocop:enable Style/FrozenStringLiteralComment
2
4
 
5
+ # Module initial definition
3
6
  module StoryBranch
4
7
  # Your code goes here...
5
8
  end
@@ -42,7 +42,8 @@ module StoryBranch
42
42
  end
43
43
  end
44
44
 
45
- desc 'finish', 'Creates a git commit message for the staged changes with a [Finishes] tag'
45
+ desc 'finish',
46
+ 'Creates a commit message for the staged changes with the finish tag'
46
47
  method_option :help, aliases: '-h', type: :boolean,
47
48
  desc: 'Display usage information'
48
49
  def finish(*)
@@ -3,6 +3,8 @@
3
3
  require 'forwardable'
4
4
 
5
5
  module StoryBranch
6
+ # TTY Command base class. All commands available for the gem will be based
7
+ # of this class.
6
8
  class Command
7
9
  extend Forwardable
8
10
 
@@ -10,8 +10,8 @@ module StoryBranch
10
10
  # Migrate command is intended to make the migration from old version
11
11
  # of story branch to the latest one easier.
12
12
  class Migrate < StoryBranch::Command
13
- GLOBAL_CONFIG_FILE = "#{Dir.home}/.story_branch".freeze
14
- LOCAL_CONFIG_FILE = '.story_branch'.freeze
13
+ GLOBAL_CONFIG_FILE = "#{Dir.home}/.story_branch"
14
+ LOCAL_CONFIG_FILE = '.story_branch'
15
15
  OLD_CONFIG_FILES = [LOCAL_CONFIG_FILE, GLOBAL_CONFIG_FILE].freeze
16
16
 
17
17
  def initialize(options)
@@ -83,14 +83,14 @@ module StoryBranch
83
83
  end
84
84
 
85
85
  def old_config_file_not_found
86
- <<-MESSAGE
87
- Old configuration not found.
88
- Trying to start from scratch? Use story_branch add
86
+ <<~MESSAGE
87
+ Old configuration not found.
88
+ Trying to start from scratch? Use story_branch add
89
89
  MESSAGE
90
90
  end
91
91
 
92
92
  def cant_migrate_missing_value
93
- <<-MESSAGE
93
+ <<~MESSAGE
94
94
  Old configuration not found. Nothing has been migrated
95
95
  Trying to start from scratch? Use story_branch add
96
96
  MESSAGE
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tty-config'
2
4
 
3
5
  module StoryBranch
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'git'
2
4
  require 'levenshtein'
3
5
 
4
6
  module StoryBranch
7
+ # Class used to interact with git. It relies on git gem as the wrapper
8
+ # and levenshtein algo to determine branch name proximity
5
9
  class GitUtils
6
10
  def self.g
7
11
  ::Git.open '.'
@@ -10,9 +14,9 @@ module StoryBranch
10
14
  def self.existing_branch?(name)
11
15
  branch_names.each do |n|
12
16
  return true if Levenshtein.distance(n, name) < 3
13
- existing_branch_name = n.match(/(.*)(-[1-9][0-9]+$)/)
14
- next unless existing_branch_name
15
- levenshtein_distance = Levenshtein.distance existing_branch_name[1], name
17
+ branch_name_match = n.match(/(.*)(-[1-9][0-9]+$)/)
18
+ next unless branch_name_match
19
+ levenshtein_distance = Levenshtein.distance branch_name_match[1], name
16
20
  return true if levenshtein_distance < 3
17
21
  end
18
22
  false
@@ -36,13 +40,13 @@ module StoryBranch
36
40
  end
37
41
 
38
42
  def self.current_story
39
- current_branch.match(/(.*)-(\d+$)/)
43
+ /(.*)-(\d+$)/.match current_branch
40
44
  end
41
45
 
42
46
  def self.current_branch_story_parts
43
47
  matches = current_story
44
48
  return unless matches.length == 3
45
- { title: matches[1], id: matches[2] }
49
+ { title: matches[1], id: matches[2].to_i }
46
50
  end
47
51
 
48
52
  def self.create_branch(name)
@@ -51,11 +55,8 @@ module StoryBranch
51
55
  end
52
56
 
53
57
  def self.status_collect(status, regex)
54
- status.select{|e|
55
- e.match(regex)
56
- }.map{ |e|
57
- e.match(regex)[1]
58
- }
58
+ chosen_stati = status.select { |e| e.match(regex) }
59
+ chosen_stati.map { |e| e.match(regex)[1] }
59
60
  end
60
61
 
61
62
  def self.status
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './string_utils'
2
4
  require_relative './pivotal_utils'
3
5
  require_relative './config_manager'
6
+ require 'tty-prompt'
4
7
 
5
8
  module StoryBranch
9
+ # Main story branch class. It is resposnible for the main interaction between
10
+ # the user and Pivotal Tracker. It is also responsible for config init.
6
11
  class Main
7
12
  ERRORS = {
8
13
  'Stories in the started state must be estimated.' =>
@@ -22,12 +27,12 @@ module StoryBranch
22
27
  # TODO:
23
28
  # Move these methods to the command logic.
24
29
  def create_story_branch
25
- puts 'Connecting with Pivotal Tracker'
30
+ prompt.say 'Connecting with Pivotal Tracker'
26
31
  @p.project
27
- puts 'Getting stories...'
32
+ prompt.say 'Getting stories...'
28
33
  stories = @p.display_stories :started, false
29
34
  if stories.empty?
30
- puts 'No stories started, exiting'
35
+ prompt.say 'No stories started, exiting'
31
36
  exit
32
37
  end
33
38
  story = @p.select_story stories
@@ -39,7 +44,7 @@ module StoryBranch
39
44
  end
40
45
 
41
46
  def story_finish
42
- puts 'Connecting with Pivotal Tracker'
47
+ prompt.say 'Connecting with Pivotal Tracker'
43
48
  @p.project
44
49
 
45
50
  unless @p.is_current_branch_a_story?
@@ -48,26 +53,28 @@ module StoryBranch
48
53
  end
49
54
 
50
55
  if GitUtils.status?(:untracked) || GitUtils.status?(:modified)
51
- puts 'There are unstaged changes'
52
- puts 'Use git add to stage changes before running git finish'
53
- puts 'Use git stash if you want to hide changes for this commit'
56
+ prompt.say 'There are unstaged changes'
57
+ prompt.say 'Use git add to stage changes before running git finish'
58
+ prompt.say 'Use git stash if you want to hide changes for this commit'
54
59
  return nil
55
60
  end
56
61
 
57
62
  unless GitUtils.status?(:added) || GitUtils.status?(:staged)
58
- puts 'There are no staged changes.'
59
- puts 'Nothing to do'
63
+ prompt.say 'There are no staged changes.'
64
+ prompt.say 'Nothing to do'
60
65
  return nil
61
66
  end
62
67
 
63
- puts 'Use standard finishing commit message: [y/N]?'
64
- commit_message = "[Finishes ##{GitUtils.current_branch_story_parts[:id]}] #{StoryBranch::StringUtils.undashed GitUtils.current_branch_story_parts[:title]}"
65
- puts commit_message
68
+ current_story = GitUtils.current_branch_story_parts
69
+ commit_message = "[#{@p.finish_tag} ##{current_story[:id]}] "\
70
+ "#{StoryBranch::StringUtils.undashed(current_story[:title])}"
66
71
 
67
- if gets.chomp!.casecmp('y').zero?
68
- GitUtils.commit commit_message
72
+ prompt.say(commit_message)
73
+ abort_commit = prompt.no?('Use standard finishing commit message?')
74
+ if abort_commit
75
+ prompt.say 'Aborted'
69
76
  else
70
- puts 'Aborted'
77
+ GitUtils.commit commit_message
71
78
  end
72
79
  rescue Blanket::Unauthorized
73
80
  unauthorised_message
@@ -84,6 +91,11 @@ module StoryBranch
84
91
 
85
92
  private
86
93
 
94
+ def prompt
95
+ return @prompt if @prompt
96
+ @prompt = TTY::Prompt.new
97
+ end
98
+
87
99
  def config
88
100
  return @config if @config
89
101
  @config = ConfigManager.init_config(Dir.home)
@@ -1,10 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'blanket'
2
4
  require 'rb-readline'
3
5
  require_relative './git_utils'
4
6
 
5
7
  module StoryBranch
8
+ # Utility class for integration with PivotalTracker. It relies on Blanket
9
+ # wrapper to communicate with pivotal tracker's api.
6
10
  class PivotalUtils
7
- API_URL = 'https://www.pivotaltracker.com/services/v5/'.freeze
11
+ API_URL = 'https://www.pivotaltracker.com/services/v5/'
8
12
  attr_accessor :api_key, :project_id, :finish_tag
9
13
 
10
14
  def valid?
@@ -28,15 +32,14 @@ module StoryBranch
28
32
  end
29
33
 
30
34
  def is_current_branch_a_story?
31
- StoryBranch::GitUtils.current_story and
32
- StoryBranch::GitUtils.current_story.length == 3 and
33
- filtered_stories_list(:started, true)
34
- .map(&:id)
35
- .include? StoryBranch::GitUtils.current_story[2].to_i
35
+ current_story = StoryBranch::GitUtils.current_branch_story_parts
36
+ return unless current_story
37
+ filtered_stories_list(:started, true).map(&:id).include? current_story[:id]
36
38
  end
37
39
 
38
40
  def story_from_current_branch
39
- story_accessor.get(StoryBranch::GitUtils.current_story[2].to_i) if StoryBranch::GitUtils.current_story.length == 3
41
+ return unless StoryBranch::GitUtils.current_story.length == 3
42
+ story_accessor.get(StoryBranch::GitUtils.current_story[2].to_i)
40
43
  end
41
44
 
42
45
  # TODO: Maybe add some other predicates
@@ -1,23 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StoryBranch
4
+ # Utility class for string manipulation
2
5
  class StringUtils
3
- def self.dashed(s)
4
- s.tr(' _,./:;+&', '-')
6
+ def self.sanitize(s)
7
+ res = s.strip
8
+ res.tr!("\n", '-')
9
+ encoding_options = {
10
+ invalid: :replace, # Replace invalid byte sequences
11
+ undef: :replace, # Replace anything not defined in ASCII
12
+ replace: '-' # Use a dash for those replacements
13
+ }
14
+ res.encode(Encoding.find('ASCII'), encoding_options)
5
15
  end
6
16
 
7
- def self.simple_sanitize(s)
8
- strip_newlines(s.tr('\'"%!@#$(){}[]*\\?', ''))
17
+ def self.dashed(s)
18
+ sanitize(s).tr(" _,./:;+&'\"?", '-').squeeze('-')
9
19
  end
10
20
 
11
21
  def self.normalised_branch_name(s)
12
- simple_sanitize((dashed s).downcase).squeeze('-')
13
- end
14
-
15
- def self.strip_newlines(s)
16
- s.tr "\n", '-'
22
+ dashed(s).downcase
17
23
  end
18
24
 
19
25
  def self.undashed(s)
20
- s.tr(/-/, ' ').capitalize
26
+ s.tr('-', ' ').squeeze(' ').strip.capitalize
21
27
  end
22
28
  end
23
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StoryBranch
2
- VERSION = '0.3.0'.freeze
4
+ VERSION = '0.3.1'
3
5
  end
data/story_branch.gemspec CHANGED
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('../lib', __FILE__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'story_branch/version'
4
6
 
7
+ # rubocop:disable Metrics/BlockLength
5
8
  Gem::Specification.new do |spec|
6
9
  spec.name = 'story_branch'
7
10
  spec.license = 'MIT'
@@ -22,15 +25,22 @@ Gem::Specification.new do |spec|
22
25
  ]
23
26
 
24
27
  spec.summary = 'Create git branches based on pivotal tracker stories'
25
- spec.description = 'Simple gem that fetches the available stories in your \
26
- pivotaltracker project and allows you to create a git branch with the name \
27
- based on the selected story'
28
+ spec.description = <<~DESCRIPTION
29
+ Simple gem that fetches the available stories in your PivotalTracker
30
+ project and allows you to create a git branch with the name based
31
+ on the selected story
32
+ DESCRIPTION
33
+
28
34
  spec.homepage = 'https://github.com/story-branch/story_branch'
35
+ spec.required_ruby_version = '>= 2.3'
29
36
 
30
37
  # Specify which files should be added to the gem when it is released.
31
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
38
+ # The `git ls-files -z` loads the files in the RubyGem that have been
39
+ # added into git.
32
40
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
41
+ `git ls-files -z`.split("\x0").reject do |f|
42
+ f.match(%r{^(test|spec|features)/})
43
+ end
34
44
  end
35
45
  spec.bindir = 'exe'
36
46
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -51,4 +61,6 @@ Gem::Specification.new do |spec|
51
61
  spec.add_development_dependency 'fakefs', '~> 0.14'
52
62
  spec.add_development_dependency 'rake', '~> 10.0'
53
63
  spec.add_development_dependency 'rspec', '~> 3.0'
64
+ spec.add_development_dependency 'rspec_junit_formatter'
54
65
  end
66
+ # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: story_branch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Milkins
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: exe
14
14
  cert_chain: []
15
- date: 2018-06-21 00:00:00.000000000 Z
15
+ date: 2018-06-26 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: blanket_wrapper
@@ -210,10 +210,24 @@ dependencies:
210
210
  - - "~>"
211
211
  - !ruby/object:Gem::Version
212
212
  version: '3.0'
213
- description: |-
214
- Simple gem that fetches the available stories in your \
215
- pivotaltracker project and allows you to create a git branch with the name \
216
- based on the selected story
213
+ - !ruby/object:Gem::Dependency
214
+ name: rspec_junit_formatter
215
+ requirement: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ type: :development
221
+ prerelease: false
222
+ version_requirements: !ruby/object:Gem::Requirement
223
+ requirements:
224
+ - - ">="
225
+ - !ruby/object:Gem::Version
226
+ version: '0'
227
+ description: |
228
+ Simple gem that fetches the available stories in your PivotalTracker
229
+ project and allows you to create a git branch with the name based
230
+ on the selected story
217
231
  email:
218
232
  - jasonm23@gmail.com
219
233
  - rui.p.baltazar@gmail.com
@@ -233,6 +247,7 @@ files:
233
247
  - ".github/ISSUE_TEMPLATE.md"
234
248
  - ".gitignore"
235
249
  - ".rspec"
250
+ - ".ruby-version"
236
251
  - Gemfile
237
252
  - Gemfile.lock
238
253
  - LICENSE.txt
@@ -280,7 +295,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
280
295
  requirements:
281
296
  - - ">="
282
297
  - !ruby/object:Gem::Version
283
- version: '0'
298
+ version: '2.3'
284
299
  required_rubygems_version: !ruby/object:Gem::Requirement
285
300
  requirements:
286
301
  - - ">="