story_branch 0.7.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,7 @@ require_relative './jira/tracker'
6
6
  require_relative './git_utils'
7
7
  require_relative './git_wrapper'
8
8
  require_relative './config_manager'
9
+ require_relative './url_opener'
9
10
  require 'tty-prompt'
10
11
 
11
12
  module StoryBranch
@@ -67,6 +68,15 @@ module StoryBranch
67
68
  update_status('started', 'unstarted', 'unstart')
68
69
  end
69
70
 
71
+ def open_current_url
72
+ if current_story
73
+ prompt.say 'Opening story in browser...'
74
+ StoryBranch::UrlOpener.open_url(current_story.html_url)
75
+ else
76
+ prompt.say 'Could not find matching story in configured tracker'
77
+ end
78
+ end
79
+
70
80
  private
71
81
 
72
82
  def require_pivotal
@@ -77,23 +87,13 @@ module StoryBranch
77
87
  end
78
88
 
79
89
  def current_story
80
- return @current_story if @current_story
81
-
82
- current_story = GitUtils.current_branch_story_parts
90
+ return nil unless @tracker
83
91
 
84
- unless current_story.empty?
85
- @current_story = @tracker.get_story_by_id(current_story[:id])
86
- return @current_story if @current_story
87
- end
88
-
89
- prompt.error('No tracked feature associated with this branch')
90
- nil
92
+ @tracker.current_story
91
93
  end
92
94
 
93
95
  def unstaged_changes?
94
- unless GitUtils.status?(:untracked) || GitUtils.status?(:modified)
95
- return false
96
- end
96
+ return false unless GitUtils.status?(:untracked) || GitUtils.status?(:modified)
97
97
 
98
98
  message = <<~MESSAGE
99
99
  There are unstaged changes
@@ -114,7 +114,6 @@ module StoryBranch
114
114
  true
115
115
  end
116
116
 
117
- # rubocop:disable Metrics/AbcSize
118
117
  # rubocop:disable Metrics/MethodLength
119
118
  def update_status(current_status, next_status, action)
120
119
  stories = @tracker.stories_with_state(current_status)
@@ -139,7 +138,6 @@ module StoryBranch
139
138
  story
140
139
  end
141
140
  # rubocop:enable Metrics/MethodLength
142
- # rubocop:enable Metrics/AbcSize
143
141
 
144
142
  def build_stories_structure(stories)
145
143
  options = {}
@@ -161,26 +159,18 @@ module StoryBranch
161
159
  def create_feature_branch(story)
162
160
  return if story.nil?
163
161
 
164
- if GitUtils.branch_for_story_exists? story.id
165
- prompt.error("An existing branch has the same story id: #{story.id}")
166
- return
167
- end
168
-
169
162
  branch_name = valid_branch_name(story)
170
163
  return unless branch_name
171
164
 
172
- # rubocop:disable Metrics/LineLength
173
165
  feature_branch_name_with_story_id = build_branch_name(branch_name, story.id)
174
166
 
175
167
  prompt.say("Creating: #{feature_branch_name_with_story_id} with #{current_branch} as parent")
176
- # rubocop:enable Metrics/LineLength
177
168
  GitWrapper.create_branch feature_branch_name_with_story_id
178
169
  end
179
170
 
180
171
  def valid_branch_name(story)
181
172
  prompt.say "You are checked out at: #{current_branch}"
182
- branch_name = prompt.ask('Provide a new branch name',
183
- default: story.dashed_title)
173
+ branch_name = prompt.ask('Provide a new branch name', default: story.dashed_title)
184
174
  feature_branch_name = StringUtils.truncate(branch_name.chomp)
185
175
 
186
176
  validate_branch_name(feature_branch_name)
@@ -190,8 +180,7 @@ module StoryBranch
190
180
  # rubocop:disable Metrics/MethodLength
191
181
  def validate_branch_name(name)
192
182
  if GitUtils.similar_branch? name
193
- prompt.warn('This name is very similar to an existing branch.'\
194
- ' It is recommended to use a more unique name.')
183
+ prompt.warn('This name is very similar to an existing branch. It is recommended to use a more unique name.')
195
184
  decision = prompt.select('What to do?') do |menu|
196
185
  menu.choice 'Rename the branch', 1
197
186
  menu.choice 'Proceed with branch name', 2
@@ -224,11 +213,11 @@ module StoryBranch
224
213
  tracker_type = @config.tracker_type
225
214
  case tracker_type
226
215
  when 'github'
227
- StoryBranch::Github::Tracker.new(@config.tracker_params)
216
+ StoryBranch::Github::Tracker.new(**@config.tracker_params)
228
217
  when 'pivotal-tracker'
