abak-flow 1.0.10 → 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 +15 -0
- data/README.md +49 -34
- data/abak-flow.gemspec +1 -3
- data/lib/abak-flow.rb +18 -14
- data/lib/abak-flow/branch.rb +9 -10
- data/lib/abak-flow/commands/checkup.rb +11 -14
- data/lib/abak-flow/commands/compare.rb +14 -24
- data/lib/abak-flow/commands/configure.rb +108 -0
- data/lib/abak-flow/commands/done.rb +80 -0
- data/lib/abak-flow/commands/publish.rb +62 -0
- data/lib/abak-flow/configuration.rb +66 -43
- data/lib/abak-flow/errors_presenter.rb +31 -0
- data/lib/abak-flow/inspector.rb +36 -0
- data/lib/abak-flow/locale.rb +45 -0
- data/lib/abak-flow/locales/en.yml +78 -40
- data/lib/abak-flow/locales/ru.yml +78 -40
- data/lib/abak-flow/manager.rb +28 -8
- data/lib/abak-flow/pull_request.rb +21 -30
- data/lib/abak-flow/repository.rb +17 -32
- data/lib/abak-flow/request.rb +18 -80
- data/lib/abak-flow/version.rb +1 -1
- data/spec/lib/abak-flow/commands/checkup_spec.rb +7 -7
- data/spec/lib/abak-flow/commands/compare_spec.rb +9 -8
- metadata +41 -76
- data/lib/abak-flow/visitor.rb +0 -63
@@ -1,44 +1,82 @@
|
|
1
1
|
ru:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
abak:
|
3
|
+
flow:
|
4
|
+
commands:
|
5
|
+
checkup:
|
6
|
+
fail: Вы не готовы!
|
7
|
+
success: Поздравляем, вы готовы чтобы жечь :)
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
upstream_not_setup: Репозиторий с именем 'upstream' не найден
|
14
|
-
recommendations: Проверьте файл .git/cofig
|
9
|
+
compare:
|
10
|
+
words:
|
11
|
+
updating: "Обновляю %{branch} → %{upstream}"
|
12
|
+
diverging: "Ветки могут расходиться\nСовет: переключитесь в ветку '%{branch}' и повторите команду"
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
configure:
|
15
|
+
fail: Что-то пошло не так!
|
16
|
+
success: Конфигурация сгененирована и сохранена ↓
|
17
|
+
words:
|
18
|
+
email: Почта
|
19
|
+
password: Пароль
|
20
|
+
locale: Язык
|
21
|
+
http_proxy: HTTP прокси
|
22
|
+
sms_otp: SMS пароль
|
23
|
+
configuring: Настраиваю
|
24
|
+
errors:
|
25
|
+
execution_failed: Ошибка при запрос к апи Github
|
26
|
+
empty_response: Почему-то ответ от апи Github был пустотой
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
28
|
+
done:
|
29
|
+
words:
|
30
|
+
deleting: Удаляю %{branch} в %{upstream}
|
31
|
+
done: √
|
32
|
+
errors:
|
33
|
+
branch:
|
34
|
+
delete_now_allowed: Вы не можете удалить %{branch}
|
35
|
+
missed_on: Ветка %{branch} не существует на %{upstream}
|
36
|
+
|
37
|
+
publish:
|
38
|
+
fail: Черт побери, только не ошибка!
|
39
|
+
words:
|
40
|
+
updating: Обновляю %{branch} → %{upstream}
|
41
|
+
publicating: Создаю пул реквест %{branch} → %{upstream}
|
42
|
+
errors:
|
43
|
+
publication:
|
44
|
+
failed: Во время публикации произошли ошибки
|
45
|
+
|
46
|
+
configuration:
|
47
|
+
name: Конфигурация
|
48
|
+
fields:
|
49
|
+
login: Логин
|
50
|
+
password: Пароль
|
51
|
+
errors:
|
52
|
+
login:
|
53
|
+
blank: Не может быть пустым
|
54
|
+
password:
|
55
|
+
blank: Не может быть пустым
|
56
|
+
|
57
|
+
repository:
|
58
|
+
name: Репозиторий
|
59
|
+
fields:
|
60
|
+
origin: Origin
|
61
|
+
upstream: Upstream
|
62
|
+
errors:
|
63
|
+
origin:
|
64
|
+
not_set: Удаленный репозиторий 'origin' не объявлен
|
65
|
+
upstream:
|
66
|
+
not_set: Удаленный репозиторий 'upstream' не объявлен
|
67
|
+
|
68
|
+
pullrequest:
|
69
|
+
name: Пул реквест
|
70
|
+
fields:
|
71
|
+
title: Заголовок
|
72
|
+
body: Описание
|
73
|
+
head: Ветка Head
|
74
|
+
base: Ветка Base
|
75
|
+
exception: Исключение
|
76
|
+
errors:
|
77
|
+
head:
|
78
|
+
invalid: Название ветки неверно
|
79
|
+
base:
|
80
|
+
invalid: Название ветки неверно
|
81
|
+
exception:
|
82
|
+
message: "%{backtrace}"
|
data/lib/abak-flow/manager.rb
CHANGED
@@ -7,23 +7,40 @@ module Abak::Flow
|
|
7
7
|
class Manager
|
8
8
|
include Singleton
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
class << self
|
11
|
+
def git
|
12
|
+
instance.git
|
13
|
+
end
|
14
|
+
|
15
|
+
def github
|
16
|
+
instance.github
|
17
|
+
end
|
18
|
+
|
19
|
+
def locale
|
20
|
+
instance.locale
|
21
|
+
end
|
22
|
+
|
23
|
+
def configuration
|
24
|
+
instance.configuration
|
25
|
+
end
|
26
|
+
|
27
|
+
def repository
|
28
|
+
instance.repository
|
29
|
+
end
|
14
30
|
end
|
15
31
|
|
16
32
|
def configuration
|
17
|
-
@configuration ||= Configuration.new
|
33
|
+
@configuration ||= Configuration.new
|
18
34
|
end
|
19
35
|
|
20
36
|
def repository
|
21
|
-
@repository ||= Repository.new
|
37
|
+
@repository ||= Repository.new
|
22
38
|
end
|
23
39
|
|
24
40
|
def github
|
25
|
-
@github ||= Octokit::Client.new(
|
26
|
-
|
41
|
+
@github ||= Octokit::Client.new(
|
42
|
+
login: configuration.login,
|
43
|
+
password: configuration.password,
|
27
44
|
proxy: configuration.http_proxy)
|
28
45
|
end
|
29
46
|
|
@@ -31,5 +48,8 @@ module Abak::Flow
|
|
31
48
|
@git ||= Git.open(".")
|
32
49
|
end
|
33
50
|
|
51
|
+
def locale
|
52
|
+
@locale ||= Locale.new(configuration.locale)
|
53
|
+
end
|
34
54
|
end
|
35
55
|
end
|
@@ -1,15 +1,10 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require "ruler"
|
3
|
-
|
4
2
|
module Abak::Flow
|
5
3
|
class PullRequest
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :errors, :link
|
4
|
+
attr_reader :link
|
9
5
|
|
10
|
-
def initialize(params
|
11
|
-
@
|
12
|
-
@errors = []
|
6
|
+
def initialize(params)
|
7
|
+
@_errors = Hash.new
|
13
8
|
|
14
9
|
@head = params.fetch(:head)
|
15
10
|
@base = params.fetch(:base)
|
@@ -17,42 +12,38 @@ module Abak::Flow
|
|
17
12
|
@body = params.fetch(:body)
|
18
13
|
end
|
19
14
|
|
20
|
-
def
|
21
|
-
@
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
fact(:base_is_incorrect) { not @base.valid? }
|
26
|
-
fact(:title_is_incorrect) { @title.empty? }
|
27
|
-
fact(:body_is_incorrect) { @head.tracker_task? ? @body.empty? : false }
|
15
|
+
def valid?
|
16
|
+
@_errors = Hash.new
|
17
|
+
@_errors["head"] = ["invalid"] unless @head.valid?
|
18
|
+
@_errors["base"] = ["invalid"] unless @base.valid?
|
19
|
+
@_errors["title"] = ["blank"] if @title.empty?
|
28
20
|
|
29
|
-
|
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") }
|
33
|
-
end
|
34
|
-
|
35
|
-
@errors.empty? ? true : false
|
21
|
+
@_errors.empty?
|
36
22
|
end
|
37
23
|
|
38
|
-
def
|
39
|
-
|
24
|
+
def errors
|
25
|
+
ErrorsPresenter.new(self, @_errors)
|
40
26
|
end
|
41
27
|
|
42
28
|
def publish
|
29
|
+
@_errors = Hash.new
|
30
|
+
|
43
31
|
begin
|
44
|
-
head_with_repo = [
|
32
|
+
head_with_repo = [Manager.repository.origin.owner, @head] * ':'
|
45
33
|
|
46
|
-
response =
|
47
|
-
|
34
|
+
response = Manager.github.create_pull_request(
|
35
|
+
Manager.repository.upstream.to_s, @base.to_s, head_with_repo, @title, @body)
|
48
36
|
|
49
|
-
@link = response
|
37
|
+
@link = response[:html_url]
|
50
38
|
|
51
39
|
true
|
52
40
|
rescue Exception => exception
|
53
41
|
backtrace = exception.backtrace[0...10] * "\n"
|
54
42
|
|
55
|
-
@
|
43
|
+
@_errors["exception"] = [{
|
44
|
+
field: "message",
|
45
|
+
options: {backtrace: "#{exception.message}\n\n#{backtrace}"}
|
46
|
+
}]
|
56
47
|
|
57
48
|
false
|
58
49
|
end
|
data/lib/abak-flow/repository.rb
CHANGED
@@ -1,64 +1,49 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require "i18n"
|
3
|
-
require "ruler"
|
4
|
-
require "forwardable"
|
5
2
|
|
6
3
|
module Abak::Flow
|
7
4
|
class Repository
|
8
|
-
include Ruler
|
9
5
|
extend Forwardable
|
10
6
|
|
11
|
-
REMOTES =
|
7
|
+
REMOTES = %w{origin upstream}.map(&:freeze)
|
12
8
|
|
13
|
-
|
9
|
+
def initialize
|
10
|
+
@_errors = Hash.new
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
def initialize(manager)
|
18
|
-
@manager = manager
|
19
|
-
@errors = []
|
20
|
-
|
21
|
-
configure!
|
12
|
+
create_public_instance_methods
|
22
13
|
end
|
23
14
|
|
24
|
-
def
|
25
|
-
@
|
15
|
+
def valid?
|
16
|
+
@_errors = Hash.new
|
17
|
+
@_errors["origin"] = ['not_set'] if origin.nil?
|
18
|
+
@_errors["upstream"] = ['not_set'] if upstream.nil?
|
26
19
|
|
27
|
-
|
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
|
20
|
+
@_errors.empty?
|
36
21
|
end
|
37
22
|
|
38
|
-
def
|
39
|
-
|
23
|
+
def errors
|
24
|
+
ErrorsPresenter.new(self, @_errors)
|
40
25
|
end
|
41
26
|
|
42
27
|
private
|
43
|
-
|
28
|
+
|
29
|
+
def create_public_instance_methods
|
44
30
|
remotes = Hash[fetch_remotes_from_git]
|
31
|
+
|
45
32
|
REMOTES.each do |name|
|
46
33
|
define_singleton_method(name) { remotes[name] }
|
47
34
|
end
|
48
35
|
end
|
49
36
|
|
50
37
|
def fetch_remotes_from_git
|
51
|
-
git.remotes.
|
52
|
-
|
53
|
-
map { |remote| create_remote(remote) }.
|
54
|
-
compact
|
38
|
+
Manager.git.remotes.select { |remote| REMOTES.include?(remote.name) }
|
39
|
+
.map { |remote| create_remote(remote) }.compact
|
55
40
|
end
|
56
41
|
|
57
42
|
def create_remote(remote)
|
58
43
|
matches = /.+.github\.com[\:|\/](?<owner>.+)\/(?<project>.+).git/.match(remote.url)
|
59
44
|
|
60
45
|
if !matches.nil? && matches.captures.length == 2
|
61
|
-
[remote.name
|
46
|
+
[remote.name, Remote.new(matches[:owner], matches[:project], remote)]
|
62
47
|
end
|
63
48
|
end
|
64
49
|
|
data/lib/abak-flow/request.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
require "commander/import"
|
3
|
-
require "ansi/code"
|
4
3
|
|
4
|
+
# TODO : I18n
|
5
|
+
# TODO : Переименовать в CLI
|
5
6
|
module Abak::Flow
|
6
7
|
program :name, "Утилита для оформления pull request на github.com"
|
7
8
|
program :version, Abak::Flow::VERSION
|
@@ -25,89 +26,26 @@ module Abak::Flow
|
|
25
26
|
cmd.action Commands::Compare, :run
|
26
27
|
end # command :compare
|
27
28
|
|
28
|
-
command :
|
29
|
-
|
30
|
-
|
29
|
+
command :configure do |cmd|
|
30
|
+
cmd.syntax = "git request setup"
|
31
|
+
cmd.description = "Настроить приложение abak-flow для работы с github"
|
32
|
+
cmd.action Commands::Configure, :run
|
33
|
+
end # command :configure
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
command :publish do |cmd|
|
36
|
+
cmd.syntax = "git request publish"
|
37
|
+
cmd.description = "Оформить pull request в upstream репозиторий"
|
35
38
|
|
36
|
-
|
37
|
-
|
39
|
+
cmd.option "--title STRING", String, "Заголовок для вашего pull request"
|
40
|
+
cmd.option "--body STRING", String, "Текст для вашего pull request"
|
41
|
+
cmd.option "--base STRING", String, "Имя ветки, в которую нужно принять изменения"
|
38
42
|
|
39
|
-
|
40
|
-
base = Branch.new(options.base || head.extract_base_name)
|
41
|
-
|
42
|
-
title = options.title || head.extract_title
|
43
|
-
body = options.body || head.extract_body
|
44
|
-
|
45
|
-
p = PullRequest.new({base: base, head: head, title: title, body: body}, m)
|
46
|
-
|
47
|
-
v = Visitor.new(m.configuration, m.repository, p, call: :ready?, inspect: :errors)
|
48
|
-
v.exit_on_fail(:publish, 1)
|
49
|
-
|
50
|
-
say ANSI.white {
|
51
|
-
I18n.t("commands.publish.updating",
|
52
|
-
branch: ANSI.bold { head },
|
53
|
-
upstream: ANSI.bold { "#{m.repository.origin}" }) }
|
54
|
-
|
55
|
-
head.update
|
56
|
-
|
57
|
-
say ANSI.white {
|
58
|
-
I18n.t("commands.publish.requesting",
|
59
|
-
branch: ANSI.bold { "#{m.repository.origin.owner}:#{head}" },
|
60
|
-
upstream: ANSI.bold { "#{m.repository.upstream.owner}:#{base}" }) }
|
61
|
-
|
62
|
-
v = Visitor.new(p, call: :publish, inspect: :errors)
|
63
|
-
v.exit_on_fail(:publish, 2)
|
64
|
-
|
65
|
-
say ANSI.green { I18n.t("commands.publish.success", link: p.link) }
|
66
|
-
end
|
43
|
+
cmd.action Commands::Publish, :run
|
67
44
|
end # command :publish
|
68
45
|
|
69
|
-
command :done do |
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
c.action do |args, options|
|
74
|
-
m = Manager.instance
|
75
|
-
v = Visitor.new(m.configuration, m.repository, call: :ready?, inspect: :errors)
|
76
|
-
v.exit_on_fail(:done, 1)
|
77
|
-
|
78
|
-
branch = Branch.new(m.git.current_branch)
|
79
|
-
|
80
|
-
if branch.develop? || branch.master?
|
81
|
-
say ANSI.red {
|
82
|
-
I18n.t("commands.done.errors.branch_is_incorrect",
|
83
|
-
branch: ANSI.bold { branch }) }
|
84
|
-
exit 2
|
85
|
-
end
|
86
|
-
|
87
|
-
say ANSI.white {
|
88
|
-
I18n.t("commands.done.deleting",
|
89
|
-
branch: ANSI.bold { branch },
|
90
|
-
upstream: ANSI.bold { "#{m.repository.origin}" }) }
|
91
|
-
|
92
|
-
# FIXME : Исправить молчаливую ситуацию
|
93
|
-
# Возможно стоит предупредить о ее отсутствии
|
94
|
-
branch.delete_on_remote rescue nil
|
95
|
-
|
96
|
-
say ANSI.white {
|
97
|
-
I18n.t("commands.done.deleting",
|
98
|
-
branch: ANSI.bold { branch },
|
99
|
-
upstream: ANSI.bold { "working tree" }) }
|
100
|
-
|
101
|
-
# TODO : Добавить проверку, что ветка,
|
102
|
-
# в которую надо попасть (master/develop)
|
103
|
-
# существует
|
104
|
-
|
105
|
-
# TODO : Быть может стоит вынести это в настройки
|
106
|
-
# и позволить выбирать, куда отправлять
|
107
|
-
# при удалении ветки, а по умолчанию использовать master
|
108
|
-
m.git.checkout(
|
109
|
-
branch.extract_base_name(if_undef: Branch::DEVELOPMENT))
|
110
|
-
branch.delete_on_local
|
111
|
-
end
|
46
|
+
command :done do |cmd|
|
47
|
+
cmd.syntax = "git request done"
|
48
|
+
cmd.description = "Удалить ветки (local и origin) в которых велась работа"
|
49
|
+
cmd.action Commands::Done, :run
|
112
50
|
end # command :done
|
113
51
|
end
|