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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +32 -28
- data/.github/weekly-digest.yml +7 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +42 -0
- data/.ruby-version +1 -1
- data/README.md +14 -8
- data/docs/index.md +6 -6
- data/lib/story_branch/cli.rb +20 -8
- data/lib/story_branch/commands/{add.rb → configure.rb} +2 -3
- data/lib/story_branch/commands/create.rb +1 -0
- data/lib/story_branch/commands/finish.rb +1 -0
- data/lib/story_branch/commands/open_issue.rb +22 -0
- data/lib/story_branch/commands/start.rb +1 -0
- data/lib/story_branch/commands/unstart.rb +1 -0
- data/lib/story_branch/git_utils.rb +2 -19
- data/lib/story_branch/git_wrapper.rb +2 -2
- data/lib/story_branch/github/issue.rb +3 -4
- data/lib/story_branch/github/label.rb +1 -0
- data/lib/story_branch/github/tracker.rb +2 -1
- data/lib/story_branch/jira/issue.rb +8 -1
- data/lib/story_branch/jira/project.rb +1 -1
- data/lib/story_branch/jira/tracker.rb +6 -3
- data/lib/story_branch/main.rb +18 -29
- data/lib/story_branch/pivotal/project.rb +3 -3
- data/lib/story_branch/pivotal/tracker.rb +2 -1
- data/lib/story_branch/string_utils.rb +1 -1
- data/lib/story_branch/templates/open_issue/.gitkeep +1 -0
- data/lib/story_branch/tracker_base.rb +19 -2
- data/lib/story_branch/url_opener.rb +18 -0
- data/lib/story_branch/version.rb +1 -1
- data/story_branch.gemspec +20 -18
- data/tools/prep_changelog.rb +50 -0
- metadata +164 -24
- data/Gemfile.lock +0 -129
data/lib/story_branch/main.rb
CHANGED
@@ -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
|
81
|
-
|
82
|
-
current_story = GitUtils.current_branch_story_parts
|
90
|
+
return nil unless @tracker
|
83
91
|
|
84
|
-
|
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(
|
216
|
+
StoryBranch::Github::Tracker.new(**@config.tracker_params)
|
228
217
|
when 'pivotal-tracker'
|
229
|
-
StoryBranch::Pivotal::Tracker.new(
|
218
|
+
StoryBranch::Pivotal::Tracker.new(**@config.tracker_params)
|
230
219
|
when 'jira'
|
231
|
-
StoryBranch::Jira::Tracker.new(
|
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 = {}
|
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
|
-
|
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)
|
@@ -0,0 +1 @@
|
|
1
|
+
#
|
@@ -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
|
data/lib/story_branch/version.rb
CHANGED
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', '<
|
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', '
|
59
|
-
spec.add_runtime_dependency 'thor', '
|
60
|
-
spec.add_runtime_dependency 'tty-command', '~> 0.8.
|
61
|
-
spec.add_runtime_dependency 'tty-config', '~> 0.2.
|
62
|
-
spec.add_runtime_dependency 'tty-pager',
|
63
|
-
spec.add_runtime_dependency 'tty-prompt', '~> 0.18'
|
64
|
-
spec.add_runtime_dependency 'xdg', '
|
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.
|
67
|
-
spec.add_development_dependency 'fakefs', '
|
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', '
|
72
|
-
spec.add_development_dependency '
|
73
|
-
spec.add_development_dependency '
|
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
|