lokalise_rails 1.3.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: c7c3c99beec724dff9ae92477d8e710119f0b7b2e7f4cbaa19487687eab39328
4
- data.tar.gz: 74e0368d48cd5dfed11d1b442bbea1d03748808fcb827b52bdaef7c0ae6e6fca
3
+ metadata.gz: 9ac898ae13038db9d3426f367e3cba3b54c41e35797dfb56dd5da5595959e728
4
+ data.tar.gz: 2bf9f24929b226b8994b3f4648f67b5da59aa0b68687cb7f597f531ac2d7bb99
5
5
  SHA512:
6
- metadata.gz: 1c95761a6a14d37a19d42a97f9526f42d54738cdd3cdf3e8a8e79e04dace1bbbe705723f5a23ecd3476d7c202252d7910d7e1a633116f9fc0b70082f56814aaf
7
- data.tar.gz: 937ae8358ce78c48ca50e189f38bf92369e669a94aed55e9c57d7633b7a32900452b26ebee13c142873186f0644a288307de29375894c3745f75abad1ab07f3d
6
+ metadata.gz: 93be5d1f8379908fbf6e3ac7a1f44534373779d8aa3e375f456ef7a83454a07babe3971aa364afe374759e54571d036c60c68e16f14c81397128770573058a9a
7
+ data.tar.gz: 84c42e122da897f7103a16d11e9a5e066cee28c2b6413c44ec3e459868dfe89d8c5005f3fa644024bea7dfd7c49233de5fecc67746016485f467febe91b3fa52
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0 (19-Aug-21)
4
+
5
+ * Add exponential backoff mechanism for file imports to comply with the upcoming API changes ("rate limiting"), see below for more details.
6
+ * Add `max_retries_import` option with a default value of `5`.
7
+
8
+ ## 2.0.0.rc1 (12-Aug-21)
9
+
10
+ * **Lokalise is introducing API rate limiting.** Access to all endpoints will be limited to 6 requests per second from 14 September, 2021. This limit is applied per API token and per IP address. If you exceed the limit, a 429 HTTP status code will be returned and a `Lokalise::Error::TooManyRequests` exception will be raised. Therefore, to overcome this issue LokaliseRails is introducing an exponential backoff mechanism for file exports. Why? Because if you have, say, 10 translation files, we'll have to send 10 separate API requests which will probably mean exceeding the limit (this is not the case with importing as we're always receiving a single archive). Thus, if the HTTP status code 429 was received, we'll do the following:
11
+
12
+ ```ruby
13
+ sleep 2 ** retries
14
+ retries += 1
15
+ ```
16
+
17
+ * If the maximum number of retries has been reached LokaliseRails will re-raise the `Lokalise::Error::TooManyRequests` error and give up. By default, the maximum number of retries is set to `5` but you can control it using the `max_retries_export` option.
18
+ * Enabled compression for the API client.
19
+
20
+ ## 1.4.0 (29-Jun-21)
21
+
22
+ * Re-worked exception handling. Now when something goes wrong during the import or export process, this gem will re-raise all such errors (previously it just printed out some errors to the `$stdout`). If you run a Rake task, it will exit with a status code `1` and the actual error message. If you run a task programattically, you'll get an exception.
23
+ * Dropped support for Ruby 2.5
24
+ * Test against Ruby 3
25
+
26
+ ## 1.3.1 (01-Apr-21)
27
+
28
+ * A bit better exception handling
29
+ * Update dependencies
30
+
3
31
  ## 1.3.0 (02-Feb-21)
4
32
 
