git-story-workflow 1.5.0 → 1.7.0
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/VERSION +1 -1
- data/config/story.yml +1 -1
- data/git-story-workflow.gemspec +4 -4
- data/lib/git/story/app.rb +103 -47
- data/lib/git/story/prepare-commit-msg +5 -8
- data/lib/git/story/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 596a9130689707c63f88c05175e839d2fd6618452096191d9f943ab7b0cf5273
|
4
|
+
data.tar.gz: e2917683df0992dc786210a6d666aa287f615501ab2334916d6a49c828579ddf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58477df77c6ab0ffcfda37cd1089dca528bb19b412f5e5359271d5b9956537c001f283e798881deedcae90f6ffd4254f76e37c95d7872e04caf3af9f1122b034
|
7
|
+
data.tar.gz: ce696203a7f9955074fa7829d5c2afd31adb884154c9eca38820bd9f91a38b5f97c6ba01c99523c1155316652503289f7bd7030ff4b3f442ddecdddab0823278
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0
|
data/config/story.yml
CHANGED
data/git-story-workflow.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: git-story-workflow 1.
|
2
|
+
# stub: git-story-workflow 1.7.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "git-story-workflow".freeze
|
6
|
-
s.version = "1.
|
6
|
+
s.version = "1.7.0"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib".freeze]
|
10
10
|
s.authors = ["Florian Frank".freeze]
|
11
|
-
s.date = "
|
11
|
+
s.date = "2022-01-12"
|
12
12
|
s.description = "Gem abstracting a git workflow\u2026".freeze
|
13
13
|
s.email = "flori@ping.de".freeze
|
14
14
|
s.executables = ["git-story".freeze]
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.homepage = "http://flori.github.com/git-story-workflow".freeze
|
18
18
|
s.licenses = ["Apache-2.0".freeze]
|
19
19
|
s.rdoc_options = ["--title".freeze, "Git-story-workflow".freeze, "--main".freeze, "README.md".freeze]
|
20
|
-
s.rubygems_version = "3.2.
|
20
|
+
s.rubygems_version = "3.2.22".freeze
|
21
21
|
s.summary = "Gem abstracting a git workflow".freeze
|
22
22
|
s.test_files = ["spec/git/story/app_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
23
23
|
|
data/lib/git/story/app.rb
CHANGED
@@ -100,31 +100,9 @@ class Git::Story::App
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
def provide_name(story_id = nil)
|
104
|
-
until story_id.present?
|
105
|
-
story_id = ask(prompt: 'Story id? ').strip
|
106
|
-
end
|
107
|
-
story_id = story_id.gsub(/[^0-9]+/, '')
|
108
|
-
@story_id = Integer(story_id)
|
109
|
-
if stories.any? { |s| s.story_id == @story_id }
|
110
|
-
@reason = "story for ##@story_id already created"
|
111
|
-
return
|
112
|
-
end
|
113
|
-
if name = fetch_story_name(@story_id)
|
114
|
-
name = normalize_name(
|
115
|
-
name,
|
116
|
-
max_size: 128 - 'story'.size - @story_id.to_s.size - 2 * ?_.size
|
117
|
-
).full? || name
|
118
|
-
[ 'story', name, @story_id ] * ?_
|
119
|
-
else
|
120
|
-
@reason = "name for ##@story_id could not be fetched from tracker"
|
121
|
-
return
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
103
|
command doc: '[STORY_ID] fetch status of current story, -n SECONDS refreshes'
|
126
104
|
def status(story_id = current(check: true)&.[](/_(\d+)\z/, 1)&.to_i)
|
127
|
-
if story = fetch_story(story_id)
|
105
|
+
if story = fetch_story(story_id, with_owner: true)
|
128
106
|
color_state =
|
129
107
|
case cs = story.current_state
|
130
108
|
when 'unscheduled', 'planned', 'unstarted'
|
@@ -147,20 +125,21 @@ class Git::Story::App
|
|
147
125
|
else
|
148
126
|
t
|
149
127
|
end
|
150
|
-
owners = Array(fetch_story_owners(story_id)).map { |o| "#{o.name} <#{o.email}>" }
|
151
128
|
result = <<~end
|
152
129
|
Id: #{(?# + story.id.to_s).green}
|
153
130
|
Name: #{story.name.inspect.bold}
|
154
131
|
Type: #{color_type}
|
155
132
|
Estimate: #{story.estimate.to_s.full? { |e| e.yellow.bold } || 'n/a'}
|
156
133
|
State: #{color_state}
|
157
|
-
Branch: #{current_branch_checked?&.color('#ff5f00')}
|
158
134
|
Labels: #{story.labels.map { |l| l.name.on_color(91) }.join(' ')}
|
159
|
-
Owners: #{owners.join(', ').yellow}
|
135
|
+
Owners: #{story.owners.map { |o| "%s <%s>" % [ o.name, o.email ] }.join(', ').yellow}
|
160
136
|
Pivotal: #{story.url.color(33)}
|
161
137
|
end
|
162
|
-
if url = github_url(current_branch_checked?)
|
163
|
-
result <<
|
138
|
+
if branch = current_branch_checked? and url = github_url(current_branch_checked?)
|
139
|
+
result << <<~end
|
140
|
+
Github: #{url.color(33)}
|
141
|
+
Branch: #{branch.color('#ff5f00')}
|
142
|
+
end
|
164
143
|
end
|
165
144
|
result
|
166
145
|
end
|
@@ -226,7 +205,8 @@ class Git::Story::App
|
|
226
205
|
fetch_tags
|
227
206
|
opts = ([
|
228
207
|
'--color=never',
|
229
|
-
'--pretty=%B'
|
208
|
+
'--pretty=%B',
|
209
|
+
'--reverse',
|
230
210
|
] | rest) * ' '
|
231
211
|
output = capture("git log #{opts} #{ref}")
|
232
212
|
pivotal_ids = SortedSet[]
|
@@ -234,18 +214,48 @@ class Git::Story::App
|
|
234
214
|
fetch_statuses(pivotal_ids) * (?┄ * Tins::Terminal.cols << ?\n)
|
235
215
|
end
|
236
216
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
217
|
+
command doc: '[REF] Create some parts of deploy document'
|
218
|
+
def deploy_document(ref = default_ref, rest: [])
|
219
|
+
ref = build_ref_range(ref)
|
220
|
+
fetch_commits
|
221
|
+
fetch_tags
|
222
|
+
opts = ([
|
223
|
+
'--color=never',
|
224
|
+
'--pretty=%B'
|
225
|
+
] | rest) * ' '
|
226
|
+
output = capture("git log #{opts} #{ref}")
|
227
|
+
pivotal_ids = SortedSet[]
|
228
|
+
output.scan(/\[\s*#\s*(\d+)\s*\]/) { pivotal_ids << $1.to_i }
|
229
|
+
stories = ''
|
230
|
+
attendees = Set[]
|
231
|
+
fetch_stories(pivotal_ids) do |pid|
|
232
|
+
story = fetch_story(pid, with_owner: true)
|
233
|
+
if !story
|
234
|
+
stories << "• ** Story with id #{pid} could not be found **"
|
235
|
+
next
|
236
|
+
end
|
237
|
+
attendees.merge story.owners
|
238
|
+
stories << <<~end
|
239
|
+
• [##{story.id}] #{story.name}
|
240
|
+
○ Pivotal: https://www.pivotaltracker.com/story/show/#{pid}
|
241
|
+
○ Type: #{story.story_type}
|
242
|
+
○ Status: #{story.current_state}
|
243
|
+
○ Owners: #{story.owners.map { |o| "%s <%s>" % [ o.name, o.email ] }.join(', ')}
|
244
|
+
○ Tasks to be done before deployment:
|
245
|
+
☐ …
|
246
|
+
○ Tasks to be done after deployment:
|
247
|
+
☐ …
|
248
|
+
end
|
241
249
|
end
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
250
|
+
attendees.map! { |a| "• @#{a.email}" }
|
251
|
+
<<~end
|
252
|
+
#{attendees.join(?\n)}
|
253
|
+
|
254
|
+
#{stories}
|
246
255
|
end
|
247
256
|
end
|
248
257
|
|
258
|
+
|
249
259
|
command doc: '[REF] output diff since last production deploy tag'
|
250
260
|
def deploy_diff(ref = default_ref, rest: [])
|
251
261
|
ref = build_ref_range(ref)
|
@@ -276,8 +286,8 @@ class Git::Story::App
|
|
276
286
|
"Story #{name} created.".green
|
277
287
|
end
|
278
288
|
|
279
|
-
command doc: '
|
280
|
-
def switch
|
289
|
+
command doc: 'switch to selected story branch'
|
290
|
+
def switch
|
281
291
|
fetch_commits
|
282
292
|
if branch = pick_branch(prompt: 'Switch to story? %s')
|
283
293
|
sh "git checkout #{branch}"
|
@@ -285,7 +295,7 @@ class Git::Story::App
|
|
285
295
|
end
|
286
296
|
end
|
287
297
|
|
288
|
-
command doc: '
|
298
|
+
command doc: 'delete selected story branch'
|
289
299
|
def delete(pattern = nil)
|
290
300
|
fetch_commits
|
291
301
|
if branch = pick_branch(prompt: 'Delete story branch? %s', symbol: ?⌦)
|
@@ -337,6 +347,28 @@ class Git::Story::App
|
|
337
347
|
|
338
348
|
private
|
339
349
|
|
350
|
+
def provide_name(story_id = nil)
|
351
|
+
until story_id.present?
|
352
|
+
story_id = ask(prompt: 'Story id? ').strip
|
353
|
+
end
|
354
|
+
story_id = story_id.gsub(/[^0-9]+/, '')
|
355
|
+
@story_id = Integer(story_id)
|
356
|
+
if stories.any? { |s| s.story_id == @story_id }
|
357
|
+
@reason = "story for ##@story_id already created"
|
358
|
+
return
|
359
|
+
end
|
360
|
+
if name = fetch_story_name(@story_id)
|
361
|
+
name = normalize_name(
|
362
|
+
name,
|
363
|
+
max_size: 128 - 'story'.size - @story_id.to_s.size - 2 * ?_.size
|
364
|
+
).full? || name
|
365
|
+
[ 'story', name, @story_id ] * ?_
|
366
|
+
else
|
367
|
+
@reason = "name for ##@story_id could not be fetched from tracker"
|
368
|
+
return
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
340
372
|
def determine_command
|
341
373
|
c, command = [], nil
|
342
374
|
possible_commands = []
|
@@ -448,11 +480,6 @@ class Git::Story::App
|
|
448
480
|
name
|
449
481
|
end
|
450
482
|
|
451
|
-
def apply_pattern(pattern, stories)
|
452
|
-
pattern = pattern.gsub(?#, '')
|
453
|
-
stories.grep(/#{Regexp.quote(pattern)}/)
|
454
|
-
end
|
455
|
-
|
456
483
|
def error(msg)
|
457
484
|
puts msg.red
|
458
485
|
exit 1
|
@@ -470,8 +497,11 @@ class Git::Story::App
|
|
470
497
|
fetch_story(story_id)&.name
|
471
498
|
end
|
472
499
|
|
473
|
-
def fetch_story(story_id)
|
474
|
-
pivotal_get("projects/#{pivotal_project}/stories/#{story_id}").full?
|
500
|
+
def fetch_story(story_id, with_owner: false)
|
501
|
+
if story = pivotal_get("projects/#{pivotal_project}/stories/#{story_id}").full?
|
502
|
+
story.owners = Array((fetch_story_owners(story_id) if with_owner))
|
503
|
+
end
|
504
|
+
story
|
475
505
|
end
|
476
506
|
|
477
507
|
def fetch_story_owners(story_id)
|
@@ -586,4 +616,30 @@ class Git::Story::App
|
|
586
616
|
url = url.sub('git@github.com:', 'https://github.com/')
|
587
617
|
url = url.sub(/(\.git)\z/, "/tree/#{branch}")
|
588
618
|
end
|
619
|
+
|
620
|
+
def fetch_stories(pivotal_ids, &block)
|
621
|
+
block or raise ArgumentError, '&block parameter is required'
|
622
|
+
tg = ThreadGroup.new
|
623
|
+
pivotal_ids.each do |pid|
|
624
|
+
order = 0
|
625
|
+
tg.add(
|
626
|
+
Thread.new do
|
627
|
+
Thread.current[:order] = order
|
628
|
+
Thread.current[:result] = block.(pid)
|
629
|
+
rescue
|
630
|
+
end
|
631
|
+
)
|
632
|
+
end
|
633
|
+
tg.list.with_infobar(label: 'Story').map do |t|
|
634
|
+
t.join
|
635
|
+
+infobar
|
636
|
+
[ t[:order], t[:result] ]
|
637
|
+
end.sort_by(&:first).transpose[1]
|
638
|
+
end
|
639
|
+
|
640
|
+
def fetch_statuses(pivotal_ids)
|
641
|
+
fetch_stories(pivotal_ids) do |pid|
|
642
|
+
status(pid)
|
643
|
+
end
|
644
|
+
end
|
589
645
|
end
|
@@ -26,12 +26,8 @@ class CommitMesssageParser
|
|
26
26
|
def parse(template)
|
27
27
|
@message_data = template.readlines
|
28
28
|
@message_data.each do |line|
|
29
|
-
if /^\s*\[.*(?:#\d
|
29
|
+
if /^\s*\[.*(?:#\d{7,}).*\]/i =~ line
|
30
30
|
@story_number_found = true
|
31
|
-
if @story_number_done = !!done
|
32
|
-
@message_data.slice!(@line_index)
|
33
|
-
next
|
34
|
-
end
|
35
31
|
end
|
36
32
|
if line =~ /^\s*#/
|
37
33
|
break
|
@@ -58,7 +54,7 @@ class CommitMesssageParser
|
|
58
54
|
end
|
59
55
|
|
60
56
|
story_numbers =
|
61
|
-
`git branch --no-color`.sub!(/^\* .*?(?:_(\d
|
57
|
+
`git branch --no-color`.sub!(/^\* .*?(?:_(\d{7,}(?:_\d{7,})*))$/) {
|
62
58
|
break $1.split(/_/)
|
63
59
|
} || []
|
64
60
|
story_numbers.map!(&:chomp)
|
@@ -67,8 +63,9 @@ Tempfile.open('commit') do |output|
|
|
67
63
|
message_parsed = CommitMesssageParser.new.parse(template)
|
68
64
|
if message_parsed.story_number_found?
|
69
65
|
output.puts message_parsed.total
|
70
|
-
elsif
|
71
|
-
|
66
|
+
elsif story_numbers.empty?
|
67
|
+
template.rewind
|
68
|
+
output.puts template.read
|
72
69
|
else
|
73
70
|
full_message = [ message_parsed.data, "", ]
|
74
71
|
if prefix = complex_config.story.pivotal_reference_prefix?
|
data/lib/git/story/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-story-workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gem_hadar
|
@@ -218,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
218
218
|
- !ruby/object:Gem::Version
|
219
219
|
version: '0'
|
220
220
|
requirements: []
|
221
|
-
rubygems_version: 3.2.
|
221
|
+
rubygems_version: 3.2.22
|
222
222
|
signing_key:
|
223
223
|
specification_version: 4
|
224
224
|
summary: Gem abstracting a git workflow
|