git-story-workflow 0.11.1 → 1.2.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: fa0887c8fd640da56c1578e69a70043e614c1863c8dd2f62c07e2add8e0abfd8
4
- data.tar.gz: d08fcf94e5dab825e8cc38b204db3f2ff432ce981344fbde787a754f067904ea
3
+ metadata.gz: 36b917809872cfe428b4919698d7c9fc4cfa5ae9fee374ae9c3b893b5061080c
4
+ data.tar.gz: a44657b9ce55dd5fec18f68abc04109e49ee17e44e76e490b6e4bcfe61585d7d
5
5
  SHA512:
6
- metadata.gz: b4c7211fb8ba03d5867e6523e93d3824b3a69853a939bbbd71299d31e1f9e99992efd124a877897324ccaa0e11a8faeb353ef9b43d13c9d1baca25c4547f9ac6
7
- data.tar.gz: 5766e372298ad30fce87ad884d0f81a95c79c3e0af55d7240762f8e917139eee538c376c74cca0684f5101aa6dac23a30b1c1953085a22d3e2ab31bbfcda7226
6
+ metadata.gz: a043895d4a9e6057d243e5447eec1668e8c05a0190abd60cfe443e2f0c59784c9ed10d7865a1c04dbb8687889b7c480d0c0b08f6307d27776ccee623c577c0e0
7
+ data.tar.gz: 5a5020e9b44229ea153aeaa8f97eb83bf54a65567774eb2adb7ad1e01e12ed1df802c713412d5179029b2fb10ced2226a7b2752db040d005ccb668fd9dade5f6
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.1
1
+ 1.2.0
@@ -1,23 +1,23 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: git-story-workflow 0.11.1 ruby lib
2
+ # stub: git-story-workflow 1.2.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "git-story-workflow".freeze
6
- s.version = "0.11.1"
6
+ s.version = "1.2.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-03-02"
11
+ s.date = "2021-05-04"
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/pre-push".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.2.15".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.rb CHANGED
@@ -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'
data/lib/git/story/app.rb CHANGED
@@ -36,18 +36,13 @@ 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
- if @argv.empty?
41
- @command = nil
42
- else
43
- @command = (@argv * ?_).to_sym
44
- @argv.clear
45
- end
46
- @debug = debug
39
+ @opts = go 'n:', @argv
40
+ @debug = debug
41
+ determine_command
42
+ Git::Story::Setup.perform
47
43
  end
48
44
 
49
45
  def run
50
- Git::Story::Setup.perform
51
46
  if command_of(@command)
52
47
  if method(@command).parameters.include?(%i[key rest])
53
48
  puts __send__(@command, *@argv, rest: @rest_argv)
@@ -112,62 +107,6 @@ class Git::Story::App
112
107
  end
113
108
  end
114
109
 
115
- command doc: '[BRANCH] display test status of branch, -n SECONDS refreshes'
116
- def test_status(branch = current(check: false))
117
- url = nil
118
- watch do
119
- auth_token = complex_config.story.semaphore_auth_token
120
- project = complex_config.story.semaphore_test_project
121
- url = "https://semaphoreci.com/api/v1/projects/#{project}/#{branch}/status?auth_token=#{auth_token}"
122
- Git::Story::SemaphoreResponse.get(url, debug: @debug)
123
- end
124
- rescue => e
125
- "Getting #{url.inspect} => #{e.class}: #{e}".red
126
- end
127
-
128
- command doc: '[SERVER] display deploy status of branch, -n SECONDS refreshes'
129
- def deploy_status(server = complex_config.story.semaphore_default_server)
130
- url = nil
131
- watch do
132
- auth_token = complex_config.story.semaphore_auth_token
133
- project = complex_config.story.semaphore_test_project
134
- url = "https://semaphoreci.com/api/v1/projects/#{project}/servers/#{server}?auth_token=#{auth_token}"
135
- server = Git::Story::SemaphoreResponse.get(url, debug: @debug)
136
- deploys = server.deploys
137
- upcoming = deploys.select(&:pending?)&.last
138
- passed = deploys.select(&:passed?)
139
- current = passed.first
140
- if !passed.empty? && upcoming
141
- upcoming.estimated_duration = passed.sum { |d| d.duration.to_f } / passed.size
142
- end
143
- <<~end
144
- Server: #{server.server_name&.green}
145
- Branch: #{server.branch_name&.color('#ff5f00')}
146
- Semaphore: #{server.server_url}
147
- Strategy: #{server.strategy}
148
- Upcoming:
149
- #{upcoming}
150
- Current:
151
- #{current}
152
- end
153
- end
154
- rescue => e
155
- "Getting #{url.inspect} => #{e.class}: #{e}".red
156
- end
157
-
158
- command doc: '[BRANCH] display build status for branch, -n SECONDS refreshes'
159
- def build_status(branch = current(check: false))
160
- watch do
161
- [
162
- "Test Status".bold,
163
- test_status(branch) || 'n/a',
164
- "Deploy Status".bold,
165
- deploy_status || 'n/a',
166
- ] * "\n\n"
167
- end
168
- end
169
-
170
-
171
110
  command doc: '[STORY_ID] fetch status of current story, -n SECONDS refreshes'
172
111
  def status(story_id = current(check: true)&.[](/_(\d+)\z/, 1)&.to_i)
173
112
  if story = fetch_story(story_id)
@@ -361,8 +300,31 @@ class Git::Story::App
361
300
  nil
362
301
  end
363
302
 