5
33
  * Use ruby-lokalise-api v3
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  ![Gem](https://img.shields.io/gem/v/lokalise_rails)
4
4
  [![Build Status](https://travis-ci.com/bodrovis/lokalise_rails.svg?branch=master)](https://travis-ci.com/github/bodrovis/lokalise_rails)
5
5
  [![Test Coverage](https://codecov.io/gh/bodrovis/lokalise_rails/graph/badge.svg)](https://codecov.io/gh/bodrovis/lokalise_rails)
6
+ ![Downloads total](https://img.shields.io/gem/dt/lokalise_rails)
6
7
 
7
8
  This gem provides [Lokalise](http://lokalise.com) integration for Ruby on Rails and allows to exchange translation files easily. It relies on [ruby-lokalise-api](https://lokalise.github.io/ruby-lokalise-api) to send APIv2 requests.
8
9
 
@@ -112,6 +113,7 @@ Options are specified in the `config/lokalise_rails.rb` file.
112
113
 
113
114
  Full list of available import options [can be found in the official API documentation](https://app.lokalise.com/api2docs/curl/#transition-download-files-post).
114
115
  * `import_safe_mode` (`boolean`) - default to `false`. When this option is enabled, the import task will check whether the directory set with `locales_path` is empty or not. If it is not empty, you will be prompted to continue.
116
+ * `max_retries_import` (`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`. If the maximum number of retries has been reached, a `Lokalise::Error::TooManyRequests` exception will be raised and the export operation will be halted.
115
117
 
116
118
  ### Export settings
117
119
 
@@ -133,6 +135,8 @@ en_US:
133
135
  c.skip_file_export = ->(file) { f.split[1].to_s.include?('fr') }
134
136
  ```
135
137
 
138
+ * `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.
139
+
136
140
  ### Settings to work with formats other than YAML
137
141
 
138
142
  If your translation files are not in YAML format, you will need to adjust the following options:
@@ -16,6 +16,12 @@ LokaliseRails.config do |c|
16
16
  # Provide request timeouts for the Lokalise API client:
17
17
  # c.timeouts = {open_timeout: nil, timeout: nil}
18
18
 
19
+ # Provide maximum number of retries for file exporting:
20
+ # c.max_retries_export = 5
21
+
22
+ # Provide maximum number of retries for file importing:
23
+ # c.max_retries_import = 5
24
+
19
25
  # Import options have the following defaults:
20
26
  # c.import_opts = {
21
27
  # format: 'yaml',
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'lokalise_rails/error'
3
4
  require 'lokalise_rails/task_definition/base'
4
5
  require 'lokalise_rails/task_definition/importer'
5
6
  require 'lokalise_rails/task_definition/exporter'
@@ -9,7 +10,8 @@ module LokaliseRails
9
10
  attr_accessor :api_token, :project_id
10
11
  attr_writer :import_opts, :import_safe_mode, :export_opts, :locales_path,
11
12
  :file_ext_regexp, :skip_file_export, :branch, :timeouts,
12
- :translations_loader, :translations_converter, :lang_iso_inferer
13
+ :translations_loader, :translations_converter, :lang_iso_inferer,
14
+ :max_retries_export, :max_retries_import
13
15
 
14
16
  # Main interface to provide configuration options for rake tasks
15
17
  def config
@@ -31,6 +33,16 @@ module LokaliseRails
31
33
  @timeouts || {}
32
34
  end
33
35
 
36
+ # Maximum number of retries for file exporting
37
+ def max_retries_export
38
+ @max_retries_export || 5
39
+ end
40
+
41
+ # Maximum number of retries for file importing
42
+ def max_retries_import
43
+ @max_retries_import || 5
44
+ end
45
+
34
46
  # Regular expression used to select translation files with proper extensions
35
47
  def file_ext_regexp
36
48
  @file_ext_regexp || /\.ya?ml\z/i
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseRails
4
+ class Error < StandardError
5
+ # Initializes a new Error object
6
+ def initialize(message = '')
7
+ super(message)
8
+ end
9
+ end
10
+ end
@@ -13,7 +13,7 @@ module LokaliseRails
13
13
  #
14
14
  # @return [Lokalise::Client]
15
15
  def api_client
16
- @api_client ||= ::Lokalise.client LokaliseRails.api_token, LokaliseRails.timeouts
16
+ @api_client ||= ::Lokalise.client LokaliseRails.api_token, {enable_compression: true}.merge(LokaliseRails.timeouts)
17
17
  end
18
18
 
19
19
  # Resets API client
@@ -25,11 +25,12 @@ module LokaliseRails
25
25
  # Checks task options
26
26
  #
27
27
  # @return Array
28
- def opt_errors
28
+ def check_options_errors!
29
29
  errors = []
30
- errors << 'Project ID is not set! Aborting...' if LokaliseRails.project_id.nil? || LokaliseRails.project_id.empty?
31
- errors << 'Lokalise API token is not set! Aborting...' if LokaliseRails.api_token.nil? || LokaliseRails.api_token.empty?
32
- errors
30
+ errors << 'Project ID is not set!' if LokaliseRails.project_id.nil? || LokaliseRails.project_id.empty?
31
+ errors << 'Lokalise API token is not set!' if LokaliseRails.api_token.nil? || LokaliseRails.api_token.empty?
32
+
33
+ raise(LokaliseRails::Error, errors.join(' ')) if errors.any?
33
34
  end
34
35
 
35
36
  private
@@ -57,6 +58,22 @@ module LokaliseRails
57
58
  def project_id_with_branch
58
59
  "#{LokaliseRails.project_id}:#{LokaliseRails.branch}"
59
60
  end
61
+
62
+ # Sends request with exponential backoff mechanism
63
+ def with_exp_backoff(max_retries)
64
+ return unless block_given?
65
+
66
+ retries = 0
67
+ begin
68
+ yield
69
+ rescue Lokalise::Error::TooManyRequests => e
70
+ raise(e.class, "Gave up after #{retries} retries") if retries >= max_retries
71
+
72
+ sleep 2**retries
73
+ retries += 1
74
+ retry
75
+ end
76
+ end
60
77
  end
61
78
  end
62
79
  end
@@ -10,20 +10,13 @@ module LokaliseRails
10
10
  #
11
11
  # @return [Array]
12
12
  def export!
13
- errors = opt_errors
14
-
15
- if errors.any?
16
- errors.each { |e| $stdout.puts e }
17
- return errors
18
- end
13
+ check_options_errors!
19
14
 
20
15
  queued_processes = []
21
16
  each_file do |full_path, relative_path|
22
- queued_processes << api_client.upload_file(
23
- project_id_with_branch, opts(full_path, relative_path)
24
- )
17
+ queued_processes << do_upload(full_path, relative_path)
25
18
  rescue StandardError => e
26
- $stdout.puts "Error while trying to upload #{full_path}: #{e.inspect}"
19
+ raise e.class, "Error while trying to upload #{full_path}: #{e.message}"
27
20
  end
28
21
 
29
22
  $stdout.print 'Task complete!'
@@ -31,6 +24,14 @@ module LokaliseRails
31
24
  queued_processes
32
25
  end
33
26
 
27
+ # Performs the actual file uploading to Lokalise. If the API rate limit is exceeed,
28
+ # applies exponential backoff
29
+ def do_upload(f_path, r_path)
30
+ with_exp_backoff(LokaliseRails.max_retries_export) do
31
+ api_client.upload_file project_id_with_branch, opts(f_path, r_path)
32
+ end
33
+ end
34
+
34
35
  # Processes each translation file in the specified directory
35
36
  def each_file
36
37
  return unless block_given?
@@ -13,12 +13,7 @@ module LokaliseRails
13
13
  #
14
14
  # @return [Boolean]
15
15
  def import!
16
- errors = opt_errors
17
-
18
- if errors.any?
19
- errors.each { |e| $stdout.puts e }
20
- return false
21
- end
16
+ check_options_errors!
22
17
 
23
18
  unless proceed_when_safe_mode?
24
19
  $stdout.print 'Task cancelled!'
@@ -31,15 +26,16 @@ module LokaliseRails
31
26
  true
32
27
  end
33
28
 
34
- # Downloads files from Lokalise using the specified options
29
+ # Downloads files from Lokalise using the specified options.
30
+ # Utilizes exponential backoff if "too many requests" error is received
35
31
  #
36
32
  # @return [Hash]
37
33
  def download_files
38
- opts = LokaliseRails.import_opts
39
-
40
- api_client.download_files project_id_with_branch, opts
34
+ with_exp_backoff(LokaliseRails.max_retries_import) do
35
+ api_client.download_files project_id_with_branch, LokaliseRails.import_opts
36
+ end
41
37
  rescue StandardError => e
42
- $stdout.puts "There was an error when trying to download files: #{e.inspect}"
38
+ raise e.class, "There was an error when trying to download files: #{e.message}"
43
39
  end
44
40
 
45
41
  # Opens ZIP archive (local or remote) with translations and processes its entries
@@ -49,6 +45,8 @@ module LokaliseRails
49
45
  Zip::File.open_buffer(open_file_or_remote(path)) do |zip|
50
46
  fetch_zip_entries(zip) { |entry| process!(entry) }
51
47
  end
48
+ rescue StandardError => e
49
+ raise e.class, "There was an error when trying to process the downloaded files: #{e.message}"
52
50
  end
53
51
 
54
52
  # Iterates over ZIP entries. Each entry may be a file or folder.
@@ -73,7 +71,7 @@ module LokaliseRails
73
71
  f.write LokaliseRails.translations_converter.call(data)
74
72
  end
75
73
  rescue StandardError => e
76
- $stdout.puts "Error when trying to process #{zip_entry&.name}: #{e.inspect}"
74
+ raise e.class, "Error when trying to process #{zip_entry&.name}: #{e.message}"
77
75
  end
78
76
 
79
77
  # Checks whether the user wishes to proceed when safe mode is enabled and the target directory is not empty
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseRails
4
- VERSION = '1.3.0'
4
+ VERSION = '2.0.0'
5
5
  end
@@ -6,9 +6,13 @@ require "#{Rails.root}/config/lokalise_rails"
6
6
  namespace :lokalise_rails do
7
7
  task :import do
8
8
  LokaliseRails::TaskDefinition::Importer.import!
9
+ rescue StandardError => e
10
+ abort e.inspect
9
11
  end
10
12
 
11
13
  task :export do
12
14
  LokaliseRails::TaskDefinition::Exporter.export!
15
+ rescue StandardError => e
16
+ abort e.inspect
13
17
  end
14
18
  end
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.add_development_dependency 'rspec', '~> 3.6'
38
38
  spec.add_development_dependency 'rubocop', '~> 1.0'
39
39
  spec.add_development_dependency 'rubocop-performance', '~> 1.5'
40
- spec.add_development_dependency 'rubocop-rspec', '~> 2.1.0'
40
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0'
41
41
  spec.add_development_dependency 'simplecov', '~> 0.16'
42
42
  spec.add_development_dependency 'vcr', '~> 6.0'
43
43
  end
@@ -34,22 +34,18 @@ describe LokaliseRails::TaskDefinition::Base do
34
34
  end
35
35
  end
36
36
 
37
- describe '.opt_errors' do
38
- it 'returns an error when the API key is not set' do
37
+ describe '.check_options_errors!' do
38
+ it 'raises an error when the API key is not set' do
39
39
  allow(LokaliseRails).to receive(:api_token).and_return(nil)
40
- errors = described_class.opt_errors
40
+
41
+ expect(-> { described_class.check_options_errors! }).to raise_error(LokaliseRails::Error, /API token is not set/i)
41
42
 
42
43
  expect(LokaliseRails).to have_received(:api_token)
43
- expect(errors.length).to eq(1)
44
- expect(errors.first).to include('API token is not set')
45
44
  end
46
45
 
47
46
  it 'returns an error when the project_id is not set' do
48
47
  allow_project_id nil do
49
- errors = described_class.opt_errors
50
-
51
- expect(errors.length).to eq(1)
52
- expect(errors.first).to include('Project ID is not set')
48
+ expect(-> { described_class.check_options_errors! }).to raise_error(LokaliseRails::Error, /ID is not set/i)
53
49
  end
54
50
  end
55
51
  end
@@ -7,6 +7,45 @@ describe LokaliseRails::TaskDefinition::Exporter do
7
7
  let(:path) { "#{Rails.root}/config/locales/nested/#{filename}" }
8
8
  let(:relative_name) { "nested/#{filename}" }
9
9
 
10
+ context 'with many translation files' do
11
+ let(:fake_class) { described_class }
12
+
13
+ before :all do
14
+ add_translation_files! with_ru: true, additional: 5
15
+ end
16
+
17
+ after :all do
18
+ rm_translation_files
19
+ end
20
+
21
+ describe '.export!' do
22
+ it 'sends a proper API request and handles rate limiting' do
23
+ allow_project_id '672198945b7d72fc048021.15940510'
24
+
25
+ process = VCR.use_cassette('upload_files_multiple') do
26
+ described_class.export!
27
+ end.first
28
+
29
+ expect(process.project_id).to eq(LokaliseRails.project_id)
30
+ expect(process.status).to eq('queued')
31
+ end
32
+
33
+ it 'handles too many requests' do
34
+ allow_project_id '672198945b7d72fc048021.15940510'
35
+ allow(LokaliseRails).to receive(:max_retries_export).and_return(2)
36
+
37
+ fake_client = double
38
+ allow(fake_client).to receive(:upload_file).and_raise(Lokalise::Error::TooManyRequests)
39
+ allow(fake_class).to receive(:api_client).and_return(fake_client)
40
+
41
+ expect(-> { fake_class.export! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 2 retries/i)
42
+ expect(LokaliseRails).to have_received(:max_retries_export).exactly(1).times
43
+ expect(fake_class).to have_received(:api_client).exactly(3).times
44
+ expect(fake_client).to have_received(:upload_file).exactly(3).times
45
+ end
46
+ end
47
+ end
48
+
10
49
  context 'with one translation file' do
11
50
  before :all do
12
51
  add_translation_files!
@@ -26,6 +65,7 @@ describe LokaliseRails::TaskDefinition::Exporter do
26
65
 
27
66
  expect(process.project_id).to eq(LokaliseRails.project_id)
28
67
  expect(process.status).to eq('queued')
68
+ expect(LokaliseRails.max_retries_export).to eq(5)
29
69
  end
30
70
 
31
71
  it 'sends a proper API request when a different branch is provided' do
@@ -44,13 +84,13 @@ describe LokaliseRails::TaskDefinition::Exporter do
44
84
  it 'halts when the API key is not set' do
45
85
  allow(LokaliseRails).to receive(:api_token).and_return(nil)
46
86
 
47
- expect(-> { described_class.export! }).to output(/API token is not set/).to_stdout
87
+ expect(-> { described_class.export! }).to raise_error(LokaliseRails::Error, /API token is not set/i)
48
88
  expect(LokaliseRails).to have_received(:api_token)
49
89
  end
50
90
 
51
91
  it 'halts when the project_id is not set' do
52
92
  allow_project_id nil do
53
- expect(-> { described_class.export! }).to output(/Project ID is not set/).to_stdout
93
+ expect(-> { described_class.export! }).to raise_error(LokaliseRails::Error, /ID is not set/i)
54
94
  end
55
95
  end
56
96
  end
@@ -107,17 +147,12 @@ describe LokaliseRails::TaskDefinition::Exporter do
107
147
  end
108
148
 
109
149
  describe '.export!' do
110
- it 'rescues from export errors' do
150
+ it 're-raises export errors' do
111
151
  allow_project_id
112
152
 
113
- processes = VCR.use_cassette('upload_files_error') do
114
- described_class.export!
153
+ VCR.use_cassette('upload_files_error') do
154
+ expect { described_class.export! }.to raise_error(Lokalise::Error::BadRequest, /Unknown `lang_iso`/)
115
155
  end
116
-
117
- expect(processes.length).to eq(1)
118
- process = processes.first
119
- expect(process.project_id).to eq(LokaliseRails.project_id)
120
- expect(process.status).to eq('queued')
121
156
  end
122
157
  end
123
158
 
@@ -4,44 +4,67 @@ describe LokaliseRails::TaskDefinition::Importer do
4
4
  describe '.open_and_process_zip' do
5
5
  let(:faulty_trans) { "#{Rails.root}/public/faulty_trans.zip" }
6
6
 
7
- it 'rescues from errors during file processing' do
7
+ it 're-raises errors during file processing' do
8
8
  expect(-> { described_class.open_and_process_zip(faulty_trans) }).
9
- to output(/Psych::DisallowedClass/).to_stdout
9
+ to raise_error(Psych::DisallowedClass, /Error when trying to process fail\.yml/)
10
+ end
11
+
12
+ it 're-raises errors during file opening' do
13
+ expect(-> { described_class.open_and_process_zip('http://fake.url/wrong/path.zip') }).
14
+ to raise_error(SocketError, /Failed to open TCP connection/)
10
15
  end
11
16
  end
12
17
 
13
18
  describe '.download_files' do
14
19
  it 'returns a proper download URL' do
15
- allow_project_id '189934715f57a162257d74.88352370' do
20
+ allow_project_id '672198945b7d72fc048021.15940510' do
16
21
  response = VCR.use_cassette('download_files') do
17
22
  described_class.download_files
18
23
  end
19
24
 
20
- expect(response['project_id']).to eq('189934715f57a162257d74.88352370')
25
+ expect(response['project_id']).to eq('672198945b7d72fc048021.15940510')
21
26
  expect(response['bundle_url']).to include('s3-eu-west-1.amazonaws.com')
27
+ expect(described_class.api_client.enable_compression).to eq(true)
28
+ expect(LokaliseRails.max_retries_import).to eq(5)
22
29
  end
23
30
  end
24
31
 
25
- it 'rescues from errors during file download' do
32
+ it 're-raises errors during file download' do
26
33
  allow_project_id 'invalid'
27
34
  VCR.use_cassette('download_files_error') do
28
35
  expect(-> { described_class.download_files }).
29
- to output(/Lokalise::Error::BadRequest/).to_stdout
36
+ to raise_error(Lokalise::Error::BadRequest, /Invalid `project_id` parameter/)
30
37
  end
31
38
  end
32
39
  end
33
40
 
34
41
  describe '.import!' do
42
+ let(:fake_class) { described_class }
43
+
44
+ it 'handles too many requests' do
45
+ allow_project_id '672198945b7d72fc048021.15940510'
46
+ allow(LokaliseRails).to receive(:max_retries_import).and_return(2)
47
+
48
+ fake_client = double
49
+ allow(fake_client).to receive(:download_files).and_raise(Lokalise::Error::TooManyRequests)
50
+ allow(fake_class).to receive(:api_client).and_return(fake_client)
51
+
52
+ expect(-> { fake_class.import! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 2 retries/i)
53
+ expect(LokaliseRails).to have_received(:max_retries_import).exactly(1).times
54
+ expect(fake_class).to have_received(:api_client).exactly(3).times
55
+ expect(fake_client).to have_received(:download_files).exactly(3).times
56
+ end
57
+
35
58
  it 'halts when the API key is not set' do
36
59
  allow(LokaliseRails).to receive(:api_token).and_return(nil)
37
- expect(-> { described_class.import! }).to output(/API token is not set/).to_stdout
60
+ expect(-> { described_class.import! }).to raise_error(LokaliseRails::Error, /API token is not set/i)
38
61
  expect(LokaliseRails).to have_received(:api_token)
39
62
  expect(count_translations).to eq(0)
40
63
  end
41
64
 
42
65
  it 'halts when the project_id is not set' do
43
66
  allow_project_id nil do
44
- expect(-> { described_class.import! }).to output(/Project ID is not set/).to_stdout
67
+ expect(-> { described_class.import! }).to raise_error(LokaliseRails::Error, /ID is not set/i)
45
68
  expect(count_translations).to eq(0)
46
69
  end
47
70
  end
@@ -58,6 +58,16 @@ describe LokaliseRails do
58
58
  fake_class.import_safe_mode = true
59
59
  end
60
60
 
61
+ it 'is possible to set max_retries_export' do
62
+ allow(fake_class).to receive(:max_retries_export=).with(10)
63
+ fake_class.max_retries_export = 10
64
+ end
65
+
66
+ it 'is possible to set max_retries_import' do
67
+ allow(fake_class).to receive(:max_retries_import=).with(10)
68
+ fake_class.max_retries_import = 10
69
+ end
70
+
61
71
  it 'is possible to set api_token' do
62
72
  allow(fake_class).to receive(:api_token=).with('abc')
63
73
  fake_class.api_token = 'abc'
@@ -1,7 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe LokaliseRails do
4
+ it 'halts when the API key is not set' do
5
+ allow(described_class).to receive(:api_token).and_return(nil)
6
+
7
+ expect(export_executor).to raise_error(SystemExit, /API token is not set/i)
8
+ expect(described_class).to have_received(:api_token)
9
+ end
10
+
11
+ it 'halts when the project ID is not set' do
12
+ allow_project_id nil do
13
+ expect(export_executor).to raise_error(SystemExit, /ID is not set/i)
14
+ end
15
+ end
16
+
4
17
  it 'runs export rake task properly' do
5
18
  expect(export_executor).to output(/complete!/).to_stdout
6
19
  end
20
+
21
+ context 'with two translation files' do
22
+ let(:filename_ru) { 'ru.yml' }
23
+ let(:path_ru) { "#{Rails.root}/config/locales/#{filename_ru}" }
24
+ let(:relative_name_ru) { filename_ru }
25
+
26
+ before :all do
27
+ add_translation_files! with_ru: true
28
+ end
29
+
30
+ after :all do
31
+ rm_translation_files
32
+ end
33
+
34
+ describe '.export!' do
35
+ it 're-raises export errors' do
36
+ allow_project_id
37
+
38
+ VCR.use_cassette('upload_files_error') do
39
+ expect(export_executor).to raise_error(SystemExit, /Unknown `lang_iso`/)
40
+ end
41
+ end
42
+ end
43
+ end
7
44
  end
@@ -7,6 +7,19 @@ RSpec.describe LokaliseRails do
7
7
  let(:local_trans) { "#{Rails.root}/public/trans.zip" }
8
8
  let(:remote_trans) { 'https://github.com/bodrovis/lokalise_rails/blob/master/spec/dummy/public/trans.zip?raw=true' }
9
9
 
10
+ it 'halts when the API key is not set' do
11
+ allow(described_class).to receive(:api_token).and_return(nil)
12
+
13
+ expect(import_executor).to raise_error(SystemExit, /API token is not set/i)
14
+ expect(described_class).to have_received(:api_token)
15
+ end
16
+
17
+ it 'halts when the project ID is not set' do
18
+ allow_project_id nil do
19
+ expect(import_executor).to raise_error(SystemExit, /ID is not set/i)
20
+ end
21
+ end
22
+
10
23
  context 'when directory is empty' do
11
24
  before do
12
25
  mkdir_locales
@@ -24,16 +24,20 @@ module FileManager
24
24
  locales_dir.count { |file| File.file?(file) }
25
25
  end
26
26
 
27
- def add_translation_files!(with_ru: false)
27
+ def add_translation_files!(with_ru: false, additional: nil)
28
28
  FileUtils.mkdir_p "#{Rails.root}/config/locales/nested"
29
- File.open("#{Rails.root}/config/locales/nested/en.yml", 'w+:UTF-8') do |f|
30
- f.write en_data
31
- end
29
+ open_and_write('config/locales/nested/en.yml') { |f| f.write en_data }
32
30
 
33
31
  return unless with_ru
34
32
 
35
- File.open("#{Rails.root}/config/locales/ru.yml", 'w+:UTF-8') do |f|
36
- f.write ru_data
33
+ open_and_write('config/locales/ru.yml') { |f| f.write ru_data }
34
+
35
+ return unless additional
36
+
37
+ additional.times do |i|
38
+ data = {'en' => {"key_#{i}" => "value #{i}"}}
39
+
40
+ open_and_write("config/locales/en_#{i}.yml") { |f| f.write data.to_yaml }
37
41
  end
38
42
  end
39
43
 
@@ -46,9 +50,13 @@ module FileManager
46
50
  end
47
51
  DATA
48
52
 
49
- File.open("#{Rails.root}/config/lokalise_rails.rb", 'w+:UTF-8') do |f|
50
- f.write data
51
- end
53
+ open_and_write('config/lokalise_rails.rb') { |f| f.write data }
54
+ end
55
+
56
+ def open_and_write(rel_path, &block)
57
+ return unless block
58
+
59
+ File.open("#{Rails.root}/#{rel_path}", 'w+:UTF-8', &block)
52
60
  end
53
61
 
54
62
  def remove_config
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SpecAddons
4
- def allow_project_id(value = ENV['LOKALISE_PROJECT_ID'])
4
+ def allow_project_id(value = '189934715f57a162257d74.88352370')
5
5
  allow(LokaliseRails).to receive(:project_id).and_return(value)
6
6
  return unless block_given?
7
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lokalise_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.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-02-02 00:00:00.000000000 Z
11
+ date: 2021-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-lokalise-api
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 2.1.0
145
+ version: 2.4.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 2.1.0
152
+ version: 2.4.0
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: simplecov
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -198,6 +198,7 @@ files:
198
198
  - lib/generators/lokalise_rails/install_generator.rb
199
199
  - lib/generators/templates/lokalise_rails_config.rb
200
200
  - lib/lokalise_rails.rb
201
+ - lib/lokalise_rails/error.rb
201
202
  - lib/lokalise_rails/railtie.rb
202
203
  - lib/lokalise_rails/task_definition/base.rb
203
204
  - lib/lokalise_rails/task_definition/exporter.rb
@@ -258,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
258
259
  - !ruby/object:Gem::Version
259
260
  version: '0'
260
261
  requirements: []
261
- rubygems_version: 3.2.7
262
+ rubygems_version: 3.2.25
262
263
  signing_key:
263
264
  specification_version: 4
264
265
  summary: Lokalise integration for Ruby on Rails