nabokov 0.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 +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'
|