lokalise_manager 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +10 -2
- data/lib/lokalise_manager/global_config.rb +12 -1
- data/lib/lokalise_manager/task_definitions/base.rb +13 -4
- data/lib/lokalise_manager/task_definitions/exporter.rb +31 -12
- data/lib/lokalise_manager/task_definitions/importer.rb +2 -2
- data/lib/lokalise_manager/utils/array_utils.rb +27 -0
- data/lib/lokalise_manager/utils/hash_utils.rb +28 -0
- data/lib/lokalise_manager/version.rb +1 -1
- data/lib/lokalise_manager.rb +3 -0
- data/lokalise_manager.gemspec +4 -1
- data/spec/lib/lokalise_manager/global_config_spec.rb +10 -0
- data/spec/lib/lokalise_manager/task_definitions/base_spec.rb +15 -4
- data/spec/lib/lokalise_manager/task_definitions/exporter_spec.rb +42 -26
- data/spec/lib/lokalise_manager/task_definitions/importer_spec.rb +43 -11
- data/spec/lib/utils/array_utils_spec.rb +18 -0
- data/spec/lib/utils/hash_utils_spec.rb +13 -0
- data/spec/support/vcr.rb +3 -1
- metadata +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f9ca0fe8caf151e84dcc09f29368bc61b5bc3cdb4341ef5c1b21040b764a17a
|
4
|
+
data.tar.gz: 8c9194a836a1261638f2b22d8d2d7553bfbe605325911cb0c0ecef9332e9084c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c4b7131ea9d6b60ff4094d0e34c92484818eb3c608a016932426c83bbcab4a06f4c820399f2fa70cc2a78d9a60a73dcf442ec9ba082bdc095ab539b467e1677
|
7
|
+
data.tar.gz: b98c062b4ecc030c37fa1f1ad95126209749c99ec7aba72b616fad380819d55552dc6d4b2a611b94471f79b3748855eefbaab3c9397ab49e9f8e19a6a6afb1ab
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 2.0.0 (27-Jan-22)
|
4
|
+
|
5
|
+
* `export!` method is now taking advantage of multi-threading (as Lokalise API allows to send requests in parallel since January 2022)
|
6
|
+
* Test with Ruby 3.1.0
|
7
|
+
* Other minor fixes
|
8
|
+
|
9
|
+
## 1.2.1 (26-Nov-21)
|
10
|
+
|
11
|
+
* Use refinements instead of monkey patching to add hash methods
|
12
|
+
* Don't use `OpenStruct` anymore to store config opts
|
13
|
+
* Minor fixes
|
14
|
+
|
15
|
+
## 1.2.0 (26-Oct-21)
|
16
|
+
|
17
|
+
* Add a new option `:silent_mode` which is `false` by default. When silent mode is enabled, no debug info will be printed out to `$stdout`. The only exception are the "safe mode" messages — you'll still be prompted to continue if the target directory is not empty.
|
18
|
+
* Use `#deep_merge` instead of a simple merge when processing options.
|
19
|
+
|
20
|
+
## 1.1.0 (25-Oct-21)
|
21
|
+
|
22
|
+
* Add a new option `:use_oauth2_token` which is `false` by default. When enabled, you'll be able to provide a token obtained via [OAuth 2 flow](https://docs.lokalise.com/en/articles/5574713-oauth-2) rather than generated via Lokalise profile. The token should still be provided via the `:api_token` option:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
importer = LokaliseManager.importer api_token: 'TOKEN_VIA_OAUTH2', project_id: '123.abc', use_oauth2_token: true
|
26
|
+
```
|
27
|
+
|
3
28
|
## 1.0.0 (14-Oct-21)
|
4
29
|
|
5
30
|
* Initial release
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# LokaliseManager
|
2
2
|
|
3
3
|
![Gem](https://img.shields.io/gem/v/lokalise_manager)
|
4
|
-
|
4
|
+
![CI](https://github.com/bodrovis/lokalise_manager/actions/workflows/ci.yml/badge.svg)
|
5
5
|
[![Test Coverage](https://codecov.io/gh/bodrovis/lokalise_manager/graph/badge.svg)](https://codecov.io/gh/bodrovis/lokalise_manager)
|
6
6
|
![Downloads total](https://img.shields.io/gem/dt/lokalise_manager)
|
7
7
|
|
@@ -15,6 +15,8 @@ If you are looking for a Rails integration, please check [lokalise_rails](https:
|
|
15
15
|
|
16
16
|
This gem requires Ruby 2.5+. You will also need to [setup a Lokalise account](https://app.lokalise.com/signup) and create a [translation project](https://docs.lokalise.com/en/articles/1400460-projects). Finally, you will need to generate a [read/write API token](https://docs.lokalise.com/en/articles/1929556-api-tokens) at your Lokalise profile.
|
17
17
|
|
18
|
+
Alternatively, you can utilize a token obtained via OAuth 2 flow. When using such a token, you'll have to set `:use_oauth2_token` option to `true` (see below).
|
19
|
+
|
18
20
|
### Installation
|
19
21
|
|
20
22
|
Add the gem to your `Gemfile`:
|
@@ -87,10 +89,12 @@ Please don't forget that Lokalise API has rate limiting and you cannot send more
|
|
87
89
|
### Common config
|
88
90
|
|
89
91
|
* `api_token` (`string`, required) — Lokalise API token with read/write permissions.
|
92
|
+
* `use_oauth2_token` (`boolean`) — whether you would like to use a token obtained via [OAuth 2 flow](https://docs.lokalise.com/en/articles/5574713-oauth-2). Defaults to `false`.
|
90
93
|
* `project_id` (`string`, required) — Lokalise project ID. You must have import/export permissions in the specified project.
|
91
94
|
* `locales_path` (`string`) — path to the directory with your translation files. Defaults to `"#{Dir.getwd}/locales"`.
|
92
95
|
* `branch` (`string`) — Lokalise project branch to use. Defaults to `""` (no branch is provided).
|
93
96
|
* `timeouts` (`hash`) — set [request timeouts for the Lokalise API client](https://lokalise.github.io/ruby-lokalise-api/additional_info/customization#setting-timeouts). By default, requests have no timeouts: `{open_timeout: nil, timeout: nil}`. Both values are in seconds.
|
97
|
+
* `silent_mode` (`boolean`) — whether you would like to output debugging information to `$stdout`. By default, after a task is performed, a short notification message will be printed out to the terminal. When set to `false`, notifications won't be printed. Please note that currently `import_safe_mode` has higher priority. Even if you enable `silent_mode`, and the `import_safe_mode` is enabled as well, you will be prompted to confirm the import operation if the target directory is not empty.
|
94
98
|
|
95
99
|
### Import config
|
96
100
|
|
@@ -169,6 +173,10 @@ If your translation files are not in YAML format, you will need to adjust the fo
|
|
169
173
|
* `translations_converter` (`lambda` or `proc`) — converts translations data to a proper format before saving them to a translation file. Defaults to `->(raw_data) { raw_data.to_yaml }`. In the simplest case you may just return the data back, for example `-> (raw_data) { raw_data }`.
|
170
174
|
* `lang_iso_inferer` (`lambda` or `proc`) — infers language ISO code based on the translation file data before uploading it to Lokalise. Defaults to `->(data) { YAML.safe_load(data)&.keys&.first }`.
|
171
175
|
|
176
|
+
### Customizing JSON parser and network adapter
|
177
|
+
|
178
|
+
JSON parser and network adapter utilized by lokalise_manager can be customized as well. Please check [ruby-lokalise-api doc](https://lokalise.github.io/ruby-lokalise-api/additional_info/customization) to learn more.
|
179
|
+
|
172
180
|
## Providing config options
|
173
181
|
|
174
182
|
### Per-client
|
@@ -263,4 +271,4 @@ importer.import!
|
|
263
271
|
|
264
272
|
## License
|
265
273
|
|
266
|
-
Copyright (c) [Lokalise team](http://lokalise.com), [Ilya Bodrov](http://bodrovis.tech). License type is [MIT](https://github.com/bodrovis/lokalise_manager/blob/master/LICENSE).
|
274
|
+
Copyright (c) [Lokalise team](http://lokalise.com), [Ilya Bodrov](http://bodrovis.tech). License type is [MIT](https://github.com/bodrovis/lokalise_manager/blob/master/LICENSE).
|
@@ -7,13 +7,24 @@ module LokaliseManager
|
|
7
7
|
attr_writer :import_opts, :import_safe_mode, :export_opts, :locales_path,
|
8
8
|
:file_ext_regexp, :skip_file_export, :branch, :timeouts,
|
9
9
|
:translations_loader, :translations_converter, :lang_iso_inferer,
|
10
|
-
:max_retries_export, :max_retries_import
|
10
|
+
:max_retries_export, :max_retries_import, :use_oauth2_token, :silent_mode
|
11
11
|
|
12
12
|
# Main interface to provide configuration options
|
13
13
|
def config
|
14
14
|
yield self
|
15
15
|
end
|
16
16
|
|
17
|
+
# When enabled, won't print any debugging info to $stdout
|
18
|
+
def silent_mode
|
19
|
+
@silent_mode || false
|
20
|
+
end
|
21
|
+
|
22
|
+
# When enabled, will use OAuth 2 Lokalise client and will require to provide a token obtained via OAuth 2 flow
|
23
|
+
# rather than via Lokalise profile
|
24
|
+
def use_oauth2_token
|
25
|
+
@use_oauth2_token || false
|
26
|
+
end
|
27
|
+
|
17
28
|
# Full path to directory with translation files
|
18
29
|
def locales_path
|
19
30
|
@locales_path || "#{Dir.getwd}/locales"
|
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'ruby-lokalise-api'
|
4
4
|
require 'pathname'
|
5
|
-
require 'ostruct'
|
6
5
|
|
7
6
|
module LokaliseManager
|
8
7
|
module TaskDefinitions
|
9
8
|
class Base
|
9
|
+
using LokaliseManager::Utils::HashUtils
|
10
|
+
|
10
11
|
attr_accessor :config
|
11
12
|
|
12
13
|
# Creates a new importer or exporter. It accepts custom config and merges it
|
@@ -23,19 +24,27 @@ module LokaliseManager
|
|
23
24
|
opts[reader.to_sym] = global_config.send(reader)
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
+
all_opts = primary_opts.deep_merge(custom_opts)
|
28
|
+
|
29
|
+
config_klass = Struct.new(*all_opts.keys, keyword_init: true)
|
30
|
+
|
31
|
+
@config = config_klass.new all_opts
|
27
32
|
end
|
28
33
|
|
29
34
|
# Creates a Lokalise API client
|
30
35
|
#
|
31
36
|
# @return [Lokalise::Client]
|
32
37
|
def api_client
|
33
|
-
|
38
|
+
client_opts = [config.api_token, {enable_compression: true}.merge(config.timeouts)]
|
39
|
+
client_method = config.use_oauth2_token ? :oauth_client : :client
|
40
|
+
|
41
|
+
@api_client = ::Lokalise.send(client_method, *client_opts)
|
34
42
|
end
|
35
43
|
|
36
44
|
# Resets API client
|
37
45
|
def reset_api_client!
|
38
|
-
Lokalise.reset_client!
|
46
|
+
::Lokalise.reset_client!
|
47
|
+
::Lokalise.reset_oauth_client!
|
39
48
|
@api_client = nil
|
40
49
|
end
|
41
50
|
|
@@ -5,6 +5,7 @@ require 'base64'
|
|
5
5
|
module LokaliseManager
|
6
6
|
module TaskDefinitions
|
7
7
|
class Exporter < Base
|
8
|
+
using LokaliseManager::Utils::ArrayUtils
|
8
9
|
# Performs translation file export to Lokalise and returns an array of queued processes
|
9
10
|
#
|
10
11
|
# @return [Array]
|
@@ -12,31 +13,48 @@ module LokaliseManager
|
|
12
13
|
check_options_errors!
|
13
14
|
|
14
15
|
queued_processes = []
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
|
17
|
+
all_files.in_groups_of(6) do |files_group|
|
18
|
+
parallel_upload(files_group).each do |thr|
|
19
|
+
raise_on_fail thr
|
20
|
+
|
21
|
+
queued_processes.push thr[:process]
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
|
-
$stdout.print
|
25
|
+
$stdout.print('Task complete!') unless config.silent_mode
|
22
26
|
|
23
27
|
queued_processes
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
27
31
|
|
32
|
+
def parallel_upload(files_group)
|
33
|
+
files_group.compact.map do |file_data|
|
34
|
+
do_upload(*file_data)
|
35
|
+
end.map(&:value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def raise_on_fail(thread)
|
39
|
+
raise thread[:error].class, "Error while trying to upload #{thread[:path]}: #{thread[:error].message}" if thread[:status] == :fail
|
40
|
+
end
|
41
|
+
|
28
42
|
# Performs the actual file uploading to Lokalise. If the API rate limit is exceeed,
|
29
43
|
# applies exponential backoff
|
30
44
|
def do_upload(f_path, r_path)
|
31
|
-
|
32
|
-
|
45
|
+
Thread.new do
|
46
|
+
process = with_exp_backoff(config.max_retries_export) do
|
47
|
+
api_client.upload_file project_id_with_branch, opts(f_path, r_path)
|
48
|
+
end
|
49
|
+
{status: :ok, process: process}
|
50
|
+
rescue StandardError => e
|
51
|
+
{status: :fail, path: f_path, error: e}
|
33
52
|
end
|
34
53
|
end
|
35
54
|
|
36
|
-
#
|
37
|
-
def
|
38
|
-
|
39
|
-
|
55
|
+
# Gets translation files from the specified directory
|
56
|
+
def all_files
|
57
|
+
files = []
|
40
58
|
loc_path = config.locales_path
|
41
59
|
Dir["#{loc_path}/**/*"].sort.each do |f|
|
42
60
|
full_path = Pathname.new f
|
@@ -45,8 +63,9 @@ module LokaliseManager
|
|
45
63
|
|
46
64
|
relative_path = full_path.relative_path_from Pathname.new(loc_path)
|
47
65
|
|
48
|
-
|
66
|
+
files << [full_path, relative_path]
|
49
67
|
end
|
68
|
+
files
|
50
69
|
end
|
51
70
|
|
52
71
|
# Generates export options
|
@@ -14,13 +14,13 @@ module LokaliseManager
|
|
14
14
|
check_options_errors!
|
15
15
|
|
16
16
|
unless proceed_when_safe_mode?
|
17
|
-
$stdout.print
|
17
|
+
$stdout.print('Task cancelled!') unless config.silent_mode
|
18
18
|
return false
|
19
19
|
end
|
20
20
|
|
21
21
|
open_and_process_zip download_files['bundle_url']
|
22
22
|
|
23
|
-
$stdout.print
|
23
|
+
$stdout.print('Task complete!') unless config.silent_mode
|
24
24
|
true
|
25
25
|
end
|
26
26
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Taken from https://github.com/rails/rails/blob/6bfc637659248df5d6719a86d2981b52662d9b50/activesupport/lib/active_support/core_ext/array/grouping.rb
|
4
|
+
|
5
|
+
module LokaliseManager
|
6
|
+
module Utils
|
7
|
+
module ArrayUtils
|
8
|
+
refine Array do
|
9
|
+
def in_groups_of(number, fill_with = nil, &block)
|
10
|
+
if number.to_i <= 0
|
11
|
+
raise ArgumentError,
|
12
|
+
"Group size must be a positive integer, was #{number.inspect}"
|
13
|
+
end
|
14
|
+
|
15
|
+
if fill_with == false
|
16
|
+
collection = self
|
17
|
+
else
|
18
|
+
padding = (number - (size % number)) % number
|
19
|
+
collection = dup.concat(Array.new(padding, fill_with))
|
20
|
+
end
|
21
|
+
|
22
|
+
collection.each_slice(number, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Taken from https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
|
4
|
+
|
5
|
+
module LokaliseManager
|
6
|
+
module Utils
|
7
|
+
module HashUtils
|
8
|
+
refine Hash do
|
9
|
+
def deep_merge(other_hash, &block)
|
10
|
+
dup.deep_merge!(other_hash, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Same as +deep_merge+, but modifies +self+.
|
14
|
+
def deep_merge!(other_hash, &block)
|
15
|
+
merge!(other_hash) do |key, this_val, other_val|
|
16
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
17
|
+
this_val.deep_merge(other_val, &block)
|
18
|
+
elsif block
|
19
|
+
yield(key, this_val, other_val)
|
20
|
+
else
|
21
|
+
other_val
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/lokalise_manager.rb
CHANGED
data/lokalise_manager.gemspec
CHANGED
@@ -32,7 +32,10 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_development_dependency 'rspec', '~> 3.6'
|
33
33
|
spec.add_development_dependency 'rubocop', '~> 1.0'
|
34
34
|
spec.add_development_dependency 'rubocop-performance', '~> 1.5'
|
35
|
-
spec.add_development_dependency 'rubocop-rspec', '~> 2.
|
35
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.6'
|
36
36
|
spec.add_development_dependency 'simplecov', '~> 0.16'
|
37
37
|
spec.add_development_dependency 'vcr', '~> 6.0'
|
38
|
+
spec.metadata = {
|
39
|
+
'rubygems_mfa_required' => 'true'
|
40
|
+
}
|
38
41
|
end
|
@@ -14,6 +14,16 @@ describe LokaliseManager::GlobalConfig do
|
|
14
14
|
fake_class.project_id = '123.abc'
|
15
15
|
end
|
16
16
|
|
17
|
+
it 'is possible to set silent_mode' do
|
18
|
+
allow(fake_class).to receive(:silent_mode=).with(true)
|
19
|
+
fake_class.silent_mode = true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is possible to set use_oauth2_token' do
|
23
|
+
allow(fake_class).to receive(:use_oauth2_token=).with(true)
|
24
|
+
fake_class.use_oauth2_token = true
|
25
|
+
end
|
26
|
+
|
17
27
|
it 'is possible to set file_ext_regexp' do
|
18
28
|
allow(fake_class).to receive(:file_ext_regexp=).with(Regexp.new('.*'))
|
19
29
|
fake_class.file_ext_regexp = Regexp.new('.*')
|
@@ -24,7 +24,7 @@ describe LokaliseManager::TaskDefinitions::Base do
|
|
24
24
|
specify '.reset_client!' do
|
25
25
|
expect(described_object.api_client).to be_an_instance_of(Lokalise::Client)
|
26
26
|
described_object.reset_api_client!
|
27
|
-
current_client = described_object.instance_variable_get
|
27
|
+
current_client = described_object.instance_variable_get :@api_client
|
28
28
|
expect(current_client).to be_nil
|
29
29
|
end
|
30
30
|
|
@@ -94,9 +94,20 @@ describe LokaliseManager::TaskDefinitions::Base do
|
|
94
94
|
timeout: 500
|
95
95
|
})
|
96
96
|
|
97
|
-
|
98
|
-
expect(
|
99
|
-
expect(
|
97
|
+
client = described_object.api_client
|
98
|
+
expect(client).to be_an_instance_of(Lokalise::Client)
|
99
|
+
expect(client).not_to be_an_instance_of(Lokalise::OAuthClient)
|
100
|
+
expect(client.open_timeout).to eq(100)
|
101
|
+
expect(client.timeout).to eq(500)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'uses .oauth_client when the use_oauth2_token is true' do
|
105
|
+
allow(described_object.config).to receive(:use_oauth2_token).and_return(true)
|
106
|
+
|
107
|
+
client = described_object.api_client
|
108
|
+
|
109
|
+
expect(client).to be_an_instance_of(Lokalise::OAuthClient)
|
110
|
+
expect(client).not_to be_an_instance_of(Lokalise::Client)
|
100
111
|
end
|
101
112
|
end
|
102
113
|
end
|
@@ -24,26 +24,30 @@ describe LokaliseManager::TaskDefinitions::Exporter do
|
|
24
24
|
|
25
25
|
describe '.export!' do
|
26
26
|
it 'sends a proper API request and handles rate limiting' do
|
27
|
-
process =
|
28
|
-
|
29
|
-
|
27
|
+
process = nil
|
28
|
+
|
29
|
+
VCR.use_cassette('upload_files_multiple') do
|
30
|
+
expect(-> { process = described_object.export!.first }).to output(/complete!/).to_stdout
|
31
|
+
end
|
30
32
|
|
31
33
|
expect(process.project_id).to eq(project_id)
|
32
34
|
expect(process.status).to eq('queued')
|
33
35
|
end
|
34
36
|
|
35
37
|
it 'handles too many requests' do
|
38
|
+
allow(described_object.config).to receive(:max_retries_export).and_return(1)
|
36
39
|
allow(described_object).to receive(:sleep).and_return(0)
|
37
40
|
|
38
41
|
fake_client = instance_double('Lokalise::Client')
|
42
|
+
allow(fake_client).to receive(:token).with(any_args).and_return('fake_token')
|
39
43
|
allow(fake_client).to receive(:upload_file).with(any_args).and_raise(Lokalise::Error::TooManyRequests)
|
40
44
|
allow(described_object).to receive(:api_client).and_return(fake_client)
|
41
45
|
|
42
|
-
expect(-> { described_object.export! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after
|
46
|
+
expect(-> { described_object.export! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 1 retries/i)
|
43
47
|
|
44
|
-
expect(described_object).to have_received(:sleep).exactly(
|
45
|
-
expect(described_object).to have_received(:api_client).
|
46
|
-
expect(fake_client).to have_received(:upload_file).exactly(
|
48
|
+
expect(described_object).to have_received(:sleep).exactly(6).times
|
49
|
+
expect(described_object).to have_received(:api_client).at_least(12).times
|
50
|
+
expect(fake_client).to have_received(:upload_file).exactly(12).times
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
@@ -58,6 +62,19 @@ describe LokaliseManager::TaskDefinitions::Exporter do
|
|
58
62
|
end
|
59
63
|
|
60
64
|
describe '.export!' do
|
65
|
+
it 'sends a proper API request but does not output anything when silent_mode is enabled' do
|
66
|
+
allow(described_object.config).to receive(:silent_mode).and_return(true)
|
67
|
+
|
68
|
+
process = nil
|
69
|
+
|
70
|
+
VCR.use_cassette('upload_files') do
|
71
|
+
expect(-> { process = described_object.export!.first }).not_to output(/complete!/).to_stdout
|
72
|
+
end
|
73
|
+
|
74
|
+
expect(process.status).to eq('queued')
|
75
|
+
expect(described_object.config).to have_received(:silent_mode).at_most(1).times
|
76
|
+
end
|
77
|
+
|
61
78
|
it 'sends a proper API request' do
|
62
79
|
process = VCR.use_cassette('upload_files') do
|
63
80
|
described_object.export!
|
@@ -93,9 +110,9 @@ describe LokaliseManager::TaskDefinitions::Exporter do
|
|
93
110
|
end
|
94
111
|
end
|
95
112
|
|
96
|
-
describe '
|
113
|
+
describe '#all_files' do
|
97
114
|
it 'yield proper arguments' do
|
98
|
-
expect
|
115
|
+
expect(described_object.send(:all_files).first).to include(
|
99
116
|
Pathname.new(path),
|
100
117
|
Pathname.new(relative_name)
|
101
118
|
)
|
@@ -165,30 +182,29 @@ describe LokaliseManager::TaskDefinitions::Exporter do
|
|
165
182
|
end
|
166
183
|
end
|
167
184
|
|
168
|
-
describe '
|
169
|
-
it '
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
]
|
185
|
+
describe '#each_file' do
|
186
|
+
it 'returns all files' do
|
187
|
+
files = described_object.send(:all_files)
|
188
|
+
expect(files[0]).to include(
|
189
|
+
Pathname.new(path),
|
190
|
+
Pathname.new(relative_name)
|
191
|
+
)
|
192
|
+
expect(files[1]).to include(
|
193
|
+
Pathname.new(path_ru),
|
194
|
+
Pathname.new(filename_ru)
|
179
195
|
)
|
180
196
|
end
|
181
197
|
|
182
|
-
it 'does not
|
198
|
+
it 'does not return files that have to be skipped' do
|
183
199
|
allow(described_object.config).to receive(:skip_file_export).twice.and_return(
|
184
200
|
->(f) { f.split[1].to_s.include?('ru') }
|
185
201
|
)
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
]
|
202
|
+
files = described_object.send(:all_files)
|
203
|
+
expect(files[0]).to include(
|
204
|
+
Pathname.new(path),
|
205
|
+
Pathname.new(relative_name)
|
191
206
|
)
|
207
|
+
expect(files.count).to eq(1)
|
192
208
|
|
193
209
|
expect(described_object.config).to have_received(:skip_file_export).twice
|
194
210
|
end
|
@@ -9,12 +9,16 @@ describe LokaliseManager::TaskDefinitions::Importer do
|
|
9
9
|
let(:loc_path) { described_object.config.locales_path }
|
10
10
|
let(:project_id) { ENV['LOKALISE_PROJECT_ID'] }
|
11
11
|
let(:local_trans) { "#{Dir.getwd}/spec/fixtures/trans.zip" }
|
12
|
-
let(:faulty_trans) { "#{Dir.getwd}/spec/fixtures/faulty_trans.zip" }
|
13
12
|
|
14
|
-
describe '
|
13
|
+
describe '#open_and_process_zip' do
|
15
14
|
it 're-raises errors during file processing' do
|
16
|
-
|
17
|
-
|
15
|
+
entry = double
|
16
|
+
allow(entry).to receive(:name).and_return('fail.yml')
|
17
|
+
allow(described_object).to receive(:data_from).with(entry).and_raise(EncodingError)
|
18
|
+
expect(-> { described_object.send(:process!, entry) }).
|
19
|
+
to raise_error(EncodingError, /Error when trying to process fail\.yml/)
|
20
|
+
|
21
|
+
expect(described_object).to have_received(:data_from)
|
18
22
|
end
|
19
23
|
|
20
24
|
it 're-raises errors during file opening' do
|
@@ -23,7 +27,7 @@ describe LokaliseManager::TaskDefinitions::Importer do
|
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
26
|
-
describe '
|
30
|
+
describe '#download_files' do
|
27
31
|
it 'returns a proper download URL' do
|
28
32
|
response = VCR.use_cassette('download_files') do
|
29
33
|
described_object.send :download_files
|
@@ -103,15 +107,31 @@ describe LokaliseManager::TaskDefinitions::Importer do
|
|
103
107
|
end
|
104
108
|
|
105
109
|
it 'runs import successfully' do
|
106
|
-
result =
|
107
|
-
|
110
|
+
result = nil
|
111
|
+
|
112
|
+
VCR.use_cassette('import') do
|
113
|
+
expect(-> { result = described_object.import! }).to output(/complete!/).to_stdout
|
108
114
|
end
|
109
115
|
|
110
116
|
expect(result).to be true
|
111
117
|
|
112
|
-
expect(count_translations).to eq(
|
113
|
-
expect_file_exist loc_path, '
|
114
|
-
expect_file_exist loc_path, '
|
118
|
+
expect(count_translations).to eq(24)
|
119
|
+
expect_file_exist loc_path, 'en_1.yml'
|
120
|
+
expect_file_exist loc_path, 'ru_2.yml'
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'runs import successfully but does not provide any output when silent_mode is enabled' do
|
124
|
+
allow(described_object.config).to receive(:silent_mode).and_return(true)
|
125
|
+
result = nil
|
126
|
+
|
127
|
+
VCR.use_cassette('import') do
|
128
|
+
expect(-> { result = described_object.import! }).not_to output(/complete!/).to_stdout
|
129
|
+
end
|
130
|
+
|
131
|
+
expect(result).to be true
|
132
|
+
expect_file_exist loc_path, 'en_1.yml'
|
133
|
+
expect_file_exist loc_path, 'ru_2.yml'
|
134
|
+
expect(described_object.config).to have_received(:silent_mode).at_most(1).times
|
115
135
|
end
|
116
136
|
end
|
117
137
|
|
@@ -157,9 +177,21 @@ describe LokaliseManager::TaskDefinitions::Importer do
|
|
157
177
|
it 'import halts when a user chooses not to proceed' do
|
158
178
|
allow(safe_mode_obj).to receive(:download_files).at_most(0).times
|
159
179
|
allow($stdin).to receive(:gets).and_return('N')
|
160
|
-
expect(-> { safe_mode_obj.import! }).to output(/
|
180
|
+
expect(-> { safe_mode_obj.import! }).to output(/cancelled/).to_stdout
|
181
|
+
|
182
|
+
expect(safe_mode_obj).not_to have_received(:download_files)
|
183
|
+
expect($stdin).to have_received(:gets)
|
184
|
+
expect(count_translations).to eq(1)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'import halts when a user chooses not to proceed and debug info is not printed out when silent_mode is enabled' do
|
188
|
+
allow(safe_mode_obj.config).to receive(:silent_mode).and_return(true)
|
189
|
+
allow(safe_mode_obj).to receive(:download_files).at_most(0).times
|
190
|
+
allow($stdin).to receive(:gets).and_return('N')
|
191
|
+
expect(-> { safe_mode_obj.import! }).not_to output(/cancelled/).to_stdout
|
161
192
|
|
162
193
|
expect(safe_mode_obj).not_to have_received(:download_files)
|
194
|
+
expect(safe_mode_obj.config).to have_received(:silent_mode)
|
163
195
|
expect($stdin).to have_received(:gets)
|
164
196
|
expect(count_translations).to eq(1)
|
165
197
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe LokaliseManager::Utils::ArrayUtils do
|
4
|
+
using described_class
|
5
|
+
let(:arr) { (1..8).to_a }
|
6
|
+
|
7
|
+
describe '#in_groups_of' do
|
8
|
+
it 'raises an exception when the number is less than 1' do
|
9
|
+
expect(-> { arr.in_groups_of(-1) }).to raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'uses collection itself if fill_with is false' do
|
13
|
+
enum = arr.in_groups_of(5, false)
|
14
|
+
enum.next
|
15
|
+
expect(enum.next.count).to eq(3)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe LokaliseManager::Utils::HashUtils do
|
4
|
+
using described_class
|
5
|
+
let(:h1) { {a: 100, b: 200, c: {c1: 100}} }
|
6
|
+
let(:h2) { {b: 250, c: {c1: 200}} }
|
7
|
+
|
8
|
+
specify '#deep_merge' do
|
9
|
+
result = h1.deep_merge(h2) { |_key, this_val, other_val| this_val + other_val }
|
10
|
+
expect(result[:b]).to eq(450)
|
11
|
+
expect(result[:c][:c1]).to eq(300)
|
12
|
+
end
|
13
|
+
end
|
data/spec/support/vcr.rb
CHANGED
@@ -6,6 +6,8 @@ VCR.configure do |c|
|
|
6
6
|
c.ignore_hosts 'codeclimate.com'
|
7
7
|
c.hook_into :faraday
|
8
8
|
c.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
9
|
-
c.filter_sensitive_data('<LOKALISE_TOKEN>')
|
9
|
+
c.filter_sensitive_data('<LOKALISE_TOKEN>') do |_i|
|
10
|
+
ENV.fetch('LOKALISE_API_TOKEN')
|
11
|
+
end
|
10
12
|
c.configure_rspec_metadata!
|
11
13
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lokalise_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Bodrov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-lokalise-api
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 2.
|
131
|
+
version: '2.6'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 2.
|
138
|
+
version: '2.6'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: simplecov
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +187,8 @@ files:
|
|
187
187
|
- lib/lokalise_manager/task_definitions/base.rb
|
188
188
|
- lib/lokalise_manager/task_definitions/exporter.rb
|
189
189
|
- lib/lokalise_manager/task_definitions/importer.rb
|
190
|
+
- lib/lokalise_manager/utils/array_utils.rb
|
191
|
+
- lib/lokalise_manager/utils/hash_utils.rb
|
190
192
|
- lib/lokalise_manager/version.rb
|
191
193
|
- lokalise_manager.gemspec
|
192
194
|
- spec/lib/lokalise_manager/global_config_spec.rb
|
@@ -194,6 +196,8 @@ files:
|
|
194
196
|
- spec/lib/lokalise_manager/task_definitions/exporter_spec.rb
|
195
197
|
- spec/lib/lokalise_manager/task_definitions/importer_spec.rb
|
196
198
|
- spec/lib/lokalise_manager_spec.rb
|
199
|
+
- spec/lib/utils/array_utils_spec.rb
|
200
|
+
- spec/lib/utils/hash_utils_spec.rb
|
197
201
|
- spec/spec_helper.rb
|
198
202
|
- spec/support/file_manager.rb
|
199
203
|
- spec/support/spec_addons.rb
|
@@ -201,7 +205,8 @@ files:
|
|
201
205
|
homepage: https://github.com/bodrovis/lokalise_manager
|
202
206
|
licenses:
|
203
207
|
- MIT
|
204
|
-
metadata:
|
208
|
+
metadata:
|
209
|
+
rubygems_mfa_required: 'true'
|
205
210
|
post_install_message:
|
206
211
|
rdoc_options: []
|
207
212
|
require_paths:
|
@@ -217,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
222
|
- !ruby/object:Gem::Version
|
218
223
|
version: '0'
|
219
224
|
requirements: []
|
220
|
-
rubygems_version: 3.
|
225
|
+
rubygems_version: 3.3.5
|
221
226
|
signing_key:
|
222
227
|
specification_version: 4
|
223
228
|
summary: Lokalise integration for Ruby
|
@@ -227,6 +232,8 @@ test_files:
|
|
227
232
|
- spec/lib/lokalise_manager/task_definitions/exporter_spec.rb
|
228
233
|
- spec/lib/lokalise_manager/task_definitions/importer_spec.rb
|
229
234
|
- spec/lib/lokalise_manager_spec.rb
|
235
|
+
- spec/lib/utils/array_utils_spec.rb
|
236
|
+
- spec/lib/utils/hash_utils_spec.rb
|
230
237
|
- spec/spec_helper.rb
|
231
238
|
- spec/support/file_manager.rb
|
232
239
|
- spec/support/spec_addons.rb
|