git-story-workflow 0.10.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0a262c355dd2d101911c442e5e9ba5d12da74967e3db37a600dc5f2f21ed1d9
4
- data.tar.gz: bfe8ea9f227c933eaec80aae69bef429cac5d76eb311b0ddf40b7bd6247e7779
3
+ metadata.gz: 7436139595b89b702416d8a9d0f792d2c4cf078a89d56ae462093e4a36c8b1f4
4
+ data.tar.gz: 3a2542c050b36b046b49130b356284825fa3fd6d2cfef9bffbdea7735298555f
5
5
  SHA512:
6
- metadata.gz: b4957004998e3f360de92b4724a65a86ea3bc0e8264e5a740c1f8c6d4e725a4e787f449d429cfb2e5e738cd8c60cc81a38f3b481a10682282dc075c22a196ff4
7
- data.tar.gz: 89b63867df083dccceb9673a9d18b6bfc04dcbe2e592cecf7a24826b753883079e5a8072d4645660a2e2af89427c516eba8019f3f55f189b825f1db9e4f7f3dd
6
+ metadata.gz: eb7071e5a13b018ed232b9ff0e15357037b417c24720ea420b0d1ed370e83ecd8b54b65f60f4f426c8a6c6c30db236894a6839504d389bf0343e6f2efac2771f
7
+ data.tar.gz: c1755fe341e1f171169627dfe4a9b40b20a9fe34fc565f5ae2ee2d2925aebbdb38949fd5b8a1e7285730bd25fffba1c7d7b750113a44b9af4acb4204de2725a9
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 1.0.0
@@ -1,23 +1,23 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: git-story-workflow 0.10.0 ruby lib
2
+ # stub: git-story-workflow 1.0.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "git-story-workflow".freeze
6
- s.version = "0.10.0"
6
+ s.version = "1.0.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 = "2020-02-11"
11
+ s.date = "2020-09-10"
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]
15
- s.extra_rdoc_files = ["README.md".freeze, "lib/git/story.rb".freeze, "lib/git/story/app.rb".freeze, "lib/git/story/semaphore.rb".freeze, "lib/git/story/setup.rb".freeze, "lib/git/story/utils.rb".freeze, "lib/git/story/version.rb".freeze]
16
- s.files = [".gitignore".freeze, "COPYING".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/git-story".freeze, "config/story.yml".freeze, "git-story-workflow.gemspec".freeze, "lib/git/story.rb".freeze, "lib/git/story/app.rb".freeze, "lib/git/story/prepare-commit-msg".freeze, "lib/git/story/semaphore.rb".freeze, "lib/git/story/setup.rb".freeze, "lib/git/story/utils.rb".freeze, "lib/git/story/version.rb".freeze, "spec/git/story/app_spec.rb".freeze, "spec/spec_helper.rb".freeze]
15
+ s.extra_rdoc_files = ["README.md".freeze, "lib/git/story.rb".freeze, "lib/git/story/app.rb".freeze, "lib/git/story/setup.rb".freeze, "lib/git/story/utils.rb".freeze, "lib/git/story/version.rb".freeze]
16
+ s.files = [".gitignore".freeze, "COPYING".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/git-story".freeze, "config/story.yml".freeze, "git-story-workflow.gemspec".freeze, "lib/git/story.rb".freeze, "lib/git/story/app.rb".freeze, "lib/git/story/prepare-commit-msg".freeze, "lib/git/story/setup.rb".freeze, "lib/git/story/utils.rb".freeze, "lib/git/story/version.rb".freeze, "spec/git/story/app_spec.rb".freeze, "spec/spec_helper.rb".freeze]
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.1.2".freeze
20
+ s.rubygems_version = "3.1.4".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
 
@@ -21,5 +21,4 @@ end
21
21
  require 'git/story/version'
22
22
  require 'git/story/utils'
23
23
  require 'git/story/setup'
24
- require 'git/story/semaphore'
25
24
  require 'git/story/app'
@@ -36,9 +36,9 @@ class Git::Story::App
36
36
  def initialize(argv = ARGV.dup, debug: ENV['DEBUG'].to_i == 1)
37
37
  @rest_argv = (sep = argv.index('--')) ? argv.slice!(sep..-1).tap(&:shift) : []
38
38
  @argv = argv
39
- @opts = go 'n:', @argv
40
- @command = @argv.shift&.to_sym
41
- @debug = debug
39
+ @opts = go 'n:', @argv
40
+ @debug = debug
41
+ determine_command
42
42
  end
43
43
 
44
44
  def run
@@ -50,8 +50,11 @@ class Git::Story::App
50
50
  puts __send__(@command, *@argv)
51
51
  end
52
52
  else
53
- @command and @command = @command.inspect
54
- @command ||= 'n/a'
53
+ if @command
54
+ @command = @command.inspect
55
+ else
56
+ @command = 'n/a'
57
+ end
55
58
  STDERR.puts "Unknown command #{@command}\n\n#{help.join(?\n)}"
56
59
  exit 1
57
60
  end
@@ -64,7 +67,7 @@ class Git::Story::App
64
67
  longest = command_annotations.keys.map(&:size).max
65
68
  result.concat(
66
69
  command_annotations.map { |name, a|
67
- "#{name.to_s.ljust(longest)} #{a[:doc]}"
70
+ "#{name.to_s.gsub(?_, ' ').ljust(longest)} #{a[:doc]}"
68
71
  }
69
72
  )
70
73
  end
@@ -104,62 +107,6 @@ class Git::Story::App
104
107
  end
105
108
  end
106
109
 
107
- command doc: '[BRANCH] display test status of branch, -n SECONDS refreshes'
108
- def test_status(branch = current(check: false))
109
- url = nil
110
- watch do
111
- auth_token = complex_config.story.semaphore_auth_token
112
- project = complex_config.story.semaphore_test_project
113
- url = "https://semaphoreci.com/api/v1/projects/#{project}/#{branch}/status?auth_token=#{auth_token}"
114
- Git::Story::SemaphoreResponse.get(url, debug: @debug)
115
- end
116
- rescue => e
117
- "Getting #{url.inspect} => #{e.class}: #{e}".red
118
- end
119
-
120
- command doc: '[SERVER] display deploy status of branch, -n SECONDS refreshes'
121
- def deploy_status(server = complex_config.story.semaphore_default_server)
122
- url = nil
123
- watch do
124
- auth_token = complex_config.story.semaphore_auth_token
125
- project = complex_config.story.semaphore_test_project
126
- url = "https://semaphoreci.com/api/v1/projects/#{project}/servers/#{server}?auth_token=#{auth_token}"
127
- server = Git::Story::SemaphoreResponse.get(url, debug: @debug)
128
- deploys = server.deploys
129
- upcoming = deploys.select(&:pending?)&.last
130
- passed = deploys.select(&:passed?)
131
- current = passed.first
132
- if !passed.empty? && upcoming
133
- upcoming.estimated_duration = passed.sum { |d| d.duration.to_f } / passed.size
134
- end
135
- <<~end
136
- Server: #{server.server_name&.green}
137
- Branch: #{server.branch_name&.color('#ff5f00')}
138
- Semaphore: #{server.server_url}
139
- Strategy: #{server.strategy}
140
- Upcoming:
141
- #{upcoming}
142
- Current:
143
- #{current}
144
- end
145
- end
146
- rescue => e
147
- "Getting #{url.inspect} => #{e.class}: #{e}".red
148
- end
149
-
150
- command doc: '[BRANCH] display build status for branch, -n SECONDS refreshes'
151
- def build_status(branch = current(check: false))
152
- watch do
153
- [
154
- "Test Status".bold,
155
- test_status(branch) || 'n/a',
156
- "Deploy Status".bold,
157
- deploy_status || 'n/a',
158
- ] * "\n\n"
159
- end
160
- end
161
-
162
-
163
110
  command doc: '[STORY_ID] fetch status of current story, -n SECONDS refreshes'
164
111
  def status(story_id = current(check: true)&.[](/_(\d+)\z/, 1)&.to_i)
165
112
  if story = fetch_story(story_id)
@@ -317,34 +264,25 @@ class Git::Story::App
317
264
  command doc: '[PATTERN] switch to story matching PATTERN'
318
265
  def switch(pattern = nil)
319
266
  fetch_commits
320
- ss = stories.map(&:story_base_name)
321
- branch = Search.new(
322
- match: -> answer {
323
- answer = answer.strip.delete(?#).downcase
324
-
325
- matcher = Amatch::PairDistance.new(answer)
326
- matches = ss.map { |n| [ n, -matcher.similar(n.downcase) ] }.
327
- select { |_, s| s < 0 }.sort_by(&:last).map(&:first)
328
-
329
- matches.empty? and matches = ss
330
- matches.first(Tins::Terminal.lines - 1)
331
- },
332
- query: -> _answer, matches, selector {
333
- matches.each_with_index.
334
- map { |m, i| i == selector ? '⏻ ' + Search.on_blue(m) : '┊ ' + m } * ?\n
335
- },
336
- found: -> _answer, matches, selector {
337
- matches[selector]
338
- },
339
- prompt: 'Story? %s'.bold,
340
- output: STDOUT
341
- ).start
342
- if branch
267
+ if branch = pick_branch(prompt: 'Switch to story? %s')
343
268
  sh "git checkout #{branch}"
344
269
  return "Switched to story: #{branch}".green
345
270
  end
346
271
  end
347
272
 
273
+ command doc: '[PATTERN] delete story branch matching PATTERN'
274
+ def delete(pattern = nil)
275
+ fetch_commits
276
+ if branch = pick_branch(prompt: 'Delete story branch? %s', symbol: ?⌦)
277
+ sh "git pull origin #{branch}"
278
+ sh "git branch -d #{branch}"
279
+ if ask(prompt: 'Delete remote branch? (y/N) ') =~ /\Ay\z/i
280
+ sh "git push origin #{branch} --delete"
281
+ end
282
+ return "Deleted story branch: #{branch}".green
283
+ end
284
+ end
285
+
348
286
  command doc: '[BRANCH] open branch on github'
349
287
  def github(branch = current(check: false))
350
288
  if url = github_url(branch)
@@ -364,6 +302,48 @@ class Git::Story::App
364
302
 
365
303
  private
366
304
 
305
+ def determine_command
306
+ c, command = [], nil
307
+ possible_commands = []
308
+ until @argv.empty?
309
+ c << @argv.shift
310
+ command = c.join(?_).to_sym
311
+ if command_of(command)
312
+ possible_commands << [ command, @argv.dup ]
313
+ end
314
+ end
315
+ unless possible_commands.empty?
316
+ @command, argv = possible_commands.last
317
+ @argv.replace(argv)
318
+ end
319
+ self
320
+ end
321
+
322
+ def pick_branch(prompt:, symbol: ?⏻)
323
+ ss = stories.map(&:story_base_name)
324
+ branch = Search.new(
325
+ match: -> answer {
326
+ answer = answer.strip.delete(?#).downcase
327
+
328
+ matcher = Amatch::PairDistance.new(answer)
329
+ matches = ss.map { |n| [ n, -matcher.similar(n.downcase) ] }.
330
+ select { |_, s| s < 0 }.sort_by(&:last).map(&:first)
331
+
332
+ matches.empty? and matches = ss
333
+ matches.first(Tins::Terminal.lines - 1)
334
+ },
335
+ query: -> _answer, matches, selector {
336
+ matches.each_with_index.
337
+ map { |m, i| i == selector ? "#{symbol} " + Search.on_blue(m) : '┊ ' + m } * ?\n
338
+ },
339
+ found: -> _answer, matches, selector {
340
+ matches[selector]
341
+ },
342
+ prompt: prompt.bold,
343
+ output: STDOUT
344
+ ).start
345
+ end
346
+
367
347
  def default_ref
368
348
  tags.last
369
349
  end
@@ -1,6 +1,6 @@
1
1
  module Git::Story
2
2
  # Git::Story version
3
- VERSION = '0.10.0'
3
+ VERSION = '1.0.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
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: 0.10.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-11 00:00:00.000000000 Z
11
+ date: 2020-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -159,7 +159,6 @@ extra_rdoc_files:
159
159
  - README.md
160
160
  - lib/git/story.rb
161
161
  - lib/git/story/app.rb
162
- - lib/git/story/semaphore.rb
163
162
  - lib/git/story/setup.rb
164
163
  - lib/git/story/utils.rb
165
164
  - lib/git/story/version.rb
@@ -176,7 +175,6 @@ files:
176
175
  - lib/git/story.rb
177
176
  - lib/git/story/app.rb
178
177
  - lib/git/story/prepare-commit-msg
179
- - lib/git/story/semaphore.rb
180
178
  - lib/git/story/setup.rb
181
179
  - lib/git/story/utils.rb
182
180
  - lib/git/story/version.rb
@@ -186,7 +184,7 @@ homepage: http://flori.github.com/git-story-workflow
186
184
  licenses:
187
185
  - Apache-2.0
188
186
  metadata: {}
189
- post_install_message:
187
+ post_install_message:
190
188
  rdoc_options:
191
189
  - "--title"
192
190
  - Git-story-workflow
@@ -205,8 +203,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
203
  - !ruby/object:Gem::Version
206
204
  version: '0'
207
205
  requirements: []
208
- rubygems_version: 3.1.2
209
- signing_key:
206
+ rubygems_version: 3.1.4
207
+ signing_key:
210
208
  specification_version: 4
211
209
  summary: Gem abstracting a git workflow
212
210
  test_files:
@@ -1,141 +0,0 @@
1
- require 'json'
2
- require 'time'
3
- require 'open-uri'
4
- require 'infobar'
5
-
6
- class Git::Story::SemaphoreResponse < JSON::GenericObject
7
- def self.get(url, debug: false)
8
- data = URI.open(url).read
9
- debug and STDERR.puts JSON.pretty_generate(JSON(data))
10
- result = JSON(data, object_class: self)
11
- result.debug = debug
12
- result
13
- end
14
-
15
- def duration(time = nil)
16
- unless time
17
- if finished_at.nil?
18
- time = Time.now
19
- else
20
- time = Time.parse(finished_at)
21
- end
22
- end
23
- if started_at
24
- Tins::Duration.new(time - Time.parse(started_at))
25
- else
26
- Tins::Duration.new(0)
27
- end
28
- end
29
-
30
- def pending?
31
- result == 'pending'
32
- end
33
-
34
- def building?
35
- !started_at.nil?
36
- end
37
-
38
- def passed?
39
- result == 'passed'
40
- end
41
-
42
- def failed?
43
- result == 'failed'
44
- end
45
-
46
- def canceled?
47
- result == 'canceled'
48
- end
49
-
50
- def finished?
51
- finished_at.blank?
52
- end
53
-
54
- def sha1
55
- commit.id[0,10]
56
- end
57
-
58
- def entity_url
59
- server_html_url || build_url
60
- end
61
-
62
- def entity_name
63
- branch_name || server_name
64
- end
65
-
66
- def branch_history
67
- if branch_history_url
68
- self.class.get(branch_history_url, debug: debug)&.builds
69
- else
70
- []
71
- end
72
- end
73
-
74
- def estimated_duration
75
- if ed = super
76
- ed
77
- else
78
- times = branch_history.select(&:passed?).map { |b|
79
- Time.parse(b.finished_at) - Time.parse(b.started_at)
80
- }
81
- if times.empty?
82
- duration
83
- else
84
- times.sum / times.size
85
- end.to_f
86
- end
87
- end
88
-
89
- def infobar_style
90
- case
91
- when passed?, pending?
92
- {
93
- done_fg_color: '#005f00',
94
- done_bg_color: '#00d700',
95
- todo_fg_color: '#00d700',
96
- todo_bg_color: '#005f00',
97
- }
98
- else
99
- {
100
- done_fg_color: '#5f0000',
101
- done_bg_color: '#d70000',
102
- todo_fg_color: '#d70000',
103
- todo_bg_color: '#5f0000',
104
- }
105
- end
106
- end
107
-
108
- def to_s
109
- r = case
110
- when pending? && building?
111
- "#{entity_name} ##{sha1} building for #{duration(Time.now)}".yellow.bold
112
- when pending?
113
- "#{entity_name} ##{sha1} pending at the moment".yellow
114
- when passed?
115
- "#{entity_name} ##{sha1} passed after #{duration}".green
116
- when failed?
117
- "#{entity_name} ##{sha1} failed after #{duration}".red
118
- else
119
- "#{entity_name} ##{sha1} in state #{result}".blue
120
- end
121
- r = StringIO.new(r)
122
- duration_seconds = duration.to_f.to_i
123
- if passed? || failed?
124
- total_seconds = duration_seconds
125
- else
126
- total_seconds = estimated_duration.to_i
127
- end
128
- Infobar(
129
- current: duration_seconds,
130
- total: total_seconds,
131
- message: ' %l %c/%t seconds ',
132
- style: infobar_style,
133
- output: r
134
- ).update
135
- r <<
136
- "\n Semaphore: #{entity_url}" <<
137
- "\n Commit: #{commit.url}\n#{commit.message&.gsub(/^/, " " * 10)&.color(33)}" <<
138
- "\n Authored: #{(commit.author_name + ' <' + commit.author_email + ?>).bold} @#{commit.timestamp}"
139
- r.tap(&:rewind).read
140
- end
141
- end