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.
@@ -0,0 +1,80 @@
1
+ # coding: utf-8
2
+ module Abak::Flow
3
+ module Commands
4
+ class Done
5
+ include ANSI::Code
6
+
7
+ def run(args, options)
8
+ Checkup.new.process(Array.new, ::Commander::Command::Options.new)
9
+
10
+ branch = Branch.new(Manager.git.current_branch)
11
+
12
+ if branch.develop? || branch.master?
13
+ say red {
14
+ Manager.locale.error(self,
15
+ 'branch.delete_now_allowed', branch: ANSI.bold { branch })
16
+ }
17
+
18
+ exit 105
19
+ end
20
+
21
+ delete_on_remote(branch)
22
+
23
+ # TODO : Быть может стоит вынести это в настройки
24
+ # и позволить выбирать, куда отправлять
25
+ # при удалении ветки, а по умолчанию использовать master
26
+ Manager.git.checkout(
27
+ branch.extract_base_name(if_undef: Branch::MASTER))
28
+
29
+ delete_on_local(branch)
30
+ end
31
+
32
+ private
33
+
34
+ def delete_on_remote(branch)
35
+ print white {
36
+ Manager.locale.word(self,
37
+ "deleting", branch: bold { branch },
38
+ upstream: bold { "#{Manager.repository.origin}" })
39
+ }
40
+
41
+ begin
42
+ branch.delete_on_remote
43
+ rescue
44
+ say_branch_missed(branch, "#{Manager.repository.origin}")
45
+ else
46
+ say_done
47
+ end
48
+ end
49
+
50
+ def delete_on_local(branch)
51
+ print white {
52
+ Manager.locale.word(self,
53
+ "deleting", branch: bold { branch },
54
+ upstream: bold { "working tree" })
55
+ }
56
+
57
+ begin
58
+ branch.delete_on_local
59
+ rescue
60
+ say_branch_missed(branch, "working tree")
61
+ else
62
+ say_done
63
+ end
64
+ end
65
+
66
+ def say_done
67
+ say green { " " << Manager.locale.word(self, "done") }
68
+ end
69
+
70
+ def say_branch_missed(branch, upstream)
71
+ puts
72
+ say yellow {
73
+ Manager.locale.error(self,
74
+ "branch.missed_on", branch: branch,
75
+ upstream: upstream)
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ module Abak::Flow
3
+ module Commands
4
+ class Publish
5
+ include ANSI::Code
6
+
7
+ def run(args, options)
8
+ Checkup.new.process(Array.new, ::Commander::Command::Options.new)
9
+
10
+ head = Branch.new(Manager.git.current_branch)
11
+ base = Branch.new(options.base || head.extract_base_name)
12
+
13
+ title = options.title || head.extract_title
14
+ body = options.body || head.extract_body
15
+
16
+ pr = PullRequest.new(base: base, head: head, title: title, body: body)
17
+ validate_request(pr)
18
+
19
+ say white {
20
+ Manager.locale.word(self, "updating",
21
+ branch: bold { head },
22
+ upstream: bold { "#{Manager.repository.origin}" })
23
+ }
24
+
25
+ head.update
26
+
27
+ say white {
28
+ Manager.locale.word(self, "publicating",
29
+ branch: bold { "#{Manager.repository.origin.owner}:#{head}" },
30
+ upstream: bold { "#{Manager.repository.origin}" })
31
+ }
32
+
33
+ publicate_request(pr)
34
+
35
+ say green { pr.link }
36
+ end
37
+
38
+ private
39
+
40
+ def validate_request(request)
41
+ inspector = Inspector.new(call_method: :valid?, collect_attribute: :errors)
42
+ inspector.examine(request).on_fail do |insp|
43
+ say red { Manager.locale.error(self) }
44
+ say yellow { insp.output }
45
+
46
+ exit 106
47
+ end
48
+ end
49
+
50
+ def publicate_request(request)
51
+ inspector = Inspector.new(call_method: :publish, collect_attribute: :errors)
52
+ inspector.examine(request).on_fail do |insp|
53
+ say red { Manager.locale.error(self, 'publication.failed') }
54
+ say yellow { insp.output }
55
+
56
+ exit 107
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -1,68 +1,91 @@
1
1
  # coding: utf-8
2
- require "i18n"
3
- require "ruler"
4
2
 
5
3
  module Abak::Flow
6
4
  class Configuration
7
- include Ruler
8
-
9
- OPTIONS = [:oauth_user, :oauth_token, :locale, :http_proxy].freeze
10
- LOCALE_FILES = File.join(File.dirname(__FILE__), "locales/*.{rb,yml}").freeze
5
+ # TODO: Add old oauth_login and oauth_token
6
+ AVAILABLE_OPTIONS = %w{login password locale http_proxy}.map(&:freeze)
7
+ GITCONFIG_PATTERN = /abak\-flow\.([\w\d\-\_]+)/.freeze
8
+
9
+ def initialize(options = nil)
10
+ @_errors = Hash.new
11
+ @options = {
12
+ login: nil,
13
+ password: nil,
14
+ locale: "en",
15
+ http_proxy: ENV["http_proxy"] || ENV["HTTP_PROXY"]
16
+ }
17
+
18
+ options.nil? ? define_options_from_gitconfig
19
+ : define_options_from_hash(options)
20
+
21
+ create_public_instance_methods
22
+ end
11
23
 
12
- attr_reader :errors
24
+ def rewrite(options)
25
+ define_options_from_hash(options)
26
+ write_to_gitconfig!
27
+ end
13
28
 
14
- def initialize(manager)
15
- @manager = manager
16
- @errors = []
29
+ def valid?
30
+ @_errors = Hash.new
31
+ @_errors["login"] = ['blank'] if @options[:login].to_s.empty?
32
+ @_errors["password"] = ['blank'] if @options[:password].to_s.empty?
17
33
 
18
- configure!
34
+ @_errors.empty?
19
35
  end
20
36
 
21
- def ready?
22
- @errors = []
37
+ def errors
38
+ ErrorsPresenter.new(self, @_errors)
39
+ end
23
40
 
24
- multi_ruleset do
25
- fact(:oauth_user_not_setup) { oauth_user.nil? }
26
- fact(:oauth_token_not_setup) { oauth_token.nil? }
41
+ private
27
42
 
28
- rule([:oauth_user_not_setup]) { @errors << I18n.t("configuration.errors.oauth_user_not_setup") }
29
- rule([:oauth_token_not_setup]) { @errors << I18n.t("configuration.errors.oauth_token_not_setup") }
43
+ def create_public_instance_methods
44
+ AVAILABLE_OPTIONS.each do |name|
45
+ self.class.send(:define_method, name, -> { @options[name.to_sym] })
30
46
  end
31
-
32
- @errors.empty? ? true : false
33
47
  end
34
48
 
35
- def display_name
36
- I18n.t("configuration.name")
37
- end
49
+ def write_to_gitconfig!
50
+ AVAILABLE_OPTIONS.each do |name|
51
+ value = @options[name.to_sym]
38
52
 
39
- private
40
- def configure!
41
- load_gitconfig
42
- setup_locale
53
+ next if value.nil? || value.empty?
54
+ Manager.git.lib.global_config_set("abak-flow.#{name}", value)
55
+ end
43
56
  end
44
57
 
45
- def setup_locale
46
- I18n.enforce_available_locales = false
47
- I18n.load_path += Dir.glob(LOCALE_FILES)
48
- I18n.locale = locale
58
+ def define_options_from_hash(hash)
59
+ hash.each do|name, value|
60
+ name = underscore(name.to_s)
61
+ next unless AVAILABLE_OPTIONS.include?(name)
62
+
63
+ @options[name.to_sym] = value
64
+ end
49
65
  end
50
66
 
51
- def load_gitconfig
52
- git_config = @manager.git.config.select { |k, _| k.include? "abak-flow." }
53
- .map { |k,v| [to_method_name(k), v] }
67
+ def define_options_from_gitconfig
68
+ read_git_config do |name, value|
69
+ name = underscore(name)
70
+ next unless AVAILABLE_OPTIONS.include?(name)
54
71
 
55
- config = Hash[git_config]
56
- config[:locale] ||= "en"
57
- config[:http_proxy] ||= ENV["http_proxy"] || ENV["HTTP_PROXY"]
72
+ @options[name.to_sym] = value
73
+ end
74
+ end
58
75
 
59
- OPTIONS.each do |name|
60
- define_singleton_method(name) { config[name] }
76
+ def read_git_config(&block)
77
+ Manager.git.config.each do |option, value|
78
+ matches = option.match(GITCONFIG_PATTERN)
79
+ block.call(underscore(matches[1]), value) if matches && matches[1]
61
80
  end
62
81
  end
63
82
 
64
- def to_method_name(name)
65
- name.sub(/abak-flow./, "").gsub(/\W/, "_").to_sym
83
+ def underscore(name)
84
+ name.tr("-", "_")
85
+ end
86
+
87
+ def dasherize(name)
88
+ name.tr("_", "-")
66
89
  end
67
- end
68
- end
90
+ end # class Configuration
91
+ end # module Abak::Flow
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ require "forwardable"
3
+
4
+ module Abak::Flow
5
+ class ErrorsPresenter
6
+ extend Forwardable
7
+
8
+ def_delegators :@errors, :empty?, :each, :each_with_index
9
+
10
+ def initialize(object, errors)
11
+ @object = object
12
+ @object_errors = errors
13
+ @errors = create_human_readable_errors
14
+ end
15
+
16
+ private
17
+
18
+ def create_human_readable_errors
19
+ @object_errors.map do |field, errors|
20
+ field_name = Manager.locale.field(@object, field)
21
+
22
+ errors = errors.map do |error|
23
+ error = {field: error, options: Hash.new} unless error.is_a?(Hash)
24
+ Manager.locale.error(@object, "#{field}.#{error[:field]}", error[:options])
25
+ end
26
+
27
+ "#{field_name} – #{errors * ", "}"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ require "ansi/code"
3
+
4
+ module Abak::Flow
5
+ class Inspector
6
+ def initialize(options = Hash.new)
7
+ @objects = Array.new
8
+ @call_method = options.fetch(:call_method)
9
+ @collect_attribute = options.fetch(:collect_attribute)
10
+ end
11
+
12
+ def examine(*args)
13
+ @objects = args
14
+ @fail = @objects.map { |x| x.send(@call_method) }.any? { |x| not !!x }
15
+
16
+ self
17
+ end
18
+
19
+ def output
20
+ @objects.map do |object|
21
+ next if object.send(@collect_attribute).empty?
22
+
23
+ info = ""
24
+ object.send(@collect_attribute).each_with_index do |inf, idx|
25
+ info << "\n #{idx + 1}. #{inf}"
26
+ end
27
+
28
+ "#{Manager.locale.name(object)}#{info}"
29
+ end * "\n"
30
+ end
31
+
32
+ def on_fail(&block)
33
+ block.call(self) if @fail
34
+ end
35
+ end # class Inspector
36
+ end # module Abak::Flow
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ require "i18n"
3
+
4
+ module Abak::Flow
5
+ class Locale
6
+ FILES = File.join(File.dirname(__FILE__), "locales/*.{rb,yml}").freeze
7
+
8
+ def initialize(locale)
9
+ I18n.enforce_available_locales = false
10
+ I18n.load_path += Dir.glob(FILES)
11
+ I18n.locale = locale
12
+ end
13
+
14
+ def name(object)
15
+ I18n.t("#{namenize object}.name")
16
+ end
17
+
18
+ def field(object, key)
19
+ I18n.t(key, scope: "#{namenize object}.fields")
20
+ end
21
+
22
+ def word(object, key, options = {})
23
+ I18n.t(key, options.merge(scope: "#{namenize object}.words"))
24
+ end
25
+
26
+ def error(object, key = nil, options = {})
27
+ key.nil? ? I18n.t("#{namenize object}.fail", options)
28
+ : I18n.t(key, options.merge(scope: "#{namenize object}.errors"))
29
+ end
30
+
31
+ def success(object, *args)
32
+ options = args.last.is_a?(Hash) ? args.pop : {}
33
+ key = args[0]
34
+
35
+ key.nil? ? I18n.t("#{namenize object}.success", options)
36
+ : I18n.t(key, options.merge(scope: "#{namenize object}.success"))
37
+ end
38
+
39
+ private
40
+
41
+ def namenize(object)
42
+ object.class.name.downcase.gsub(/\:\:/, ".")
43
+ end
44
+ end # class Locale
45
+ end # module Abak::Flow
@@ -1,44 +1,82 @@
1
1
  en:
2
- configuration:
3
- name: Configuration
4
- errors:
5
- oauth_user_not_setup: Options oauth_user not setted
6
- oauth_token_not_setup: Options oauth_token not setted
7
- recommendations: "Check [abak-flow] section in ~/.gitcofig file"
2
+ abak:
3
+ flow:
4
+ commands:
5
+ checkup:
6
+ fail: You are not prepared!
7
+ success: Congratulations, you are ready to ROCK :)
8
8
 
