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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0640f0599d5b4967f79d2ced69f63d7cb7edde3e2a3a49336d08d17e5fb4c0f
4
- data.tar.gz: 0766d8cb7f6b478e427f8ef7dd1409d86072a74a4606b026eaa718f6fe4761b5
3
+ metadata.gz: 0f9ca0fe8caf151e84dcc09f29368bc61b5bc3cdb4341ef5c1b21040b764a17a
4
+ data.tar.gz: 8c9194a836a1261638f2b22d8d2d7553bfbe605325911cb0c0ecef9332e9084c
5
5
  SHA512:
6
- metadata.gz: 38a3adfcc0bf4a78f595547cdc3ba2962a4122d8bbeaa7e132d47dc4e76992711e653710a802e395fafcb0c316743607876a10f0914c2633472994891fd4850e
7
- data.tar.gz: 98b2edd83de044615db56ee71d090afa03fcfc7793c55854e322ab466996e0eb46c74f3b22dbdbd44e570f31746d40394912ba39c29dd17337b17e08d0417761
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
- [![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
 
@@ -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
- @config = OpenStruct.new primary_opts.merge(custom_opts)
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
- @api_client ||= ::Lokalise.client config.api_token, {enable_compression: true}.merge(config.timeouts)
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
- 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}"
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 'Task complete!'
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
- with_exp_backoff(config.max_retries_export) do
32
- api_client.upload_file project_id_with_branch, opts(f_path, r_path)
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
- # Processes each translation file in the specified directory
37
- def each_file
38
- return unless block_given?
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
- yield full_path, relative_path
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 'Task cancelled!'
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 'Task complete!'
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseManager
4
- VERSION = '1.0.0'
4
+ VERSION = '2.0.0'
5
5
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'yaml'
4
4
 
5
+ require 'lokalise_manager/utils/hash_utils'
6
+ require 'lokalise_manager/utils/array_utils'
7
+
5
8
  require 'lokalise_manager/version'
6
9
  require 'lokalise_manager/error'
7
10
  require 'lokalise_manager/global_config'
@@ -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.5.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
+ 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 '@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
 
@@ -94,9 +94,20 @@ describe LokaliseManager::TaskDefinitions::Base do
94
94
  timeout: 500
95
95
  })
96
96
 
97
- expect(described_object.api_client).to be_an_instance_of(Lokalise::Client)
98
- expect(described_object.api_client.open_timeout).to eq(100)
99
- expect(described_object.api_client.timeout).to eq(500)
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 = VCR.use_cassette('upload_files_multiple') do
28
- described_object.export!
29
- end.first
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 2 retries/i)
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(2).times
45
- expect(described_object).to have_received(:api_client).exactly(3).times
46
- 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
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 '.each_file' do
113
+ describe '#all_files' do
97
114
  it 'yield proper arguments' do
98
- expect { |b| described_object.send(:each_file, &b) }.to yield_with_args(
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 '.each_file' do
169
- it 'yields every translation file' do
170
- expect { |b| described_object.send(:each_file, &b) }.to yield_successive_args(
171
- [
172
- Pathname.new(path),
173
- Pathname.new(relative_name)
174
- ],
175
- [
176
- Pathname.new(path_ru),
177
- Pathname.new(filename_ru)
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 yield files that have to be skipped' do
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
- expect { |b| described_object.send(:each_file, &b) }.to yield_successive_args(
187
- [
188
- Pathname.new(path),
189
- Pathname.new(relative_name)
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 '.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
@@ -23,7 +27,7 @@ describe LokaliseManager::TaskDefinitions::Importer do
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
@@ -103,15 +107,31 @@ describe LokaliseManager::TaskDefinitions::Importer do
103
107
  end
104
108
 
105
109
  it 'runs import successfully' do
106
- result = VCR.use_cassette('import') do
107
- described_object.import!
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(8)
113
- expect_file_exist loc_path, 'en.yml'
114
- expect_file_exist loc_path, 'ru.yml'
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(/is not empty/).to_stdout
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>') { 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.0.0
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: 2021-10-14 00:00:00.000000000 Z
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.5.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.5.0
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.2.26
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