git-story-workflow 0.11.0 → 1.1.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/git-story-workflow.gemspec +6 -6
- data/lib/git/story.rb +0 -1
- data/lib/git/story/app.rb +27 -63
- data/lib/git/story/pre-push +35 -0
- data/lib/git/story/setup.rb +26 -18
- data/lib/git/story/version.rb +1 -1
- metadata +7 -8
- data/lib/git/story/semaphore.rb +0 -141
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7db0a45891bcce9a80051da5c583b30218ef6ad2881006440c6995e6ba95ad40
|
4
|
+
data.tar.gz: abcb5921d4d65d818c39ff0ee8af5c77e8b3fd517506db141e0c25e8cd1ca8ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e69e2cfd05235940649f29100fa36acfb3edfec918c673e7a79f5468b1ee529db3a54c9d00cd0eca3e0cec12df0578b6b185cef6e45fe0af747664eac897a7f9
|
7
|
+
data.tar.gz: 13f82228787833511601d676f2a648d3e0cc00f31b6462794a8f99c062309cbfd66e362d4647e24c8d70154a0f0e651c3c463881e726f8f2f22c61aa9de432f0
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.1.0
|
data/git-story-workflow.gemspec
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: git-story-workflow
|
2
|
+
# stub: git-story-workflow 1.1.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "git-story-workflow".freeze
|
6
|
-
s.version = "
|
6
|
+
s.version = "1.1.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-
|
11
|
+
s.date = "2020-11-27"
|
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/
|
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/
|
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.
|
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
|
|
data/lib/git/story.rb
CHANGED
data/lib/git/story/app.rb
CHANGED
@@ -36,13 +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
|
40
|
-
@
|
41
|
-
|
39
|
+
@opts = go 'n:', @argv
|
40
|
+
@debug = debug
|
41
|
+
determine_command
|
42
|
+
Git::Story::Setup.perform
|
42
43
|
end
|
43
44
|
|
44
45
|
def run
|
45
|
-
Git::Story::Setup.perform
|
46
46
|
if command_of(@command)
|
47
47
|
if method(@command).parameters.include?(%i[key rest])
|
48
48
|
puts __send__(@command, *@argv, rest: @rest_argv)
|
@@ -50,8 +50,11 @@ class Git::Story::App
|
|
50
50
|
puts __send__(@command, *@argv)
|
51
51
|
end
|
52
52
|
else
|
53
|
-
|
54
|
-
|
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)
|
@@ -355,6 +302,23 @@ class Git::Story::App
|
|
355
302
|
|
356
303
|
private
|
357
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
|
+
|
358
322
|
def pick_branch(prompt:, symbol: ?⏻)
|
359
323
|
ss = stories.map(&:story_base_name)
|
360
324
|
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
|
data/lib/git/story/setup.rb
CHANGED
@@ -11,30 +11,38 @@ module Git::Story::Setup
|
|
11
11
|
module_function
|
12
12
|
|
13
13
|
def perform(force: false)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
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
|
46
|
+
cp File.join(__dir__, filename), File.join(HOOKS_DIR, filename)
|
39
47
|
end
|
40
48
|
end
|
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:
|
4
|
+
version: 1.1.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-
|
11
|
+
date: 2020-11-27 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.
|
209
|
-
signing_key:
|
207
|
+
rubygems_version: 3.1.4
|
208
|
+
signing_key:
|
210
209
|
specification_version: 4
|
211
210
|
summary: Gem abstracting a git workflow
|
212
211
|
test_files:
|
data/lib/git/story/semaphore.rb
DELETED
@@ -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
|