303
+ command doc: 'open project on semaphore'
304
+ def semaphore
305
+ system "open #{complex_config.story.semaphore_project_url}"
306
+ nil
307
+ end
308
+
364
309
  private
365
310
 
311
+ def determine_command
312
+ c, command = [], nil
313
+ possible_commands = []
314
+ until @argv.empty?
315
+ c << @argv.shift
316
+ command = c.join(?_).to_sym
317
+ if command_of(command)
318
+ possible_commands << [ command, @argv.dup ]
319
+ end
320
+ end
321
+ unless possible_commands.empty?
322
+ @command, argv = possible_commands.last
323
+ @argv.replace(argv)
324
+ end
325
+ self
326
+ end
327
+
366
328
  def pick_branch(prompt:, symbol: ?⏻)
367
329
  ss = stories.map(&:story_base_name)
368
330
  branch = Search.new(
@@ -0,0 +1,35 @@
1
+ #!/bin/sh
2
+ # Installed by the git-story gem
3
+
4
+ remote="$1"
5
+ url="$2"
6
+
7
+ z40=0000000000000000000000000000000000000000
8
+
9
+ while read local_ref local_sha remote_ref remote_sha
10
+ do
11
+ if [ "$local_sha" = $z40 ]
12
+ then
13
+ # Handle delete
14
+ :
15
+ else
16
+ if [ "$remote_sha" = $z40 ]
17
+ then
18
+ # New branch, examine all commits
19
+ range="$local_sha"
20
+ else
21
+ # Update to existing branch, examine new commits
22
+ range="$remote_sha..$local_sha"
23
+ fi
24
+
25
+ # Check for WIP or [TODO] commit
26
+ commit=`git rev-list -n 1 --pretty=%B "$range" | egrep -i 'WIP|\[TODO\]'`
27
+ if [ -n "$commit" -a "$FORCE" != "1" ]
28
+ then
29
+ echo >&2 "Found WIP / [TODO] commit in $local_ref, not pushing"
30
+ exit 1
31
+ fi
32
+ fi
33
+ done
34
+
35
+ exit 0
@@ -11,30 +11,38 @@ module Git::Story::Setup
11
11
  module_function
12
12
 
13
13
  def perform(force: false)
14
- pcm = PREPARE_COMMIT_MESSAGE_DST
15
- if File.exist?(pcm)
16
- if force
17
- install_prepare_commit_msg
18
- elsif File.read(pcm).match?(MARKER)
19
- ;
20
- else
21
- ask(
22
- prompt: "File #{pcm.inspect} not created by git-story."\
23
- " Overwrite? (y/n, default is %s)",
24
- default: ?n,
25
- ) do |response|
26
- if response == ?y
27
- install_prepare_commit_msg
14
+ for filename in %w[ prepare-commit-msg pre-push ]
15
+ if path = file_installed?(filename)
16
+ if force
17
+ install_file filename
18
+ elsif File.read(path).match?(MARKER)
19
+ ;
20
+ else
21
+ ask(
22
+ prompt: "File #{path.inspect} not created by git-story."\
23
+ " Overwrite? (y/n, default is %s) ",
24
+ default: ?n,
25
+ ) do |response|
26
+ if response == ?y
27
+ install_file filename
28
+ end
28
29
  end
29
30
  end
31
+ else
32
+ install_file filename
30
33
  end
31
- else
32
- install_prepare_commit_msg
33
34
  end
34
35
  end
35
36
 
36
- def install_prepare_commit_msg
37
+ def file_installed?(filename)
38
+ path = File.join(HOOKS_DIR, filename)
39
+ if File.exist?(path)
40
+ path
41
+ end
42
+ end
43
+
44
+ def install_file(filename)
37
45
  File.exist?(HOOKS_DIR) or mkdir_p(HOOKS_DIR)
38
- cp PREPARE_COMMIT_MESSAGE_SRC, PREPARE_COMMIT_MESSAGE_DST
46
+ cp File.join(__dir__, filename), File.join(HOOKS_DIR, filename)
39
47
  end
40
48
  end
@@ -1,6 +1,6 @@
1
1
  module Git::Story
2
2
  # Git::Story version
3
- VERSION = '0.11.1'
3
+ VERSION = '1.2.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.11.1
4
+ version: 1.2.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-03-02 00:00:00.000000000 Z
11
+ date: 2021-05-04 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
@@ -175,8 +174,8 @@ files:
175
174
  - git-story-workflow.gemspec
176
175
  - lib/git/story.rb
177
176
  - lib/git/story/app.rb
177
+ - lib/git/story/pre-push
178
178
  - lib/git/story/prepare-commit-msg
179
- - lib/git/story/semaphore.rb
180
179
  - lib/git/story/setup.rb
181
180
  - lib/git/story/utils.rb
182
181
  - lib/git/story/version.rb
@@ -186,7 +185,7 @@ homepage: http://flori.github.com/git-story-workflow
186
185
  licenses:
187
186
  - Apache-2.0
188
187
  metadata: {}
189
- post_install_message:
188
+ post_install_message:
190
189
  rdoc_options:
191
190
  - "--title"
192
191
  - Git-story-workflow
@@ -205,8 +204,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
204
  - !ruby/object:Gem::Version
206
205
  version: '0'
207
206
  requirements: []
208
- rubygems_version: 3.1.2
209
- signing_key:
207
+ rubygems_version: 3.2.15
208
+ signing_key:
210
209
  specification_version: 4
211
210
  summary: Gem abstracting a git workflow
212
211
  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