9
- repository:
10
- name: Repository
11
- errors:
12
- origin_not_setup: Repository with name 'origin' not found
13
- upstream_not_setup: Repository with name 'upstream' not found
14
- recommendations: "Check .git/cofig file"
9
+ compare:
10
+ words:
11
+ updating: "Updating %{branch} → %{upstream}"
12
+ diverging: "Branches may diverging\nAdvice: switch to branch '%{branch}' and retry operation"
15
13
 
16
- pull_request:
17
- name: Pull Request
18
- errors:
19
- head_is_incorrect: Something wrong with 'head' branch
20
- base_is_incorrect: Something wrong with 'base' branch
21
- title_is_incorrect: Title is not specified
22
- body_is_incorrect: Message body is not specified
14
+ configure:
15
+ fail: Something goes wrong!
16
+ success: Configuration generated and saved ↓
17
+ words:
18
+ email: Email
19
+ password: Password
20
+ locale: Locale
21
+ http_proxy: HTTP proxy
22
+ sms_otp: SMS OTP
23
+ configuring: Configuring
24
+ errors:
25
+ execution_failed: Github api request failed
26
+ empty_response: Github service respond with empty response body
23
27
 
24
- commands:
25
- default:
26
- fail: Something goes wrong!
27
- checkup:
28
- fail: You are not prepared!
29
- success: "Congratulations, you are ready to ROCK :)"
30
- compare:
31
- fail: Something goes wrong!
32
- updating: "Updating %{branch} → %{upstream}"
33
- diverging: "Branches may diverging\nAdvice: switch to branch '%{branch}' and retry operation"
34
- publish:
35
- fail: Something goes wrong!
36
- success: "Pull request successfuly created %{link}"
37
- requesting: "Creating pull request %{branch} → %{upstream}"
38
- updating: "Updating %{branch} → %{upstream}"
39
- nothing: I have nothing to say ...
40
- done:
41
- fail: Something goes wrong!
42
- deleting: "Deleting %{branch} in %{upstream}"
43
- errors:
44
- branch_is_incorrect: "You can't delete %{branch}"
28
+ done:
29
+ words:
30
+ deleting: Deleting %{branch} in %{upstream}
31
+ done:
32
+ errors:
33
+ branch:
34
+ delete_now_allowed: You can't delete %{branch}
35
+ missed_on: Branch %{branch} doesn`t exists on %{upstream}
36
+
37
+ publish:
38
+ fail: Goddamned, not again!
39
+ words:
40
+ updating: Updating %{branch} %{upstream}
41
+ publicating: Creating pull request %{branch} → %{upstream}
42
+ errors:
43
+ publication:
44
+ failed: Some errors occurs while request publicating
45
+
46
+ configuration:
47
+ name: Configuration
48
+ fields:
49
+ login: Login
50
+ password: Password
51
+ errors:
52
+ login:
53
+ blank: Can't be blank
54
+ password:
55
+ blank: Can't be blank
56
+
57
+ repository:
58
+ name: Repository
59
+ fields:
60
+ origin: Origin
61
+ upstream: Upstream
62
+ errors:
63
+ origin:
64
+ not_set: Git remote 'origin' not set
65
+ upstream:
66
+ not_set: Git remote 'upstream' not set
67
+
68
+ pullrequest:
69
+ name: Pull Request
70
+ fields:
71
+ title: Title message
72
+ body: Body message
73
+ head: Head branch
74
+ base: Base branch
75
+ exception: Exception
76
+ errors:
77
+ head:
78
+ invalid: Branch name is invalid
79
+ base:
80
+ invalid: Branch name is invalid
81
+ exception:
82
+ message: "%{backtrace}"