lokalise_manager 1.2.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33815f129df22f7a27f91689cad944193aca9b992f14e7115a2737088785d3b3
4
- data.tar.gz: 1fc5a893bb917bac5afd39f2b35dbbb54286b878dce42f0805135105490520b5
3
+ metadata.gz: fa7eb812b614ec768710c4f085879dfaf6cf89f72e25b1a777f34af3e9cd8be5
4
+ data.tar.gz: afdd4c08bf9672302c279cd88b4c4caf63317b1aca98036a5e8c1dad361289f0
5
5
  SHA512:
6
- metadata.gz: 7fecf43ac4f105be85fe2e4548643849b78a239ec523a79b37fec4b6acbeddf319dd4ac594e5caf28e4b174fed76e05b18d3bf6d6343d055daa2115d661b41c4
7
- data.tar.gz: 85f6c703a1ee2107cfe165b7c652cc81d2c2f0a0ae2a02af44cfb0e0cf31a185e5cbe3cbe27c8c53d411a8dd4f3046a98b02dadde3d983855e02cead3347cfb4
6
+ metadata.gz: 5857c35bde158e85bdec5c2e4618ebf1ddc7768f5822d5492109347fa93907434869d23c5053f6c7b98da8016e4e22c40fa8fa4b513c347630aeb18288f8d18d
7
+ data.tar.gz: 02bbc800a21396c6f106b2c18df5eee2f7247d43fac80da656496d4a8ec6a50c8d9438bb3514d13b57647f29aebfb1caf1e633a79d97eb37e30ae6bbb2634ecd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.2.0 (23-Feb-22)
4
+
5
+ * Use ruby-lokalise-api v5
6
+ * Don't use any compression options (compression is now enabled by default)
7
+ * Update tests
8
+
9
+ ## 2.1.0 (27-Jan-22)
10
+
11
+ * **Breaking change**: `export!` will now return an array of objects responding to the following methods:
12
+ + `success` — usually returns `true` (to learn more, check documentation for the `:raise_on_export_fail` option below)
13
+ + `process` — returns an object (an instance of the `Lokalise::Resources::QueuedProcess`) representing a [queued background process](https://lokalise.github.io/ruby-lokalise-api/api/queued-processes) as uploading is done in the background on Lokalise. You can use this object to check the process status (whether the uploading is completed or not).
14
+ + `path` — returns an instance of the `Pathname` class which represent the file being uploaded.
15
+ * Here's an example:
16
+
17
+ ```ruby
18
+ def uploaded?(process)
19
+ 5.times do # try to check the status 5 times
20
+ process = process.reload_data # load new data
21
+ return(true) if process.status == 'finished' # return true is the upload has finished
22
+ sleep 1 # wait for 1 second, adjust this number with regards to the upload size
23
+ end
24
+
25
+ false # if all 5 checks failed, return false (probably something is wrong)
26
+ end
27
+
28
+ processes = exporter.export!
29
+ puts "Checking status for the #{processes[0].path} file"
30
+ uploaded? processes[0].process
31
+ ```
32
+
33
+ * Introduced a new option `raise_on_export_fail` (`boolean`) which is `true` by default. When this option is enabled, LokaliseManager will re-raise any exceptions that happened during the file uploading. When this option is disabled, the exporting process will continue even if something goes wrong. In this case you'll probably need to check the result yourself and make the necessary actions. For example:
34
+
35
+ ```ruby
36
+ processes = exporter.export!
37
+
38
+ processes.each do |proc_data|
39
+ if proc_data.success
40
+ # Everything is good, the uploading is queued
41
+ puts "#{proc_data.path} is sent to Lokalise!"
42
+ process = proc_data.process
43
+ puts "Current process status is #{process.status}"
44
+ else
45
+ # Something bad has happened
46
+ puts "Could not send #{proc_data.path} to Lokalise"
47
+ puts "Error #{proc_data.error.class}: #{proc_data.error.message}"
48
+ # Or you could re-raise this exception:
49
+ # raise proc_data.error.class
50
+ end
51
+ end
52
+ ```
53
+
54
+ ## 2.0.0 (27-Jan-22)
55
+
56
+ * `export!` method is now taking advantage of multi-threading (as Lokalise API allows to send requests in parallel since January 2022)
57
+ * Test with Ruby 3.1.0
58
+ * Other minor fixes
59
+
3
60
  ## 1.2.1 (26-Nov-21)
4
61
 
5
62
  * Use refinements instead of monkey patching to add hash methods
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
- [![Build Status](https://travis-ci.com/bodrovis/lokalise_manager.svg?branch=master)](https://travis-ci.com/github/bodrovis/lokalise_manager)
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
 
@@ -43,7 +43,7 @@ importer = LokaliseManager.importer api_token: '1234abc', project_id: '123.abc'
43
43
  exporter = LokaliseManager.exporter api_token: '1234abc', project_id: '123.abc'
44
44
  ```
45
45
 
46
- You *must* provide an API token and a project ID (your project ID can be found under Lokalise project settings). [Other options can be customized as well (see below)](https://github.com/bodrovis/lokalise_manager#configuration) but they have sensible defaults.
46
+ You *must* provide an API token and a project ID (your project ID can be found under Lokalise project settings). [Other options can be customized as well (see below)](#configuration) but they have sensible defaults.
47
47
 
48
48
  ### Importing files from Lokalise into your project
49
49
 
@@ -55,7 +55,7 @@ result = importer.import!
55
55
 
56
56
  The `result` will contain a boolean value which says whether the operation was successfull or not.
57
57
 
58
- Please note that upon importing translations any duplicating files inside the `locales` directory (or any other directory that you've specified in the options) will be overwritten! You can enable [safe mode](https://github.com/bodrovis/lokalise_manager#import-config) to check whether the folder is empty or not.
58
+ Please note that upon importing translations any duplicating files inside the `locales` directory (or any other directory that you've specified in the options) **will be overwritten**! You can enable [safe mode](#import-config) to check whether the folder is empty or not.
59
59
 
60
60
  ### Exporting files from your project to Lokalise
61
61
 
@@ -65,13 +65,21 @@ To upload your translation files from a local directory (defaults to `locales/`)
65
65
  processes = exporter.export!
66
66
  ```
67
67
 
68
- `processes` will contain an array of queued background processes as uploading is done in the background on Lokalise. You can perform periodic checks to read the status of the process. Here's a very simple example:
68
+ The uploading process is multi-threaded.
69
+
70
+ `processes` will contain an array of objects responding to the following methods:
71
+
72
+ * `#success` — usually returns `true` (to learn more, check documentation for the `:raise_on_export_fail` option below)
73
+ * `#process` — returns an object (an instance of the `Lokalise::Resources::QueuedProcess`) representing a [queued background process](https://lokalise.github.io/ruby-lokalise-api/api/queued-processes) as uploading is done in the background on Lokalise.
74
+ * `#path` — returns an instance of the `Pathname` class which represent the file being uploaded.
75
+
76
+ You can perform periodic checks to read the status of the process. Here's a very simple example:
69
77
 
70
78
  ```ruby
71
79
  def uploaded?(process)
72
80
  5.times do # try to check the status 5 times
73
- process = process.reload_data # load new data
74
- return(true) if process.status == 'finished' # return true is the upload has finished
81
+ process = process.reload_data # load new info about this process
82
+ return(true) if process.status == 'finished' # return true if the upload has finished
75
83
  sleep 1 # wait for 1 second, adjust this number with regards to the upload size
76
84
  end
77
85
 
@@ -79,7 +87,8 @@ def uploaded?(process)
79
87
  end
80
88
 
81
89
  processes = exporter.export!
82
- uploaded? processes[0]
90
+ puts "Checking status for the #{processes[0].path} file"
91
+ uploaded? processes[0].process
83
92
  ```
84
93
 
85
94
  Please don't forget that Lokalise API has rate limiting and you cannot send more than six requests per second.
@@ -162,7 +171,29 @@ In this case the `export_opts` will have `detect_icu_plurals` set to `true` and
162
171
  c.skip_file_export = ->(file) { f.split[1].to_s.include?('fr') }
163
172
  ```
164
173
 
165
- * `max_retries_export` (`integer`) — this option is introduced to properly handle Lokalise API rate limiting. If the HTTP status code 429 (too many requests) has been received, LokaliseRails will apply an exponential backoff mechanism with a very simple formula: `2 ** retries` (initially `retries` is `0`). If the maximum number of retries has been reached, a `Lokalise::Error::TooManyRequests` exception will be raised and the export operation will be halted. By default, LokaliseRails will make up to `5` retries which potentially means `1 + 2 + 4 + 8 + 16 + 32 = 63` seconds of waiting time. If the `max_retries_export` is less than `1`, LokaliseRails will not perform any retries and give up immediately after receiving error 429.
174
+ * `max_retries_export` (`integer`) — this option is introduced to properly handle Lokalise API rate limiting. If the HTTP status code 429 (too many requests) has been received, LokaliseManager will apply an exponential backoff mechanism with a very simple formula: `2 ** retries` (initially `retries` is `0`). If the maximum number of retries has been reached, a `Lokalise::Error::TooManyRequests` exception will be raised and the export operation will be halted. By default, LokaliseManager will make up to `5` retries which potentially means `1 + 2 + 4 + 8 + 16 + 32 = 63` seconds of waiting time. If the `max_retries_export` is less than `1`, LokaliseManager will not perform any retries and give up immediately after receiving error 429.
175
+ * `raise_on_export_fail` (`boolean`) — default is `true`. When this option is enabled, LokaliseManager will re-raise any exceptions that happened during the file uploading. In other words, if any uploading thread raised an exception, your exporting process will exit with an exception. Suppose, you are uploading 12 translation files; these files will be split in 2 groups with 6 files each, and each group will be uploaded in parallel (using threads). However, suppose some exception happens when uploading the first group. By default this exception will be re-raised for the whole process and the script will never try to upload the second group. If you would like to continue uploading even if an exception happened, set the `raise_on_export_fail` to `false`. In this case the `export!` method will return an array with scheduled processes and with information about processes that were not successfully scheduled. This information is represented as an object with three methods: `path` (contains an instance of the `Pathname` class which says which file could not be uploaded), `error` (the actual exception), and `success` (returns `false`). So, you can use the following snippet to check your processes:
176
+
177
+ ```ruby
178
+ processes = exporter.export!
179
+
180
+ processes.each do |proc_data|
181
+ if proc_data.success
182
+ # Everything is good, the uploading is queued
183
+ puts "#{proc_data.path} is sent to Lokalise!"
184
+ process = proc_data.process
185
+ puts "Current process status is #{process.status}"
186
+ else
187
+ # Something bad has happened
188
+ puts "Could not send #{proc_data.path} to Lokalise"
189
+ puts "Error #{proc_data.error.class}: #{proc_data.error.message}"
190
+ # Or you could re-raise this exception:
191
+ # raise proc_data.error.class
192
+ end
193
+ end
194
+ ```
195
+
196
+ * For example, you could collect all the files that were uploaded successfully, re-create the exporter object with the `skip_file_export` option (skipping all files that were successfully imported), and re-run the whole exporting process once again.
166
197
 
167
198
  ### Config to work with formats other than YAML
168
199
 
@@ -193,7 +224,7 @@ importer = LokaliseManager.importer api_token: '1234abc',
193
224
 
194
225
  These options will be merged with the default ones. Please note that per-client config has the highest priority.
195
226
 
196
- You can also adjust individual options later using the `#config` instance variable (it contains an OpenStruct object):
227
+ You can also adjust individual options later using the `#config` instance variable (it contains a Struct object):
197
228
 
198
229
  ```
199
230
  importer.config.project_id = '678xyz'
@@ -271,4 +302,4 @@ importer.import!
271
302
 
272
303
  ## License
273
304
 
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).
305
+ 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,19 @@ 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, :use_oauth2_token, :silent_mode
10
+ :max_retries_export, :max_retries_import, :use_oauth2_token, :silent_mode,
11
+ :raise_on_export_fail
11
12
 
12
13
  # Main interface to provide configuration options
13
14
  def config
14
15
  yield self
15
16
  end
16
17
 
18
+ # When enabled, will re-raise any exception that happens during file exporting
19
+ def raise_on_export_fail
20
+ @raise_on_export_fail || true
21
+ end
22
+
17
23
  # When enabled, won't print any debugging info to $stdout
18
24
  def silent_mode
19
25
  @silent_mode || false
@@ -35,15 +35,16 @@ module LokaliseManager
35
35
  #
36
36
  # @return [Lokalise::Client]
37
37
  def api_client
38
- client_opts = [config.api_token, {enable_compression: true}.merge(config.timeouts)]
39
- client_method = config.use_oauth2_token ? :oauth_client : :client
38
+ client_opts = [config.api_token, config.timeouts]
39
+ client_method = config.use_oauth2_token ? :oauth2_client : :client
40
40
 
41
- @api_client ||= ::Lokalise.send(client_method, *client_opts)
41
+ @api_client = ::Lokalise.send(client_method, *client_opts)
42
42
  end
43
43
 
44
44
  # Resets API client
45
45
  def reset_api_client!
46
- Lokalise.reset_client!
46
+ ::Lokalise.reset_client!
47
+ ::Lokalise.reset_oauth2_client!
47
48
  @api_client = nil
48
49
  end
49
50
 
@@ -5,6 +5,9 @@ require 'base64'
5
5
  module LokaliseManager
6
6
  module TaskDefinitions
7
7
  class Exporter < Base
8
+ # Lokalise allows no more than 6 requests per second
9
+ MAX_THREADS = 6
10
+
8
11
  # Performs translation file export to Lokalise and returns an array of queued processes
9
12
  #
10
13
  # @return [Array]
@@ -12,10 +15,13 @@ module LokaliseManager
12
15
  check_options_errors!
13
16
 
14
17
  queued_processes = []
15
- each_file do |full_path, relative_path|
16
- queued_processes << do_upload(full_path, relative_path)
17
- rescue StandardError => e
18
- raise e.class, "Error while trying to upload #{full_path}: #{e.message}"
18
+
19
+ all_files.each_slice(MAX_THREADS) do |files_group|
20
+ parallel_upload(files_group).each do |thr|
21
+ raise_on_fail(thr) if config.raise_on_export_fail
22
+
23
+ queued_processes.push thr
24
+ end
19
25
  end
20
26
 
21
27
  $stdout.print('Task complete!') unless config.silent_mode
@@ -25,28 +31,43 @@ module LokaliseManager
25
31
 
26
32
  private
27
33
 
34
+ def parallel_upload(files_group)
35
+ files_group.map do |file_data|
36
+ do_upload(*file_data)
37
+ end.map(&:value)
38
+ end
39
+
40
+ def raise_on_fail(thread)
41
+ raise(thread.error.class, "Error while trying to upload #{thread.path}: #{thread.error.message}") unless thread.success
42
+ end
43
+
28
44
  # Performs the actual file uploading to Lokalise. If the API rate limit is exceeed,
29
45
  # applies exponential backoff
30
46
  def do_upload(f_path, r_path)
31
- with_exp_backoff(config.max_retries_export) do
32
- api_client.upload_file project_id_with_branch, opts(f_path, r_path)
47
+ proc_klass = Struct.new(:success, :process, :path, :error, keyword_init: true)
48
+
49
+ Thread.new do
50
+ process = with_exp_backoff(config.max_retries_export) do
51
+ api_client.upload_file project_id_with_branch, opts(f_path, r_path)
52
+ end
53
+ proc_klass.new success: true, process: process, path: f_path
54
+ rescue StandardError => e
55
+ proc_klass.new success: false, path: f_path, error: e
33
56
  end
34
57
  end
35
58
 
36
- # Processes each translation file in the specified directory
37
- def each_file
38
- return unless block_given?
39
-
59
+ # Gets translation files from the specified directory
60
+ def all_files
40
61
  loc_path = config.locales_path
41
- Dir["#{loc_path}/**/*"].sort.each do |f|
62
+ Dir["#{loc_path}/**/*"].map do |f|
42
63
  full_path = Pathname.new f
43
64
 
44
65
  next unless file_matches_criteria? full_path
45
66
 
46
67
  relative_path = full_path.relative_path_from Pathname.new(loc_path)
47
68
 
48
- yield full_path, relative_path
49
- end
69
+ [full_path, relative_path]
70
+ end.compact
50
71
  end
51
72
 
52
73
  # Generates export options
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseManager
4
- VERSION = '1.2.1'
4
+ VERSION = '2.2.0'
5
5
  end
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.extra_rdoc_files = ['README.md']
24
24
  spec.require_paths = ['lib']
25
25
 
26
- spec.add_dependency 'ruby-lokalise-api', '~> 4.0'
26
+ spec.add_dependency 'ruby-lokalise-api', '~> 5.0'
27
27
  spec.add_dependency 'rubyzip', '~> 2.3'
28
28
 
29
29
  spec.add_development_dependency 'codecov', '~> 0.2'
@@ -32,7 +32,7 @@ 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.6.0'
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
38
  spec.metadata = {
@@ -14,6 +14,11 @@ describe LokaliseManager::GlobalConfig do
14
14
  fake_class.project_id = '123.abc'
15
15
  end
16
16
 
17
+ it 'is possible to set raise_on_export_fail' do
18
+ allow(fake_class).to receive(:raise_on_export_fail=).with(false)
19
+ fake_class.raise_on_export_fail = false
20
+ end
21
+
17
22
  it 'is possible to set silent_mode' do
18
23
  allow(fake_class).to receive(:silent_mode=).with(true)
19
24
  fake_class.silent_mode = true
@@ -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 '@api_client'
27
+ current_client = described_object.instance_variable_get :@api_client
28
28
  expect(current_client).to be_nil
29
29
  end
30
30
 
@@ -63,14 +63,14 @@ describe LokaliseManager::TaskDefinitions::Base do
63
63
  it 'raises an error when the API key is not set' do
64
64
  allow(LokaliseManager::GlobalConfig).to receive(:api_token).and_return(nil)
65
65
 
66
- expect(-> { described_object.send(:check_options_errors!) }).to raise_error(LokaliseManager::Error, /API token is not set/i)
66
+ expect { described_object.send(:check_options_errors!) }.to raise_error(LokaliseManager::Error, /API token is not set/i)
67
67
 
68
68
  expect(LokaliseManager::GlobalConfig).to have_received(:api_token)
69
69
  end
70
70
 
71
71
  it 'returns an error when the project_id is not set' do
72
72
  allow_project_id described_object, nil do
73
- expect(-> { described_object.send(:check_options_errors!) }).to raise_error(LokaliseManager::Error, /ID is not set/i)
73
+ expect { described_object.send(:check_options_errors!) }.to raise_error(LokaliseManager::Error, /ID is not set/i)
74
74
  end
75
75
  end
76
76
  end
@@ -96,7 +96,7 @@ describe LokaliseManager::TaskDefinitions::Base do
96
96
 
97
97
  client = described_object.api_client
98
98
  expect(client).to be_an_instance_of(Lokalise::Client)
99
- expect(client).not_to be_an_instance_of(Lokalise::OAuthClient)
99
+ expect(client).not_to be_an_instance_of(Lokalise::OAuth2Client)
100
100
  expect(client.open_timeout).to eq(100)
101
101
  expect(client.timeout).to eq(500)
102
102
  end
@@ -106,7 +106,7 @@ describe LokaliseManager::TaskDefinitions::Base do
106
106
 
107
107
  client = described_object.api_client
108
108
 
109
- expect(client).to be_an_instance_of(Lokalise::OAuthClient)
109
+ expect(client).to be_an_instance_of(Lokalise::OAuth2Client)
110
110
  expect(client).not_to be_an_instance_of(Lokalise::Client)
111
111
  end
112
112
  end
@@ -27,7 +27,7 @@ describe LokaliseManager::TaskDefinitions::Exporter do
27
27
  process = nil
28
28
 
29
29
  VCR.use_cassette('upload_files_multiple') do
30
- expect(-> { process = described_object.export!.first }).to output(/complete!/).to_stdout
30
+ expect { process = described_object.export!.first.process }.to output(/complete!/).to_stdout
31
31
  end
32
32
 
33
33
  expect(process.project_id).to eq(project_id)
@@ -35,17 +35,40 @@ describe LokaliseManager::TaskDefinitions::Exporter do
35
35
  end
36
36
 
37
37
  it 'handles too many requests' do
38
+ allow(described_object.config).to receive(:max_retries_export).and_return(1)
38
39
  allow(described_object).to receive(:sleep).and_return(0)
39
40
 
40
41
  fake_client = instance_double('Lokalise::Client')
42
+ allow(fake_client).to receive(:token).with(any_args).and_return('fake_token')
41
43
  allow(fake_client).to receive(:upload_file).with(any_args).and_raise(Lokalise::Error::TooManyRequests)
42
44
  allow(described_object).to receive(:api_client).and_return(fake_client)
43
45
 
44
- expect(-> { described_object.export! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 2 retries/i)
46
+ expect { described_object.export! }.to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 1 retries/i)
45
47
 
46
- expect(described_object).to have_received(:sleep).exactly(2).times
47
- expect(described_object).to have_received(:api_client).exactly(3).times
48
- expect(fake_client).to have_received(:upload_file).exactly(3).times
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
51
+ end
52
+
53
+ it 'handles too many requests but does not re-raise anything when raise_on_export_fail is false' do
54
+ allow(described_object.config).to receive(:max_retries_export).and_return(1)
55
+ allow(described_object.config).to receive(:raise_on_export_fail).and_return(false)
56
+ allow(described_object).to receive(:sleep).and_return(0)
57
+
58
+ fake_client = instance_double('Lokalise::Client')
59
+ allow(fake_client).to receive(:token).with(any_args).and_return('fake_token')
60
+ allow(fake_client).to receive(:upload_file).with(any_args).and_raise(Lokalise::Error::TooManyRequests)
61
+ allow(described_object).to receive(:api_client).and_return(fake_client)
62
+ processes = []
63
+ expect { processes = described_object.export! }.not_to raise_error
64
+
65
+ expect(processes[0].success).to be false
66
+ expect(processes[1].error.class).to eq(Lokalise::Error::TooManyRequests)
67
+ expect(processes.count).to eq(7)
68
+
69
+ expect(described_object).to have_received(:sleep).exactly(7).times
70
+ expect(described_object).to have_received(:api_client).at_least(14).times
71
+ expect(fake_client).to have_received(:upload_file).exactly(14).times
49
72
  end
50
73
  end
51
74
  end
@@ -66,7 +89,7 @@ describe LokaliseManager::TaskDefinitions::Exporter do
66
89
  process = nil
67
90
 
68
91
  VCR.use_cassette('upload_files') do
69
- expect(-> { process = described_object.export!.first }).not_to output(/complete!/).to_stdout
92
+ expect { process = described_object.export!.first.process }.not_to output(/complete!/).to_stdout
70
93
  end
71
94
 
72
95
  expect(process.status).to eq('queued')
@@ -76,7 +99,7 @@ describe LokaliseManager::TaskDefinitions::Exporter do
76
99
  it 'sends a proper API request' do
77
100
  process = VCR.use_cassette('upload_files') do
78
101
  described_object.export!
79
- end.first
102
+ end.first.process
80
103
 
81
104
  expect(process.project_id).to eq(project_id)
82
105
  expect(process.status).to eq('queued')
@@ -85,11 +108,16 @@ describe LokaliseManager::TaskDefinitions::Exporter do
85
108
  it 'sends a proper API request when a different branch is provided' do
86
109
  allow(described_object.config).to receive(:branch).and_return('develop')
87
110
 
88
- process = VCR.use_cassette('upload_files_branch') do
111
+ process_data = VCR.use_cassette('upload_files_branch') do
89
112
  described_object.export!
90
113
  end.first
91
114
 
92
115
  expect(described_object.config).to have_received(:branch).at_most(2).times
116
+ expect(process_data.success).to be true
117
+ expect(process_data.path.to_s).to include('en.yml')
118
+
119
+ process = process_data.process
120
+ expect(process).to be_an_instance_of(Lokalise::Resources::QueuedProcess)
93
121
  expect(process.project_id).to eq(project_id)
94
122
  expect(process.status).to eq('queued')
95
123
  end
@@ -97,20 +125,20 @@ describe LokaliseManager::TaskDefinitions::Exporter do
97
125
  it 'halts when the API key is not set' do
98
126
  allow(described_object.config).to receive(:api_token).and_return(nil)
99
127
 
100
- expect(-> { described_object.export! }).to raise_error(LokaliseManager::Error, /API token is not set/i)
128
+ expect { described_object.export! }.to raise_error(LokaliseManager::Error, /API token is not set/i)
101
129
  expect(described_object.config).to have_received(:api_token)
102
130
  end
103
131
 
104
132
  it 'halts when the project_id is not set' do
105
133
  allow_project_id described_object, nil do
106
- expect(-> { described_object.export! }).to raise_error(LokaliseManager::Error, /ID is not set/i)
134
+ expect { described_object.export! }.to raise_error(LokaliseManager::Error, /ID is not set/i)
107
135
  end
108
136
  end
109
137
  end
110
138
 
111
- describe '.each_file' do
139
+ describe '#all_files' do
112
140
  it 'yield proper arguments' do
113
- expect { |b| described_object.send(:each_file, &b) }.to yield_with_args(
141
+ expect(described_object.send(:all_files).flatten).to include(
114
142
  Pathname.new(path),
115
143
  Pathname.new(relative_name)
116
144
  )
@@ -180,30 +208,29 @@ describe LokaliseManager::TaskDefinitions::Exporter do
180
208
  end
181
209
  end
182
210
 
183
- describe '.each_file' do
184
- it 'yields every translation file' do
185
- expect { |b| described_object.send(:each_file, &b) }.to yield_successive_args(
186
- [
187
- Pathname.new(path),
188
- Pathname.new(relative_name)
189
- ],
190
- [
191
- Pathname.new(path_ru),
192
- Pathname.new(filename_ru)
193
- ]
211
+ describe '#all_files' do
212
+ it 'returns all files' do
213
+ files = described_object.send(:all_files).flatten
214
+ expect(files).to include(
215
+ Pathname.new(path),
216
+ Pathname.new(relative_name)
217
+ )
218
+ expect(files).to include(
219
+ Pathname.new(path_ru),
220
+ Pathname.new(filename_ru)
194
221
  )
195
222
  end
196
223
 
197
- it 'does not yield files that have to be skipped' do
224
+ it 'does not return files that have to be skipped' do
198
225
  allow(described_object.config).to receive(:skip_file_export).twice.and_return(
199
226
  ->(f) { f.split[1].to_s.include?('ru') }
200
227
  )
201
- expect { |b| described_object.send(:each_file, &b) }.to yield_successive_args(
202
- [
203
- Pathname.new(path),
204
- Pathname.new(relative_name)
205
- ]
228
+ files = described_object.send(:all_files).sort
229
+ expect(files[0]).to include(
230
+ Pathname.new(path),
231
+ Pathname.new(relative_name)
206
232
  )
233
+ expect(files.count).to eq(1)
207
234
 
208
235
  expect(described_object.config).to have_received(:skip_file_export).twice
209
236
  end
@@ -9,21 +9,25 @@ 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 '.open_and_process_zip' do
13
+ describe '#open_and_process_zip' do
15
14
  it 're-raises errors during file processing' do
16
- expect(-> { described_object.send(:open_and_process_zip, faulty_trans) }).
17
- to raise_error(Psych::DisallowedClass, /Error when trying to process fail\.yml/)
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
21
- expect(-> { described_object.send(:open_and_process_zip, 'http://fake.url/wrong/path.zip') }).
25
+ expect { described_object.send(:open_and_process_zip, 'http://fake.url/wrong/path.zip') }.
22
26
  to raise_error(SocketError, /Failed to open TCP connection/)
23
27
  end
24
28
  end
25
29
 
26
- describe '.download_files' do
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
@@ -31,14 +35,13 @@ describe LokaliseManager::TaskDefinitions::Importer do
31
35
 
32
36
  expect(response['project_id']).to eq('672198945b7d72fc048021.15940510')
33
37
  expect(response['bundle_url']).to include('s3-eu-west-1.amazonaws.com')
34
- expect(described_object.api_client.enable_compression).to eq(true)
35
38
  end
36
39
 
37
40
  it 're-raises errors during file download' do
38
41
  allow_project_id described_object, 'invalid'
39
42
 
40
43
  VCR.use_cassette('download_files_error') do
41
- expect(-> { described_object.send :download_files }).
44
+ expect { described_object.send :download_files }.
42
45
  to raise_error(Lokalise::Error::BadRequest, /Invalid `project_id` parameter/)
43
46
  end
44
47
  end
@@ -53,7 +56,7 @@ describe LokaliseManager::TaskDefinitions::Importer do
53
56
  allow(fake_client).to receive(:download_files).and_raise(Lokalise::Error::TooManyRequests)
54
57
  allow(described_object).to receive(:api_client).and_return(fake_client)
55
58
 
56
- expect(-> { described_object.import! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 2 retries/i)
59
+ expect { described_object.import! }.to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 2 retries/i)
57
60
 
58
61
  expect(described_object).to have_received(:sleep).exactly(2).times
59
62
  expect(described_object).to have_received(:api_client).exactly(3).times
@@ -62,14 +65,14 @@ describe LokaliseManager::TaskDefinitions::Importer do
62
65
 
63
66
  it 'halts when the API key is not set' do
64
67
  allow(described_object.config).to receive(:api_token).and_return(nil)
65
- expect(-> { described_object.import! }).to raise_error(LokaliseManager::Error, /API token is not set/i)
68
+ expect { described_object.import! }.to raise_error(LokaliseManager::Error, /API token is not set/i)
66
69
  expect(described_object.config).to have_received(:api_token)
67
70
  expect(count_translations).to eq(0)
68
71
  end
69
72
 
70
73
  it 'halts when the project_id is not set' do
71
74
  allow_project_id described_object, nil do
72
- expect(-> { described_object.import! }).to raise_error(LokaliseManager::Error, /ID is not set/i)
75
+ expect { described_object.import! }.to raise_error(LokaliseManager::Error, /ID is not set/i)
73
76
  expect(count_translations).to eq(0)
74
77
  end
75
78
  end
@@ -106,14 +109,14 @@ describe LokaliseManager::TaskDefinitions::Importer do
106
109
  result = nil
107
110
 
108
111
  VCR.use_cassette('import') do
109
- expect(-> { result = described_object.import! }).to output(/complete!/).to_stdout
112
+ expect { result = described_object.import! }.to output(/complete!/).to_stdout
110
113
  end
111
114
 
112
115
  expect(result).to be true
113
116
 
114
- expect(count_translations).to eq(8)
115
- expect_file_exist loc_path, 'en.yml'
116
- expect_file_exist loc_path, 'ru.yml'
117
+ expect(count_translations).to eq(24)
118
+ expect_file_exist loc_path, 'en_1.yml'
119
+ expect_file_exist loc_path, 'ru_2.yml'
117
120
  end
118
121
 
119
122
  it 'runs import successfully but does not provide any output when silent_mode is enabled' do
@@ -121,12 +124,12 @@ describe LokaliseManager::TaskDefinitions::Importer do
121
124
  result = nil
122
125
 
123
126
  VCR.use_cassette('import') do
124
- expect(-> { result = described_object.import! }).not_to output(/complete!/).to_stdout
127
+ expect { result = described_object.import! }.not_to output(/complete!/).to_stdout
125
128
  end
126
129
 
127
130
  expect(result).to be true
128
- expect_file_exist loc_path, 'en.yml'
129
- expect_file_exist loc_path, 'ru.yml'
131
+ expect_file_exist loc_path, 'en_1.yml'
132
+ expect_file_exist loc_path, 'ru_2.yml'
130
133
  expect(described_object.config).to have_received(:silent_mode).at_most(1).times
131
134
  end
132
135
  end
@@ -160,7 +163,7 @@ describe LokaliseManager::TaskDefinitions::Importer do
160
163
  )
161
164
 
162
165
  allow($stdin).to receive(:gets).and_return('Y')
163
- expect(-> { safe_mode_obj.import! }).to output(/is not empty/).to_stdout
166
+ expect { safe_mode_obj.import! }.to output(/is not empty/).to_stdout
164
167
 
165
168
  expect(count_translations).to eq(5)
166
169
  expect($stdin).to have_received(:gets)
@@ -173,7 +176,7 @@ describe LokaliseManager::TaskDefinitions::Importer do
173
176
  it 'import halts when a user chooses not to proceed' do
174
177
  allow(safe_mode_obj).to receive(:download_files).at_most(0).times
175
178
  allow($stdin).to receive(:gets).and_return('N')
176
- expect(-> { safe_mode_obj.import! }).to output(/cancelled/).to_stdout
179
+ expect { safe_mode_obj.import! }.to output(/cancelled/).to_stdout
177
180
 
178
181
  expect(safe_mode_obj).not_to have_received(:download_files)
179
182
  expect($stdin).to have_received(:gets)
@@ -184,7 +187,7 @@ describe LokaliseManager::TaskDefinitions::Importer do
184
187
  allow(safe_mode_obj.config).to receive(:silent_mode).and_return(true)
185
188
  allow(safe_mode_obj).to receive(:download_files).at_most(0).times
186
189
  allow($stdin).to receive(:gets).and_return('N')
187
- expect(-> { safe_mode_obj.import! }).not_to output(/cancelled/).to_stdout
190
+ expect { safe_mode_obj.import! }.not_to output(/cancelled/).to_stdout
188
191
 
189
192
  expect(safe_mode_obj).not_to have_received(:download_files)
190
193
  expect(safe_mode_obj.config).to have_received(:silent_mode)
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>') { ENV.fetch('LOKALISE_API_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: 1.2.1
4
+ version: 2.2.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: 2021-11-26 00:00:00.000000000 Z
11
+ date: 2022-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-lokalise-api
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.0'
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubyzip
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 2.6.0
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.6.0
138
+ version: '2.6'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: simplecov
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -220,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
222
  requirements: []
223
- rubygems_version: 3.2.31
223
+ rubygems_version: 3.3.7
224
224
  signing_key:
225
225
  specification_version: 4
226
226
  summary: Lokalise integration for Ruby