229
- StoryBranch::Pivotal::Tracker.new(@config.tracker_params)
218
+ StoryBranch::Pivotal::Tracker.new(**@config.tracker_params)
230
219
  when 'jira'
231
- StoryBranch::Jira::Tracker.new(@config.tracker_params)
220
+ StoryBranch::Jira::Tracker.new(**@config.tracker_params)
232
221
  end
233
222
  end
234
223
  end
@@ -10,17 +10,17 @@ module StoryBranch
10
10
  @project = blanket_project
11
11
  end
12
12
 
13
+ private
14
+
13
15
  # Returns an array of PT Stories (Story Class)
14
16
  # TODO: add other possible args
15
- def stories(options = {}, estimated = true)
17
+ def stories(options = {})
16
18
  stories = if options[:id]
17
19
  [@project.stories(options[:id]).get.payload]
18
20
  else
19
21
  @project.stories.get(params: options)
20
22
  end
21
23
  stories = stories.map { |s| Story.new(s, @project) }
22
- return stories if estimated == false
23
-
24
24
  stories.select(&:estimated)
25
25
  end
26
26
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'blanket'
4
- require 'story_branch/tracker_base'
4
+ require_relative '../tracker_base'
5
5
  require_relative './project'
6
6
 
7
7
  module StoryBranch
@@ -12,6 +12,7 @@ module StoryBranch
12
12
  API_URL = 'https://www.pivotaltracker.com/services/v5/'
13
13
 
14
14
  def initialize(project_id:, api_key:, **)
15
+ super
15
16
  @project_id = project_id
16
17
  @api_key = api_key
17
18
  end
@@ -11,7 +11,7 @@ module StoryBranch
11
11
  undef: :replace, # Replace anything not defined in ASCII
12
12
  replace: '-' # Use a dash for those replacements
13
13
  }
14
- res.encode(Encoding.find('ASCII'), encoding_options)
14
+ res.encode(Encoding.find('ASCII'), **encoding_options)
15
15
  end
16
16
 
17
17
  def self.dashed(text)
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pry'
4
-
5
3
  module StoryBranch
6
4
  # Base story branch tracker class that will define the expected interface
7
5
  class TrackerBase
6
+ def initialize(_options = {})
7
+ @issue_regex = Regexp.new('(\\d+)')
8
+ end
9
+
8
10
  def valid?
9
11
  raise 'valid? > must be implemented in the custom tracker'
10
12
  end
@@ -21,6 +23,21 @@ module StoryBranch
21
23
  []
22
24
  end
23
25
 
26
+ def current_story
27
+ return @current_story if @current_story
28
+
29
+ # TODO: This should look at the tracker configuration and search
30
+ # for the string either in the beginning or the end, according
31
+ # to what is configured
32
+ story_from_branch = GitUtils.branch_to_story_string(@issue_regex)
33
+ if story_from_branch.length == 2
34
+ @current_story = get_story_by_id(story_from_branch[0])
35
+ return @current_story
36
+ end
37
+ prompt.error('No tracked feature associated with this branch')
38
+ nil
39
+ end
40
+
24
41
  private
25
42
 
26
43
  def api
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoryBranch
4
+ # Class used to open a URL
5
+ class UrlOpener
6
+ def self.open_url(url)
7
+ url = "https://#{url}" unless url.start_with?('http')
8
+ case RbConfig::CONFIG['host_os']
9
+ when /mswin|mingw|cygwin/
10
+ system "start #{url}"
11
+ when /darwin/
12
+ system "open #{url}"
13
+ when /linux|bsd/
14
+ system "xdg-open #{url}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoryBranch
4
- VERSION = '0.7.0'
4
+ VERSION = '2.0.1'
5
5
  end
data/story_branch.gemspec CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
  'documentation_uri' => 'https://github.com/story-branch/story_branch/blob/master/README.md',
40
40
  'source_code_uri' => 'https://github.com/story-branch/story_branch'
41
41
  }
42
- spec.required_ruby_version = ['>= 2.4', '< 2.7']
42
+ spec.required_ruby_version = ['>= 2.4', '< 3.1']
43
43
 
44
44
  # Specify which files should be added to the gem when it is released.
45
45
  # The `git ls-files -z` loads the files in the RubyGem that have been
@@ -53,23 +53,25 @@ Gem::Specification.new do |spec|
53
53
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
54
54
  spec.require_paths = ['lib']
55
55
 
