nabokov 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitattributes +1 -0
- data/.gitignore +43 -0
- data/.rspec +2 -0
- data/.rubocop.yml +113 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +16 -0
- data/Rakefile +22 -0
- data/bin/nabokov +5 -0
- data/lib/nabokov/commands/runner.rb +22 -0
- data/lib/nabokov/commands/setup.rb +75 -0
- data/lib/nabokov/commands/syncers/localizations_repo_syncer.rb +101 -0
- data/lib/nabokov/commands/syncers/project_syncer.rb +106 -0
- data/lib/nabokov/commands/syncers/syncer.rb +68 -0
- data/lib/nabokov/core/file_manager.rb +36 -0
- data/lib/nabokov/core/nabokovfile.rb +66 -0
- data/lib/nabokov/core/nabokovfile_content_validator.rb +51 -0
- data/lib/nabokov/core/nabokovfile_keys.rb +34 -0
- data/lib/nabokov/git/git_repo.rb +137 -0
- data/lib/nabokov/helpers/informator.rb +83 -0
- data/lib/nabokov/helpers/merger.rb +86 -0
- data/lib/nabokov/models/strings_file.rb +7 -0
- data/lib/nabokov/version.rb +8 -0
- data/lib/nabokov.rb +14 -0
- data/nabokov.gemspec +31 -0
- data/spec/fixtures/.DS_Store +0 -0
- data/spec/fixtures/README.md +1 -0
- data/spec/fixtures/de.strings +1 -0
- data/spec/fixtures/en.strings +1 -0
- data/spec/fixtures/nabokovfile_example.yaml +9 -0
- data/spec/fixtures/nabokovfile_example_invalid.yaml +2 -0
- data/spec/fixtures/nabokovfile_example_without_master_branch.yaml +8 -0
- data/spec/fixtures/test_git_setup/existed_pre_commit_file +0 -0
- data/spec/fixtures/test_git_setup/existed_pre_commit_file_alias +0 -0
- data/spec/fixtures/test_git_setup/not_executable_pre_commit_file +0 -0
- data/spec/fixtures/test_localizations_repo_syncer/localizations_repo_fixtures/README.md +1 -0
- data/spec/fixtures/test_localizations_repo_syncer/nabokovfile.yaml +8 -0
- data/spec/fixtures/test_project_syncer/localizations_repo_fixtures/de.strings +2 -0
- data/spec/fixtures/test_project_syncer/localizations_repo_fixtures/en.strings +2 -0
- data/spec/fixtures/test_project_syncer/project_repo_fixtures/de.strings +2 -0
- data/spec/fixtures/test_project_syncer/project_repo_fixtures/en.strings +2 -0
- data/spec/fixtures/test_project_syncer/project_repo_fixtures/nabokovfile.yaml +9 -0
- data/spec/lib/nabokov/commands/localizations_repo_syncer_spec.rb +137 -0
- data/spec/lib/nabokov/commands/project_syncer_spec.rb +61 -0
- data/spec/lib/nabokov/commands/runner_spec.rb +7 -0
- data/spec/lib/nabokov/commands/setup_spec.rb +101 -0
- data/spec/lib/nabokov/commands/syncer_spec.rb +23 -0
- data/spec/lib/nabokov/core/file_manager_spec.rb +115 -0
- data/spec/lib/nabokov/core/nabokovfile_content_validator_spec.rb +155 -0
- data/spec/lib/nabokov/core/nabokovfile_keyes_spec.rb +31 -0
- data/spec/lib/nabokov/core/nabokovfile_spec.rb +53 -0
- data/spec/lib/nabokov/git/git_repo_spec.rb +670 -0
- data/spec/lib/nabokov/helpers/informator_spec.rb +49 -0
- data/spec/lib/nabokov/helpers/merger_spec.rb +114 -0
- data/spec/lib/nabokov/models/strings_file_spec.rb +7 -0
- data/spec/spec_helper.rb +11 -0
- metadata +238 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "uri"
|
3
|
+
require "nabokov/core/nabokovfile_keys"
|
4
|
+
require "nabokov/core/nabokovfile_content_validator"
|
5
|
+
|
6
|
+
module Nabokov
|
7
|
+
# Class represents the nabokovfile with the settings for nabokov
|
8
|
+
class Nabokovfile
|
9
|
+
# @return [String] The localizations repo url string
|
10
|
+
attr_accessor :localizations_repo_url
|
11
|
+
# @return [String] The localizations repo master branch
|
12
|
+
attr_accessor :localizations_repo_master_branch
|
13
|
+
# @return [String] The localizations repo local path
|
14
|
+
attr_accessor :localizations_repo_local_path
|
15
|
+
# @return [Hash] The Hash with key as localization name and value as repspected localization file path
|
16
|
+
attr_accessor :project_localization_file_paths
|
17
|
+
# @return [String] The project repo local path
|
18
|
+
attr_accessor :project_local_path
|
19
|
+
|
20
|
+
def initialize(path)
|
21
|
+
raise "Path is a required parameter" if path.nil?
|
22
|
+
raise "Couldn't find nabokov file at '#{path}'" unless File.exist?(path)
|
23
|
+
nabokovfile = File.read(path)
|
24
|
+
yaml_data = read_data_from_yaml_file(nabokovfile, path)
|
25
|
+
validate_content(yaml_data)
|
26
|
+
read_content(yaml_data)
|
27
|
+
end
|
28
|
+
|
29
|
+
def localizations_repo_local_path
|
30
|
+
return @localizations_repo_local_path unless @localizations_repo_local_path.nil?
|
31
|
+
@localizations_repo_local_path ||= ""
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def read_data_from_yaml_file(yaml_file, path)
|
37
|
+
YAML.load(yaml_file)
|
38
|
+
rescue Psych::SyntaxError
|
39
|
+
raise "File at '#{path}' doesn't have a legit YAML syntax"
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_content(content_hash)
|
43
|
+
validator = NabokovfileContentValidator.new(content_hash)
|
44
|
+
validator.validate
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_content(content_hash)
|
48
|
+
localizations_repo = content_hash[NabokovfileKeyes.localizations_repo]
|
49
|
+
self.localizations_repo_url = localizations_repo[NabokovfileKeyes.localizations_repo_url]
|
50
|
+
self.localizations_repo_master_branch = localizations_repo[NabokovfileKeyes.localizations_repo_master_branch].nil? ? "master" : localizations_repo[NabokovfileKeyes.localizations_repo_master_branch]
|
51
|
+
project_repo = content_hash[NabokovfileKeyes.project_repo]
|
52
|
+
self.project_localization_file_paths = project_repo[NabokovfileKeyes.project_localization_file_paths]
|
53
|
+
self.project_local_path = project_repo[NabokovfileKeyes.project_local_path]
|
54
|
+
self.localizations_repo_local_path = build_localization_local_path
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_localization_local_path
|
58
|
+
repo_url_path = URI(self.localizations_repo_url).path.to_s
|
59
|
+
home_dir = Dir.home.to_s
|
60
|
+
repo_url_name_without_extension = File.basename(repo_url_path, File.extname(repo_url_path)).downcase
|
61
|
+
repo_url_organization = File.dirname(repo_url_path).downcase
|
62
|
+
nabokov_dir_name = "/.nabokov"
|
63
|
+
home_dir + nabokov_dir_name + repo_url_organization + "/" + repo_url_name_without_extension
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "nabokov/core/nabokovfile_keys"
|
3
|
+
|
4
|
+
module Nabokov
|
5
|
+
# This class is responsible for nabokovfile content validation
|
6
|
+
# The validation rules are for localizations_repo and project_repo settings
|
7
|
+
class NabokovfileContentValidator
|
8
|
+
attr_accessor :nabokovfile_hash
|
9
|
+
|
10
|
+
def initialize(nabokovfile_hash)
|
11
|
+
self.nabokovfile_hash = nabokovfile_hash
|
12
|
+
end
|
13
|
+
|
14
|
+
# Performs validation
|
15
|
+
# First rule: localizations_repo should be the type of Hash
|
16
|
+
# localizations_repo_url should be valid URL with secure https scheme
|
17
|
+
# Second rule: project_repo should be the type of Hash
|
18
|
+
# project localizations_key should be the of Hash
|
19
|
+
# project_localization_file_paths should point to existed files
|
20
|
+
# project_local_path should point to valid folder
|
21
|
+
def validate
|
22
|
+
validate_localizations_repo
|
23
|
+
validate_project_repo
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def validate_localizations_repo
|
29
|
+
localizations_repo = self.nabokovfile_hash[NabokovfileKeyes.localizations_repo]
|
30
|
+
raise "Localizations repo must be a type of Hash" unless localizations_repo.kind_of?(Hash)
|
31
|
+
|
32
|
+
url = localizations_repo[NabokovfileKeyes.localizations_repo_url]
|
33
|
+
raise "'#{url}' is not a valid URL" unless url =~ URI.regexp
|
34
|
+
raise "Please use 'https://...' instead of '#{url}' only supports encrypted requests" unless url.start_with?("https://")
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_project_repo
|
38
|
+
project_repo = self.nabokovfile_hash[NabokovfileKeyes.project_repo]
|
39
|
+
raise "Project repo must be a type of Hash" unless project_repo.kind_of?(Hash)
|
40
|
+
|
41
|
+
localizations_key = NabokovfileKeyes.project_localization_file_paths
|
42
|
+
localizations = project_repo[localizations_key]
|
43
|
+
raise "Localizations must be a type of Hash" unless localizations.kind_of?(Hash)
|
44
|
+
localizations.each_value { |path| raise "Couldn't find strings file at '#{path}'" unless File.exist?(path) }
|
45
|
+
|
46
|
+
project_local_path_key = NabokovfileKeyes.project_local_path
|
47
|
+
project_local_path = project_repo[project_local_path_key]
|
48
|
+
raise "Project repo local path must be presented" if project_local_path.nil?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Nabokov
|
2
|
+
# Class contains the named constants for nabokovfile keyes
|
3
|
+
class NabokovfileKeyes
|
4
|
+
# @return [String] The key to get the localizations repo settings
|
5
|
+
def self.localizations_repo
|
6
|
+
return "localizations_repo"
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [String] The key to get the localizations remote URL string
|
10
|
+
def self.localizations_repo_url
|
11
|
+
return "url"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [String] The key to get the master branch of the localizations repo
|
15
|
+
def self.localizations_repo_master_branch
|
16
|
+
return "master_branch"
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [String] The key to get the project repo settings
|
20
|
+
def self.project_repo
|
21
|
+
return "project_repo"
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] The key to get the (localization_code => localization_file_path) hash
|
25
|
+
def self.project_localization_file_paths
|
26
|
+
return "localizations"
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [String] The key to get the project's local path
|
30
|
+
def self.project_local_path
|
31
|
+
return "local_path"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "git"
|
2
|
+
require "uri"
|
3
|
+
require "securerandom"
|
4
|
+
require "pathname"
|
5
|
+
|
6
|
+
module Nabokov
|
7
|
+
# This class is basically the wrapper aroung the ruby-git gem
|
8
|
+
# Note: the ruby gem is taken not from gem spec repo, but from https://github.com/Antondomashnev/ruby-git
|
9
|
+
class GitRepo
|
10
|
+
# @return [String] Repo's remote URL, could be nil
|
11
|
+
attr_accessor :remote_url
|
12
|
+
# @return [String] Local path to the repo
|
13
|
+
attr_accessor :local_path
|
14
|
+
# @return [Git::Base] Underlying git repo
|
15
|
+
attr_reader :git_repo
|
16
|
+
|
17
|
+
def initialize(local_path, remote_url = nil, git_repo = nil)
|
18
|
+
raise "local_path is a required parameter" if local_path.nil?
|
19
|
+
expanded_local_path = File.expand_path(local_path)
|
20
|
+
@local_pathname = Pathname.new(expanded_local_path)
|
21
|
+
@git_repo = git_repo
|
22
|
+
self.remote_url = remote_url
|
23
|
+
self.local_path = expanded_local_path
|
24
|
+
end
|
25
|
+
|
26
|
+
def clone
|
27
|
+
raise "Git repo has been already cloned at '#{self.local_path}', please use 'init' instead" if repo_exist_at_local_path
|
28
|
+
@git_repo ||= Git.clone(self.remote_url, @local_pathname.basename.to_s, path: @local_pathname.parent.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def init
|
32
|
+
raise "Git repo has not been cloned yet from '#{self.remote_url}', please use 'clone' instead" unless repo_exist_at_local_path
|
33
|
+
@git_repo ||= Git.init(self.local_path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(file_path)
|
37
|
+
raise "Could not find any file to add at path '#{file_path}'" unless File.exist?(file_path)
|
38
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before adding new files to the index" if @git_repo.nil?
|
39
|
+
@git_repo.add(file_path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def commit(message = nil)
|
43
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before commiting new files" if @git_repo.nil?
|
44
|
+
message ||= "Automatic commit by nabokov"
|
45
|
+
@git_repo.commit(message)
|
46
|
+
end
|
47
|
+
|
48
|
+
def push
|
49
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before pushing any changes to remote" if @git_repo.nil?
|
50
|
+
@git_repo.push
|
51
|
+
end
|
52
|
+
|
53
|
+
def pull
|
54
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before pushing any changes to remote" if @git_repo.nil?
|
55
|
+
@git_repo.pull
|
56
|
+
end
|
57
|
+
|
58
|
+
def checkout_branch(name)
|
59
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before checkouting any branch" if @git_repo.nil?
|
60
|
+
raise "branch name could not be nil or zero length" if name.nil? || name.length.zero?
|
61
|
+
if @git_repo.is_branch?(name)
|
62
|
+
@git_repo.checkout(name)
|
63
|
+
else
|
64
|
+
@git_repo.checkout(name, { new_branch: true })
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete_branch(name)
|
69
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before deleting any branch" if @git_repo.nil?
|
70
|
+
raise "branch name could not be nil or zero length" if name.nil? || name.length.zero?
|
71
|
+
@git_repo.branch(name).delete
|
72
|
+
end
|
73
|
+
|
74
|
+
def merge_branches(original_branch, branch_to_be_merged)
|
75
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before merging any branches" if @git_repo.nil?
|
76
|
+
raise "original branch name could not be nil or zero length" if original_branch.nil? || original_branch.length.zero?
|
77
|
+
raise "branch to be merged in name could not be nil or zero length" if branch_to_be_merged.nil? || branch_to_be_merged.length.zero?
|
78
|
+
@git_repo.branch(original_branch).merge(@git_repo.branch(branch_to_be_merged))
|
79
|
+
end
|
80
|
+
|
81
|
+
def changes?
|
82
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before checking if the git repo has changes" if @git_repo.nil?
|
83
|
+
return true if @git_repo.status.deleted.count > 0
|
84
|
+
return true if @git_repo.status.added.count > 0
|
85
|
+
return true if @git_repo.status.changed.count > 0
|
86
|
+
false
|
87
|
+
end
|
88
|
+
|
89
|
+
def unfinished_merge?
|
90
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before checking if the git repo has unfinished merge" if @git_repo.nil?
|
91
|
+
return @git_repo.has_unmerged_files?
|
92
|
+
end
|
93
|
+
|
94
|
+
def current_branch
|
95
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before getting the current branch" if @git_repo.nil?
|
96
|
+
return @git_repo.current_branch
|
97
|
+
end
|
98
|
+
|
99
|
+
def abort_merge
|
100
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before aborting merge" if @git_repo.nil?
|
101
|
+
raise "nothing to abort - git repo doesn't have unfinished merge" unless self.unfinished_merge?
|
102
|
+
@git_repo.abort_merge
|
103
|
+
end
|
104
|
+
|
105
|
+
def unmerged_files
|
106
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before asking for unmerged files" if @git_repo.nil?
|
107
|
+
return [] unless @git_repo.has_unmerged_files?
|
108
|
+
conflicted_files = []
|
109
|
+
@git_repo.each_conflict do |file, your_version, their_version|
|
110
|
+
conflicted_files << file
|
111
|
+
end
|
112
|
+
conflicted_files
|
113
|
+
end
|
114
|
+
|
115
|
+
def reset_to_commit(commit_sha, options = {})
|
116
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before resetting" if @git_repo.nil?
|
117
|
+
raise "'commit' is a required parameter and could not be nil" if commit_sha.nil?
|
118
|
+
if options[:hard]
|
119
|
+
@git_repo.reset_hard(commit_sha)
|
120
|
+
else
|
121
|
+
@git_repo.reset(commit_sha)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def log(number_of_commits)
|
126
|
+
raise "'git' is not initialized yet, please call either 'clone' or 'init' before getting the log" if @git_repo.nil?
|
127
|
+
commits = @git_repo.log(number_of_commits)
|
128
|
+
commits.map(&:sha)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def repo_exist_at_local_path
|
134
|
+
Dir.exist?(self.local_path)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "cork"
|
2
|
+
|
3
|
+
module Nabokov
|
4
|
+
# This class is heavily based on the Interviewer class from the Danger gem
|
5
|
+
# The original link is https://github.com/danger/danger/blob/master/lib/danger/commands/init_helpers/interviewer.rb
|
6
|
+
class Informator
|
7
|
+
attr_accessor :no_waiting, :ui
|
8
|
+
|
9
|
+
def initialize(cork_board)
|
10
|
+
@ui = cork_board
|
11
|
+
end
|
12
|
+
|
13
|
+
def show_prompt
|
14
|
+
ui.print("> ".bold.green)
|
15
|
+
end
|
16
|
+
|
17
|
+
def say(message)
|
18
|
+
ui.puts(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
def inform(message)
|
22
|
+
ui.puts(message.green)
|
23
|
+
end
|
24
|
+
|
25
|
+
def important(message)
|
26
|
+
i = message.length + 8
|
27
|
+
inform("-" * i)
|
28
|
+
inform("--- " + message + " ---")
|
29
|
+
inform("-" * i)
|
30
|
+
end
|
31
|
+
|
32
|
+
def warn(message)
|
33
|
+
ui.puts(message.yellow)
|
34
|
+
end
|
35
|
+
|
36
|
+
def error(message)
|
37
|
+
ui.puts(message.red)
|
38
|
+
end
|
39
|
+
|
40
|
+
def wait_for_return
|
41
|
+
STDOUT.flush
|
42
|
+
STDIN.gets unless @no_waiting
|
43
|
+
ui.puts
|
44
|
+
end
|
45
|
+
|
46
|
+
def ask_with_answers(question, possible_answers)
|
47
|
+
ui.print("\n#{question}? [")
|
48
|
+
|
49
|
+
print_info = proc do
|
50
|
+
possible_answers.each_with_index do |answer, i|
|
51
|
+
the_answer = i.zero? ? answer.underline : answer
|
52
|
+
ui.print " " + the_answer
|
53
|
+
ui.print(" /") if i != possible_answers.length - 1
|
54
|
+
end
|
55
|
+
ui.print " ]\n"
|
56
|
+
end
|
57
|
+
print_info.call
|
58
|
+
|
59
|
+
answer = ""
|
60
|
+
|
61
|
+
loop do
|
62
|
+
show_prompt
|
63
|
+
answer = @no_waiting ? possible_answers[0].downcase : STDIN.gets.downcase.chomp
|
64
|
+
|
65
|
+
answer = "yes" if answer == "y"
|
66
|
+
answer = "no" if answer == "n"
|
67
|
+
|
68
|
+
# default to first answer
|
69
|
+
if answer == ""
|
70
|
+
answer = possible_answers[0].downcase
|
71
|
+
ui.puts "Using: " + answer.yellow
|
72
|
+
end
|
73
|
+
|
74
|
+
break if possible_answers.map(&:downcase).include? answer
|
75
|
+
|
76
|
+
ui.print "\nPossible answers are ["
|
77
|
+
print_info.call
|
78
|
+
end
|
79
|
+
|
80
|
+
answer
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "nabokov/git/git_repo"
|
2
|
+
require "nabokov/helpers/informator"
|
3
|
+
|
4
|
+
module Nabokov
|
5
|
+
# Result of the merge action perfomed by Nabokov::Merger
|
6
|
+
class MergerResult
|
7
|
+
SUCCEEDED = "succeeded".freeze
|
8
|
+
ABORTED = "aborted".freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
# Class is responsible for merging two branches
|
12
|
+
class Merger
|
13
|
+
def initialize(informator, git_repo, rescue_commit_sha = nil)
|
14
|
+
raise "'informator' is a required parameter" if informator.nil?
|
15
|
+
raise "'git_repo' is a required parameter" if git_repo.nil?
|
16
|
+
@rescue_commit_sha = rescue_commit_sha
|
17
|
+
@git_repo = git_repo
|
18
|
+
@informator = informator
|
19
|
+
end
|
20
|
+
|
21
|
+
# Merges one branch with another branch
|
22
|
+
# It handles the situation when there are merge conflicts and provides
|
23
|
+
# the interface to the user to resolve the conflicts
|
24
|
+
def merge(head, branch)
|
25
|
+
@git_repo.merge_branches(head, branch)
|
26
|
+
MergerResult::SUCCEEDED
|
27
|
+
rescue Git::GitExecuteError
|
28
|
+
rescue_merge
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def rescue_merge
|
34
|
+
ui.error("Merge failed with conflicts. Nabokov needs your help to continue")
|
35
|
+
proceed_option = ui.ask_with_answers("Would you like to resolve the conflicts manually or abort the synchronization?\n", ["resolve", "abort"])
|
36
|
+
if proceed_option == "abort"
|
37
|
+
abort_merge
|
38
|
+
elsif proceed_option == "resolve"
|
39
|
+
resolve_merge
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def abort_merge
|
44
|
+
@git_repo.abort_merge
|
45
|
+
@git_repo.reset_to_commit(@rescue_commit_sha, { hard: true }) unless @rescue_commit_sha.nil?
|
46
|
+
MergerResult::ABORTED
|
47
|
+
end
|
48
|
+
|
49
|
+
def resolve_merge
|
50
|
+
ui.say("Great! Please resolve conflict in the following files:")
|
51
|
+
unmerged_files = @git_repo.unmerged_files
|
52
|
+
unmerged_files.each do |file|
|
53
|
+
file_path = @git_repo.local_path + "/" + file
|
54
|
+
ui.say("* #{file_path}")
|
55
|
+
end
|
56
|
+
ui.say("Please press return when you're ready to move on...")
|
57
|
+
ui.wait_for_return
|
58
|
+
commit_after_merge_resolving(unmerged_files)
|
59
|
+
MergerResult::SUCCEEDED
|
60
|
+
end
|
61
|
+
|
62
|
+
def commit_after_merge_resolving(merged_files)
|
63
|
+
commit_merge = proc do
|
64
|
+
merged_files.each do |file|
|
65
|
+
file_path = @git_repo.local_path + "/" + file
|
66
|
+
ui.say("Adding #{file_path} to git index...")
|
67
|
+
@git_repo.add(file_path)
|
68
|
+
end
|
69
|
+
ui.say("Commiting merge conflicts resolving...")
|
70
|
+
@git_repo.commit("Nabokov merge conflicts manually have been resolved...")
|
71
|
+
end
|
72
|
+
|
73
|
+
if @git_repo.changes?
|
74
|
+
commit_merge.call
|
75
|
+
else
|
76
|
+
ui.warn("Seems like you haven't resolved the merge, if you want to continue anyway please press return...")
|
77
|
+
ui.wait_for_return
|
78
|
+
commit_merge.call if @git_repo.changes?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def ui
|
83
|
+
@informator
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Nabokov
|
2
|
+
VERSION = "0.1.0".freeze
|
3
|
+
DESCRIPTION = "One of the way to work on the localization - store it in the separate github repo
|
4
|
+
and asks localization team to update files in that repo.
|
5
|
+
This solution brings as well advantages but as well a disadvantages, to minimize the disadvantages
|
6
|
+
nabokov was invented. It helps developer to automatically keep remote localzation up to date and
|
7
|
+
also remain the project localization up to date as well.".freeze
|
8
|
+
end
|
data/lib/nabokov.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "nabokov/version"
|
2
|
+
require "nabokov/core/nabokovfile"
|
3
|
+
require "nabokov/commands/runner"
|
4
|
+
require "nabokov/commands/syncers/syncer"
|
5
|
+
require "nabokov/commands/syncers/localizations_repo_syncer"
|
6
|
+
require "nabokov/commands/syncers/project_syncer"
|
7
|
+
require "nabokov/commands/setup"
|
8
|
+
|
9
|
+
require "claide"
|
10
|
+
require "pathname"
|
11
|
+
require "cork"
|
12
|
+
|
13
|
+
module Nabokov
|
14
|
+
end
|
data/nabokov.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "nabokov/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "nabokov"
|
8
|
+
spec.version = Nabokov::VERSION
|
9
|
+
spec.authors = ["Anton Domashnev"]
|
10
|
+
spec.email = ["antondomashnev@gmail.com"]
|
11
|
+
spec.description = Nabokov::DESCRIPTION
|
12
|
+
spec.summary = "Move mobile localization boringness away from you 🏃"
|
13
|
+
spec.homepage = "https://github.com/Antondomashnev/nabokov"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = ">= 2.0.0"
|
22
|
+
|
23
|
+
spec.add_runtime_dependency "rspec", "~> 3.4"
|
24
|
+
spec.add_runtime_dependency "git", "~> 1.0"
|
25
|
+
spec.add_runtime_dependency "claide", "~> 1.0"
|
26
|
+
spec.add_runtime_dependency "cork", "~> 0.1"
|
27
|
+
|
28
|
+
spec.add_development_dependency "rubocop", "~> 0.42"
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
30
|
+
spec.add_development_dependency "rake"
|
31
|
+
end
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
Nabokov template repo for specs
|
@@ -0,0 +1 @@
|
|
1
|
+
"hello" = "hallo";
|
@@ -0,0 +1 @@
|
|
1
|
+
"hello" = "hello";
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
Nabokov template repo for specs
|
@@ -0,0 +1,9 @@
|
|
1
|
+
localizations_repo:
|
2
|
+
url: 'https://github.com/Antondomashnev/nabokov_example.git'
|
3
|
+
master_branch: 'master'
|
4
|
+
|
5
|
+
project_repo:
|
6
|
+
localizations:
|
7
|
+
:en: 'spec/fixtures/test_project_syncer/project_repo/en.strings'
|
8
|
+
:de: 'spec/fixtures/test_project_syncer/project_repo/de.strings'
|
9
|
+
local_path: 'spec/fixtures/test_project_syncer/project_repo'
|