abak-flow 0.3.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +10 -1
- data/README.md +13 -30
- data/Rakefile +25 -0
- data/VERSION +1 -1
- data/abak-flow.gemspec +23 -19
- data/bin/request +1 -2
- data/lib/abak-flow/branch.rb +108 -0
- data/lib/abak-flow/branches.rb +68 -0
- data/lib/abak-flow/configuration.rb +67 -0
- data/lib/abak-flow/locales/en.yml +32 -0
- data/lib/abak-flow/locales/ru.yml +32 -0
- data/lib/abak-flow/manager.rb +35 -0
- data/lib/abak-flow/messages.rb +86 -0
- data/lib/abak-flow/pull_request.rb +39 -199
- data/lib/abak-flow/repository.rb +71 -0
- data/lib/abak-flow/request.rb +88 -198
- data/lib/abak-flow/version.rb +1 -1
- data/lib/abak-flow/visitor.rb +43 -0
- data/lib/abak-flow.rb +20 -13
- data/spec/abak-flow/branch_spec.rb +55 -0
- data/spec/abak-flow/branches_spec.rb +20 -0
- data/spec/abak-flow/configuration_spec.rb +73 -0
- data/spec/abak-flow/git_spec.rb +12 -0
- data/spec/abak-flow/github_client_spec.rb +15 -0
- data/spec/abak-flow/messages_spec.rb +146 -0
- data/spec/abak-flow/project_spec.rb +52 -0
- data/spec/abak-flow/pull_request_spec.rb +353 -0
- data/spec/abak-flow/system_spec.rb +97 -0
- data/spec/spec_helper.rb +17 -0
- metadata +82 -31
- data/lib/abak-flow/config.rb +0 -20
- data/lib/abak-flow/extensions.rb +0 -125
- data/lib/abak-flow/github_client.rb +0 -13
@@ -1,221 +1,61 @@
|
|
1
|
-
#
|
1
|
+
# coding: utf-8
|
2
|
+
require "ruler"
|
3
|
+
|
2
4
|
module Abak::Flow
|
3
5
|
class PullRequest
|
4
|
-
|
5
|
-
|
6
|
-
attr_reader :repository, :request_params
|
7
|
-
attr_reader :config, :validator
|
6
|
+
include Ruler
|
8
7
|
|
9
|
-
|
10
|
-
strategy = options.delete(:strategy) || :publish
|
8
|
+
attr_reader :errors, :link
|
11
9
|
|
12
|
-
|
13
|
-
@
|
14
|
-
@
|
10
|
+
def initialize(params, manager)
|
11
|
+
@manager = manager
|
12
|
+
@errors = []
|
15
13
|
|
16
|
-
@
|
14
|
+
@head = params.fetch(:head)
|
15
|
+
@base = params.fetch(:base)
|
16
|
+
@title = params.fetch(:title)
|
17
|
+
@body = params.fetch(:body)
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
def ready?
|
21
|
+
@errors = []
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@branch_prefix ||= current_branch.include?('/') ? current_branch.split('/').first : ''
|
28
|
-
end
|
23
|
+
multi_ruleset do
|
24
|
+
fact(:head_is_incorrect) { not @head.valid? }
|
25
|
+
fact(:base_is_incorrect) { not @base.valid? }
|
26
|
+
fact(:title_is_incorrect) { @title.empty? }
|
27
|
+
fact(:body_is_incorrect) { @body.empty? }
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def from_repo
|
35
|
-
@from_repo ||= begin
|
36
|
-
upstream_project = repository.remote_by_name('upstream').project
|
37
|
-
"#{upstream_project.owner}/#{upstream_project.name}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
alias_method :upstream_project, :from_repo
|
41
|
-
|
42
|
-
def origin_project
|
43
|
-
@origin_project ||= begin
|
44
|
-
origin_project = repository.remote_by_name('origin').project
|
45
|
-
"#{origin_project.owner}/#{origin_project.name}"
|
29
|
+
rule([:head_is_incorrect]) { @errors << I18n.t("pull_request.errors.head_is_incorrect") }
|
30
|
+
rule([:base_is_incorrect]) { @errors << I18n.t("pull_request.errors.base_is_incorrect") }
|
31
|
+
rule([:title_is_incorrect]) { @errors << I18n.t("pull_request.errors.title_is_incorrect") }
|
32
|
+
rule([:body_is_incorrect]) { @errors << I18n.t("pull_request.errors.body_is_incorrect") }
|
46
33
|
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def origin_repo
|
50
|
-
@origin_repo ||= repository.main_project.remote.name
|
51
|
-
end
|
52
|
-
|
53
|
-
def base
|
54
|
-
exit unless validator.valid?
|
55
|
-
|
56
|
-
branch = Abak::Flow::PullRequest.branch_by_prefix(branch_prefix)
|
57
34
|
|
58
|
-
|
35
|
+
@errors.empty? ? true : false
|
59
36
|
end
|
60
37
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
request_params.head || "#{repository.repo_owner}:#{current_branch}"
|
65
|
-
end
|
66
|
-
|
67
|
-
def title
|
68
|
-
exit unless validator.valid?
|
69
|
-
|
70
|
-
request_params.title
|
71
|
-
end
|
72
|
-
|
73
|
-
def body
|
74
|
-
exit unless validator.valid?
|
75
|
-
|
76
|
-
request_params.body
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.branch_by_prefix(prefix)
|
80
|
-
{:feature => :develop, :hotfix => :master}.fetch(prefix.to_sym, '')
|
81
|
-
end
|
82
|
-
|
83
|
-
# TODO Вынести
|
84
|
-
class Validator
|
85
|
-
attr_reader :strategy, :target_object
|
86
|
-
attr_reader :errors, :executed
|
87
|
-
|
88
|
-
def initialize(strategy_name, target_object)
|
89
|
-
@strategy = Abak::Flow::PullRequest.const_get("Strategy#{strategy_name.capitalize}".to_sym)
|
90
|
-
@target_object = target_object
|
91
|
-
@errors = []
|
92
|
-
end
|
93
|
-
|
94
|
-
def valid?
|
95
|
-
return errors.empty? if executed
|
96
|
-
|
97
|
-
validate!
|
98
|
-
errors.empty?
|
99
|
-
end
|
100
|
-
|
101
|
-
protected
|
102
|
-
def validate!
|
103
|
-
@executed = true
|
104
|
-
|
105
|
-
strategy.attributes.each do |attribute|
|
106
|
-
send("validate_#{attribute}")
|
107
|
-
end
|
108
|
-
|
109
|
-
print_errors
|
110
|
-
end
|
111
|
-
|
112
|
-
def print_errors
|
113
|
-
errors.each do |error|
|
114
|
-
say color(error[:message], :error).to_s
|
115
|
-
say color(error[:tip], :info).to_s
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def validate_api_user
|
120
|
-
return if target_object.config.api_user?
|
121
|
-
|
122
|
-
@errors << {
|
123
|
-
:message => 'Необходимо указать своего пользователя API github',
|
124
|
-
:tip => '=> https://github.com/Strech/abak-flow/blob/master/README.md'
|
125
|
-
}
|
126
|
-
end
|
127
|
-
|
128
|
-
def validate_api_token
|
129
|
-
return if target_object.config.api_token?
|
130
|
-
|
131
|
-
@errors << {
|
132
|
-
:message => 'Необходимо указать токен своего пользователя API github',
|
133
|
-
:tip => '=> https://github.com/Strech/abak-flow/blob/master/README.md'
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
def validate_origin
|
138
|
-
return unless target_object.repository.remote_by_name('origin').nil?
|
139
|
-
|
140
|
-
@errors << {
|
141
|
-
:message => 'Необходимо настроить репозиторий origin (форк) для текущего пользователя',
|
142
|
-
:tip => '=> git remote add origin https://Developer@github.com/abak-press/sample.git'
|
143
|
-
}
|
144
|
-
end
|
145
|
-
|
146
|
-
def validate_upstream
|
147
|
-
return unless target_object.repository.remote_by_name('upstream').nil?
|
148
|
-
|
149
|
-
@errors << {
|
150
|
-
:message => 'Необходимо настроить репозиторий upstream (главный) для текущего пользователя',
|
151
|
-
:tip => '=> git remote add upstream https://Developer@github.com/abak-press/sample.git'
|
152
|
-
}
|
153
|
-
end
|
154
|
-
|
155
|
-
def validate_title
|
156
|
-
return unless target_object.request_params.title.empty?
|
157
|
-
|
158
|
-
@errors << {
|
159
|
-
:message => 'Пожалуйста, укажите что-нибудь для заголовка pull request, например номер вашей задачи вот так:',
|
160
|
-
:tip => '=> git request publish "PC-001"'
|
161
|
-
}
|
162
|
-
end
|
163
|
-
|
164
|
-
def validate_branch
|
165
|
-
return if [:master, :develop].include?(target_object.current_branch.to_sym)
|
166
|
-
|
167
|
-
@errors << {
|
168
|
-
:message => 'Нельзя делать pull request из меток master или develop, попробуйде переключиться, например так:',
|
169
|
-
:tip => '=> git checkout master'
|
170
|
-
}
|
171
|
-
end
|
172
|
-
|
173
|
-
def validate_deleted_branch
|
174
|
-
return unless [:master, :develop].include?(target_object.current_branch.to_sym)
|
175
|
-
|
176
|
-
@errors << {
|
177
|
-
:message => 'Извините, но нельзя удалить ветку develop или master',
|
178
|
-
:tip => '=> git checkout feature/TASK-0001'
|
179
|
-
}
|
180
|
-
end
|
38
|
+
def display_name
|
39
|
+
I18n.t("pull_request.name")
|
181
40
|
end
|
182
41
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
end
|
187
|
-
end
|
42
|
+
def publish
|
43
|
+
begin
|
44
|
+
head_with_repo = [@manager.repository.origin.owner, @head] * ':'
|
188
45
|
|
189
|
-
|
190
|
-
|
191
|
-
StrategyReadycheck.attributes | [:title, :branch]
|
192
|
-
end
|
193
|
-
end
|
46
|
+
response = @manager.github.create_pull_request(
|
47
|
+
@manager.repository.upstream.to_s, @base.to_s, head_with_repo, @title, @body)
|
194
48
|
|
195
|
-
|
196
|
-
def self.attributes
|
197
|
-
StrategyReadycheck.attributes | [:title]
|
198
|
-
end
|
199
|
-
end
|
49
|
+
@link = response._links.html.href
|
200
50
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
end
|
51
|
+
true
|
52
|
+
rescue Exception => exception
|
53
|
+
backtrace = exception.backtrace[0...10] * "\n"
|
206
54
|
|
207
|
-
|
208
|
-
def self.attributes
|
209
|
-
StrategyReadycheck.attributes | [:deleted_branch]
|
210
|
-
end
|
211
|
-
end
|
55
|
+
@errors = ["#{exception.message}\n\n#{backtrace}"]
|
212
56
|
|
213
|
-
|
214
|
-
def self.attributes
|
215
|
-
[:origin, :upstream, :api_user, :api_token]
|
57
|
+
false
|
216
58
|
end
|
217
59
|
end
|
218
|
-
|
219
|
-
|
220
|
-
end
|
221
|
-
end
|
60
|
+
end # class PullRequest
|
61
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "i18n"
|
3
|
+
require "ruler"
|
4
|
+
require "forwardable"
|
5
|
+
|
6
|
+
module Abak::Flow
|
7
|
+
class Repository
|
8
|
+
include Ruler
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
REMOTES = [:origin, :upstream].freeze
|
12
|
+
|
13
|
+
def_delegators :@manager, :git
|
14
|
+
|
15
|
+
attr_reader :errors
|
16
|
+
|
17
|
+
def initialize(manager)
|
18
|
+
@manager = manager
|
19
|
+
@errors = []
|
20
|
+
|
21
|
+
configure!
|
22
|
+
end
|
23
|
+
|
24
|
+
def ready?
|
25
|
+
@errors = []
|
26
|
+
|
27
|
+
multi_ruleset do
|
28
|
+
fact(:origin_not_setup) { origin.nil? }
|
29
|
+
fact(:upstream_not_setup) { upstream.nil? }
|
30
|
+
|
31
|
+
rule([:origin_not_setup]) { @errors << I18n.t("repository.errors.origin_not_setup") }
|
32
|
+
rule([:upstream_not_setup]) { @errors << I18n.t("repository.errors.upstream_not_setup") }
|
33
|
+
end
|
34
|
+
|
35
|
+
@errors.empty? ? true : false
|
36
|
+
end
|
37
|
+
|
38
|
+
def display_name
|
39
|
+
I18n.t("repository.name")
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def configure!
|
44
|
+
remotes = Hash[fetch_remotes_from_git]
|
45
|
+
REMOTES.each do |name|
|
46
|
+
define_singleton_method(name) { remotes[name] }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_remotes_from_git
|
51
|
+
git.remotes.
|
52
|
+
select { |remote| REMOTES.include?(remote.name.to_sym) }.
|
53
|
+
map { |remote| create_remote(remote) }.
|
54
|
+
compact
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_remote(remote)
|
58
|
+
matches = /.+.github\.com[\:|\/](?<owner>.+)\/(?<project>.+).git/.match(remote.url)
|
59
|
+
|
60
|
+
if !matches.nil? && matches.captures.length == 2
|
61
|
+
[remote.name.to_sym, Remote.new(matches[:owner], matches[:project], remote)]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Remote < Struct.new(:owner, :project, :repo)
|
66
|
+
def to_s
|
67
|
+
"#{owner}/#{project}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/abak-flow/request.rb
CHANGED
@@ -1,234 +1,124 @@
|
|
1
|
-
#
|
1
|
+
# coding: utf-8
|
2
|
+
require "commander/import"
|
3
|
+
require "ansi/code"
|
4
|
+
|
2
5
|
module Abak::Flow
|
3
|
-
program :name,
|
6
|
+
program :name, "Утилита для оформления pull request на github.com"
|
4
7
|
program :version, Abak::Flow::VERSION
|
5
|
-
program :description,
|
8
|
+
program :description, "Утилита, заточенная под git-flow но с использованием github.com"
|
6
9
|
|
7
10
|
default_command :help
|
8
|
-
command :publish do |c|
|
9
|
-
c.syntax = 'git request publish <Заголовок>'
|
10
|
-
c.description = 'Оформить pull request из текущей ветки (feature -> develop, hotfix -> master)'
|
11
11
|
|
12
|
-
|
13
|
-
c.
|
14
|
-
c.
|
12
|
+
command :checkup do |c|
|
13
|
+
c.syntax = "git request checkup"
|
14
|
+
c.description = "Проверить все ли настроено для работы с github и удаленными репозиториями"
|
15
15
|
|
16
16
|
c.action do |args, options|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
if request.default_task =~ /^\w+\-\d{1,}$/
|
27
|
-
title = request.default_task if title.empty?
|
28
|
-
body = jira_browse_url + request.default_task
|
29
|
-
end
|
30
|
-
|
31
|
-
request.title = title
|
32
|
-
request.body = body
|
33
|
-
|
34
|
-
exit unless request.valid?
|
35
|
-
|
36
|
-
# Запушим текущую ветку на origin
|
37
|
-
say "=> Обновляю ветку #{request.current_branch} на origin"
|
38
|
-
Hub::Runner.execute('push', 'origin', request.current_branch)
|
39
|
-
|
40
|
-
# Запостим pull request на upstream
|
41
|
-
say '=> Делаю pull request на upstream'
|
42
|
-
begin
|
43
|
-
result = github_client.create_pull_request(request.from_repo, request.base, request.head, request.title, request.body)
|
44
|
-
say color(result._links.html.href, :green).to_s
|
45
|
-
rescue => e
|
46
|
-
say color(e.message, :error).to_s
|
47
|
-
say "\nПроблемы? Попробуйте заглянуть сюда:"
|
48
|
-
say color('=> cписок кодов статуса ответа http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html', :info).to_s
|
17
|
+
m = Manager.new
|
18
|
+
v = Visitor.new(m.configuration, m.repository, call: :ready?, look_for: :errors)
|
19
|
+
|
20
|
+
if v.ready?
|
21
|
+
say ANSI.green { I18n.t("commands.checkup.success") }
|
22
|
+
else
|
23
|
+
say ANSI.red { I18n.t("commands.checkup.fail") }
|
24
|
+
say ANSI.yellow { v.output }
|
49
25
|
end
|
50
26
|
end
|
51
|
-
end
|
52
|
-
|
53
|
-
command :update do |c|
|
54
|
-
c.syntax = 'git request update'
|
55
|
-
c.description = 'Обновить ветку на удаленном (origin) репозитории'
|
56
|
-
|
57
|
-
c.option '--branch STRING', String, 'Имя ветки, которую нужно обновить'
|
58
|
-
|
59
|
-
c.action do |args, options|
|
60
|
-
config = Abak::Flow::Config.current
|
61
|
-
request = Abak::Flow::PullRequest.new(config, :strategy => :update)
|
62
|
-
|
63
|
-
exit unless request.valid?
|
64
|
-
|
65
|
-
# Запушим текущую ветку на origin
|
66
|
-
branch = options.branch || request.current_branch
|
67
|
-
say "=> Обновляю ветку #{branch} на origin"
|
68
|
-
Hub::Runner.execute('push', 'origin', branch)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
command :feature do |c|
|
73
|
-
c.syntax = 'git request feature <Название задачи>'
|
74
|
-
c.description = 'Создать ветку для выполнения задачи. Лучше всего, если название задачи, будет ее номером из jira'
|
27
|
+
end # command :checkup
|
75
28
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
task = args.shift.to_s
|
29
|
+
command :compare do |c|
|
30
|
+
c.syntax = "git request compare"
|
31
|
+
c.description = "Сравнить свою ветку с веткой upstream репозитория"
|
80
32
|
|
81
|
-
|
82
|
-
|
83
|
-
exit
|
84
|
-
end
|
85
|
-
|
86
|
-
unless task =~ /^\w+\-\d{1,}$/
|
87
|
-
say '=> Вы приняли верное решение :)' && exit if agree("Лучше всего завести задачу с именем примерно такого формата PC-001, может попробуем заново? [y/n]:")
|
88
|
-
end
|
89
|
-
|
90
|
-
Hub::Runner.execute('flow', 'feature', 'start', task)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
command :hotfix do |c|
|
95
|
-
c.syntax = 'git request hotfix <Название задачи>'
|
96
|
-
c.description = 'Создать ветку для выполнения bugfix задачи. Лучше всего, если название задачи, будет ее номером из jira'
|
33
|
+
c.option "--base STRING", String, "Имя ветки с которой нужно сравнить"
|
34
|
+
c.option "--head STRING", String, "Имя ветки которую нужно сравнить"
|
97
35
|
|
98
36
|
c.action do |args, options|
|
99
|
-
|
37
|
+
# TODO : Вот это дубль, хочется его как-то более красиво
|
38
|
+
m = Manager.new
|
39
|
+
v = Visitor.new(m.configuration, m.repository, call: :ready?, look_for: :errors)
|
100
40
|
|
101
|
-
|
41
|
+
unless v.ready?
|
42
|
+
say ANSI.red { I18n.t("commands.compare.fail") }
|
43
|
+
say ANSI.yellow { v.output }
|
102
44
|
|
103
|
-
|
104
|
-
say color('Необходимо указать имя задачи, а лучше всего ее номер из jira', :error).to_s
|
105
|
-
exit
|
45
|
+
exit 1
|
106
46
|
end
|
107
47
|
|
108
|
-
|
109
|
-
|
48
|
+
current = m.git.current_branch
|
49
|
+
head = Branch.new(options.head || current, m)
|
50
|
+
base = Branch.new(options.base || head.pick_up_base_name, m)
|
51
|
+
|
52
|
+
if head.current?
|
53
|
+
say ANSI.white {
|
54
|
+
I18n.t("commands.compare.updating",
|
55
|
+
branch: ANSI.bold { head },
|
56
|
+
upstream: ANSI.bold { "#{m.repository.origin}" }) }
|
57
|
+
|
58
|
+
head.update
|
59
|
+
else
|
60
|
+
say ANSI.yellow {
|
61
|
+
I18n.t("commands.compare.diverging",
|
62
|
+
branch: ANSI.bold { head }) }
|
110
63
|
end
|
111
64
|
|
112
|
-
|
65
|
+
say ANSI.green { head.compare_link(base) }
|
113
66
|
end
|
114
|
-
end
|
67
|
+
end # command :compare
|
115
68
|
|
116
|
-
command :
|
117
|
-
c.syntax =
|
118
|
-
c.description =
|
69
|
+
command :publish do |c|
|
70
|
+
c.syntax = "git request publish"
|
71
|
+
c.description = "Оформить pull request в upstream репозиторий"
|
119
72
|
|
120
|
-
c.option
|
121
|
-
c.option
|
122
|
-
c.option
|
123
|
-
c.option '--origin', 'Удаляет ветку в удаленном репозитории (origin)'
|
73
|
+
c.option "--title STRING", String, "Заголовок для вашего pull request"
|
74
|
+
c.option "--body STRING", String, "Текст для вашего pull request"
|
75
|
+
c.option "--base STRING", String, "Имя ветки, в которую нужно принять изменения"
|
124
76
|
|
125
77
|
c.action do |args, options|
|
126
|
-
|
127
|
-
request = Abak::Flow::PullRequest.new(config, :strategy => :done)
|
128
|
-
branch = options.branch || request.current_branch
|
78
|
+
m = Manager.new
|
129
79
|
|
130
|
-
|
80
|
+
head = Branch.new(m.git.current_branch, m)
|
81
|
+
base = Branch.new(options.base || head.pick_up_base_name, m)
|
131
82
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
83
|
+
title = options.title || head.pick_up_title
|
84
|
+
body = [
|
85
|
+
options.body || (head.mappable? ? nil : I18n.t("commands.publish.nothing")),
|
86
|
+
head.pick_up_body
|
87
|
+
].compact * "\n\n"
|
136
88
|
|
137
|
-
|
138
|
-
|
139
|
-
if [:all, :origin].include?(type)
|
140
|
-
say '=> Вы приняли верное решение :)' && exit unless agree("#{warning} [y/n]:")
|
141
|
-
end
|
89
|
+
p = PullRequest.new({base: base, head: head, title: title, body: body}, m)
|
90
|
+
v = Visitor.new(m.configuration, m.repository, p, call: :ready?, look_for: :errors)
|
142
91
|
|
143
|
-
|
144
|
-
|
145
|
-
say
|
146
|
-
Hub::Runner.execute('push', request.origin_repo, ':' + branch)
|
147
|
-
end
|
92
|
+
unless v.ready?
|
93
|
+
say ANSI.red { I18n.t("commands.publish.fail") }
|
94
|
+
say ANSI.yellow { v.output }
|
148
95
|
|
149
|
-
|
150
|
-
say "=> Удаляю локальную ветку #{branch}"
|
151
|
-
Hub::Runner.execute('checkout', 'develop')
|
152
|
-
Hub::Runner.execute('branch', '-D', branch)
|
96
|
+
exit 1
|
153
97
|
end
|
154
|
-
end
|
155
|
-
end
|
156
98
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
99
|
+
say ANSI.white {
|
100
|
+
I18n.t("commands.publish.updating",
|
101
|
+
branch: ANSI.bold { head },
|
102
|
+
upstream: ANSI.bold { "#{m.repository.origin}" }) }
|
161
103
|
|
162
|
-
|
163
|
-
config = Abak::Flow::Config.current
|
164
|
-
request = Abak::Flow::PullRequest.new(config, :strategy => :readycheck)
|
165
|
-
|
166
|
-
if config.proxy?
|
167
|
-
message = "== В качестве прокси будет установлено значение #{config.proxy} =="
|
168
|
-
say color('=' * message.length, :info).to_s
|
169
|
-
say color(message, :info).to_s
|
170
|
-
say color('=' * message.length + "\n", :info).to_s
|
171
|
-
end
|
104
|
+
head.update
|
172
105
|
|
173
|
-
say
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
command :garbage do |c|
|
178
|
-
c.syntax = 'git request status'
|
179
|
-
c.description = 'Проверить пригодность удаленных (origin) веток и возможность их уничтожения (ветки master, develop игнорируются)'
|
106
|
+
say ANSI.white {
|
107
|
+
I18n.t("commands.publish.requesting",
|
108
|
+
branch: ANSI.bold { "#{m.repository.origin.owner}:#{head}" },
|
109
|
+
upstream: ANSI.bold { "#{m.repository.upstream.owner}:#{base}" }) }
|
180
110
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
say "=> Обновляю данные о репозитории upstream"
|
193
|
-
%w(origin upstream).each { |remote| Hub::Runner.execute('fetch', remote, '-p') }
|
194
|
-
|
195
|
-
say "=> Загружаю список веток для origin"
|
196
|
-
branches = github_client.branches(request.origin_project).
|
197
|
-
reject { |branch| %w(master develop).include? branch.name }
|
198
|
-
|
199
|
-
say "=> На origin найдено веток: #{branches.count}\n\n"
|
200
|
-
branches.each_with_index do |branch, index|
|
201
|
-
index += 1
|
202
|
-
|
203
|
-
base = Abak::Flow::PullRequest.branch_by_prefix branch.name.split('/').first
|
204
|
-
|
205
|
-
upstream_branch = %x(git branch -r --contain #{branch.commit.sha} | grep upstream/#{base} 2> /dev/null).strip
|
206
|
-
local_sha = %x(git show #{branch.name} --format=%H --no-notes 2> /dev/null | head -n 1).strip
|
207
|
-
|
208
|
-
statuses = {
|
209
|
-
unused: upstream_branch.empty?,
|
210
|
-
differ: !local_sha.empty? && local_sha != branch.commit.sha,
|
211
|
-
missing: local_sha.empty?
|
212
|
-
}
|
213
|
-
|
214
|
-
unless statuses.values.inject &:|
|
215
|
-
say color("#{index}) #{branch.name} → можно удалить", :debug).to_s
|
216
|
-
say "\n"
|
217
|
-
next
|
218
|
-
end
|
219
|
-
|
220
|
-
diagnoses = statuses.select { |_,bool| bool }.
|
221
|
-
map { |name,_| messages[name].first }.
|
222
|
-
map { |msg| "#{' ' * (index.to_s.length + 2)} ↪ #{msg}" }.
|
223
|
-
join("\n")
|
224
|
-
|
225
|
-
if statuses.select { |_,bool| bool }.keys == [:missing]
|
226
|
-
say color("#{index}) #{branch.name} → потенциально можно удалить", :warning).to_s
|
227
|
-
say "#{diagnoses}\n\n"
|
228
|
-
else
|
229
|
-
say "#{index}) #{branch.name}\n#{diagnoses}\n\n"
|
230
|
-
end
|
111
|
+
v = Visitor.new(p, call: :publish, look_for: :errors)
|
112
|
+
if v.ready?
|
113
|
+
say ANSI.green {
|
114
|
+
I18n.t("commands.publish.success",
|
115
|
+
link: ANSI.bold { p.link }) }
|
116
|
+
else
|
117
|
+
say ANSI.red { I18n.t("commands.publish.fail") }
|
118
|
+
say ANSI.yellow { v.output }
|
119
|
+
|
120
|
+
exit 3
|
231
121
|
end
|
232
122
|
end
|
233
|
-
end
|
234
|
-
end
|
123
|
+
end # command :publish
|
124
|
+
end
|
data/lib/abak-flow/version.rb
CHANGED