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 +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 -65
- 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: 36b917809872cfe428b4919698d7c9fc4cfa5ae9fee374ae9c3b893b5061080c
|
4
|
+
data.tar.gz: a44657b9ce55dd5fec18f68abc04109e49ee17e44e76e490b6e4bcfe61585d7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a043895d4a9e6057d243e5447eec1668e8c05a0190abd60cfe443e2f0c59784c9ed10d7865a1c04dbb8687889b7c480d0c0b08f6307d27776ccee623c577c0e0
|
7
|
+
data.tar.gz: 5a5020e9b44229ea153aeaa8f97eb83bf54a65567774eb2adb7ad1e01e12ed1df802c713412d5179029b2fb10ced2226a7b2752db040d005ccb668fd9dade5f6
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.2.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.2.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.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 = "
|
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/
|
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.
|
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
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
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
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.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:
|
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.
|
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:
|
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
|