56
- spec.add_runtime_dependency 'blanket_wrapper', '~> 3.0'
57
- spec.add_runtime_dependency 'damerau-levenshtein', '~> 1.3'
58
- spec.add_runtime_dependency 'jira-ruby', '~> 1.7'
59
- spec.add_runtime_dependency 'thor', '~> 0.20.0'
60
- spec.add_runtime_dependency 'tty-command', '~> 0.8.2'
61
- spec.add_runtime_dependency 'tty-config', '~> 0.2.0'
62
- spec.add_runtime_dependency 'tty-pager', '~> 0.12'
63
- spec.add_runtime_dependency 'tty-prompt', '~> 0.18'
64
- spec.add_runtime_dependency 'xdg', '~> 3.0'
56
+ spec.add_runtime_dependency 'blanket_wrapper', '~> 3.0', '> 3.0'
57
+ spec.add_runtime_dependency 'damerau-levenshtein', '~> 1.3', '> 1.3'
58
+ spec.add_runtime_dependency 'jira-ruby', '> 1.7', '< 3'
59
+ spec.add_runtime_dependency 'thor', '> 0.20', '< 2'
60
+ spec.add_runtime_dependency 'tty-command', '~> 0.8', '> 0.8'
61
+ spec.add_runtime_dependency 'tty-config', '~> 0.2', '> 0.2'
62
+ spec.add_runtime_dependency 'tty-pager', '~> 0.12', '> 0.12'
63
+ spec.add_runtime_dependency 'tty-prompt', '~> 0.18', '> 0.18'
64
+ spec.add_runtime_dependency 'xdg', '> 3.0', '< 6'
65
65
 
66
- spec.add_development_dependency 'bundler', '~> 2.0'
67
- spec.add_development_dependency 'fakefs', '~> 0.14'
68
- spec.add_development_dependency 'git', '~> 1.5'
69
- spec.add_development_dependency 'ostruct', '~> 0.1'
70
- spec.add_development_dependency 'pry', '~> 0.11'
71
- spec.add_development_dependency 'rake', '~> 10.0'
72
- spec.add_development_dependency 'rspec', '~> 3'
73
- spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4'
66
+ spec.add_development_dependency 'bundler', '~> 2.1', '> 2.1'
67
+ spec.add_development_dependency 'fakefs', '> 0.14', '< 2'
68
+ spec.add_development_dependency 'git', '~> 1.5', '> 1.5'
69
+ spec.add_development_dependency 'ostruct', '~> 0.1', '> 0.1'
70
+ spec.add_development_dependency 'pry', '~> 0.11', '> 0.11'
71
+ spec.add_development_dependency 'rake', '>= 12.3.3', '< 14'
72
+ spec.add_development_dependency 'rubocop', '~> 1.22'
73
+ spec.add_development_dependency 'rspec', '~> 3', '> 3'
74
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4', '> 0.4'
75
+ spec.add_development_dependency 'simplecov', '~> 0.16', '> 0.16'
74
76
  end
75
77
  # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/story_branch/git_wrapper'
4
+
5
+ def grab_and_print_log(from, to)
6
+ all_log = StoryBranch::GitWrapper.command("log #{from}..#{to}")
7
+
8
+ matches = all_log.scan(/CHANGELOG\n(.*?)--- 8< ---/m).flatten
9
+ matches.map!(&:strip)
10
+
11
+ File.open("release-#{from}-#{to}.md", 'w') do |output|
12
+ output << "# RELEASE NOTES\n\n"
13
+ matches.each do |m|
14
+ output << "#{m}\n"
15
+ end
16
+ end
17
+ end
18
+
19
+ # rubocop:disable Metrics/MethodLength
20
+ # rubocop:disable Metrics/AbcSize
21
+ def print_all_logs
22
+ all_tags = StoryBranch::GitWrapper.command_lines('tag --list')
23
+ cleanup_tags = all_tags.map do |t|
24
+ { cleanup_tag: t.delete('v'), tag: t }
25
+ end
26
+ cleanup_tags.sort_by! { |ctags| ctags[:cleanup_tag] }
27
+ puts cleanup_tags
28
+
29
+ cleanup_tags.each_with_index do |tag, idx|
30
+ from = tag[:tag]
31
+ if idx + 1 == cleanup_tags.length
32
+ to = 'HEAD'
33
+ else
34
+ from = tag[:tag]
35
+ to = cleanup_tags[idx + 1][:tag]
36
+ end
37
+ grab_and_print_log(from, to)
38
+ end
39
+ end
40
+ # rubocop:enable Metrics/AbcSize
41
+ # rubocop:enable Metrics/MethodLength
42
+
43
+ all_logs = ARGV[0] == 'all'
44
+ if all_logs
45
+ print_all_logs
46
+ else
47
+ from = ARGV[0] || 'v0.7.0'
48
+ to = ARGV[1] || 'HEAD'
49
+ grab_and_print_log(from, to)
50
+ end