phraseapp_updater 2.1.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/phraseapp_common.sh +6 -6
- data/bin/synchronize_phraseapp.sh +2 -2
- data/lib/phraseapp_updater/phraseapp_api.rb +134 -98
- data/lib/phraseapp_updater/version.rb +1 -1
- data/lib/phraseapp_updater.rb +5 -4
- metadata +10 -26
- data/.envrc +0 -1
- data/.github/workflows/gem-push.yml +0 -31
- data/.github/workflows/test.yml +0 -41
- data/.gitignore +0 -9
- data/.rspec +0 -2
- data/.travis.yml +0 -5
- data/CODE_OF_CONDUCT.markdown +0 -50
- data/Gemfile +0 -8
- data/README.markdown +0 -177
- data/Rakefile +0 -7
- data/nix/gem/Gemfile +0 -24
- data/nix/gem/Gemfile.lock +0 -68
- data/nix/gem/gemset.nix +0 -230
- data/nix/generate.rb +0 -41
- data/phraseapp_updater.gemspec +0 -35
- data/shell.nix +0 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f33deb3a77a37a47abdf44c354526cbe3ad3d10256bb2a046bf48922178187fd
|
|
4
|
+
data.tar.gz: f22f2ceed18653b09c24be4724707cdc40c39539535c226fd028bc03338437cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 822cc67247e2e2752397127f6b4e5e0d893cdfc3c64a29f14067d2bc5b6e131f3924d5cad982960df65da4b47971c12ad43fc9caf9c9ff15e756a596a64c163e
|
|
7
|
+
data.tar.gz: a2e1152e1a376690722722d73c2654d4ab4e417530b66b86f7562cd0b17e54f06976a295bae601ec0d4ed1e8570a518eef9a37ff317f24001643e711c0365e6c
|
data/bin/phraseapp_common.sh
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
|
|
3
3
|
# Set up a working directory
|
|
4
|
-
working_directory=$(mktemp -d
|
|
4
|
+
working_directory=$(mktemp -d phraseapp.XXXXXX)
|
|
5
5
|
|
|
6
6
|
function cleanup_working_directory(){
|
|
7
7
|
local now archive
|
|
8
8
|
now="$(date "+%Y%m%d%H%M%S")"
|
|
9
9
|
archive="/tmp/phraseapp-updater-$now.tar.gz"
|
|
10
|
-
tar czf "$archive" "${working_directory}"
|
|
10
|
+
tar -C "$(dirname "$working_directory")" -czf "$archive" "$(basename "${working_directory}")"
|
|
11
11
|
rm -rf "${working_directory}"
|
|
12
12
|
echo "Working files saved to $archive"
|
|
13
13
|
}
|
|
@@ -41,15 +41,15 @@ function make_tree_from_directory() {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
function
|
|
45
|
-
extract_files "$1:${PREFIX}"
|
|
44
|
+
function extract_prefix_from_commit() {
|
|
45
|
+
extract_files "$1" "$2:${PREFIX}"
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
function extract_files() {
|
|
49
49
|
local path
|
|
50
|
-
path=$(make_temporary_directory "git.${1%%:*}")
|
|
50
|
+
path=$(make_temporary_directory "git.${1}.${2%%:*}")
|
|
51
51
|
|
|
52
|
-
git archive --format=tar "$
|
|
52
|
+
git archive --format=tar "$2" | tar -x -C "${path}"
|
|
53
53
|
|
|
54
54
|
echo "${path}"
|
|
55
55
|
}
|
|
@@ -61,8 +61,8 @@ elif ! git merge-base --is-ancestor "${common_ancestor}" "${current_branch}"; th
|
|
|
61
61
|
skip_ancestor_merge=t
|
|
62
62
|
fi
|
|
63
63
|
|
|
64
|
-
current_branch_path=$(
|
|
65
|
-
common_ancestor_path=$(
|
|
64
|
+
current_branch_path=$(extract_prefix_from_commit current_branch "${current_branch}")
|
|
65
|
+
common_ancestor_path=$(extract_prefix_from_commit common_ancestor "${common_ancestor}")
|
|
66
66
|
|
|
67
67
|
current_phraseapp_tree=$(make_tree_from_directory "${current_phraseapp_path}")
|
|
68
68
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require 'phraseapp_updater/locale_file'
|
|
4
4
|
require 'phraseapp_updater/index_by'
|
|
5
|
-
require '
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'phrase'
|
|
6
7
|
require 'parallel'
|
|
7
8
|
require 'tempfile'
|
|
8
9
|
|
|
@@ -13,16 +14,24 @@ class PhraseAppUpdater
|
|
|
13
14
|
PAGE_SIZE = 100
|
|
14
15
|
|
|
15
16
|
def initialize(api_key, project_id, locale_file_class)
|
|
16
|
-
|
|
17
|
+
config = Phrase::Configuration.new do |c|
|
|
18
|
+
c.api_key['Authorization'] = api_key
|
|
19
|
+
c.api_key_prefix['Authorization'] = 'token'
|
|
20
|
+
c.debugging = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
@client = Phrase::ApiClient.new(config)
|
|
17
24
|
@project_id = project_id
|
|
18
25
|
@locale_file_class = locale_file_class
|
|
19
26
|
end
|
|
20
27
|
|
|
21
28
|
def create_project(name, parent_commit)
|
|
22
|
-
params =
|
|
29
|
+
params = Phrase::ProjectCreateParameters.new(
|
|
23
30
|
name: name,
|
|
24
31
|
main_format: @locale_file_class.phraseapp_type)
|
|
25
|
-
|
|
32
|
+
|
|
33
|
+
project = phraseapp_request(Phrase::ProjectsApi, :project_create, params)
|
|
34
|
+
|
|
26
35
|
STDERR.puts "Created project #{name} for #{parent_commit}"
|
|
27
36
|
|
|
28
37
|
@project_id = project.id
|
|
@@ -32,7 +41,8 @@ class PhraseAppUpdater
|
|
|
32
41
|
end
|
|
33
42
|
|
|
34
43
|
def lookup_project_id(name)
|
|
35
|
-
result, =
|
|
44
|
+
result, = paginated_request(Phrase::ProjectsApi, :projects_list, { per_page: PAGE_SIZE }, limit: 1) { |p| p.name == name }
|
|
45
|
+
|
|
36
46
|
raise ProjectNotFoundError.new(name) if result.nil?
|
|
37
47
|
|
|
38
48
|
result.id
|
|
@@ -41,9 +51,10 @@ class PhraseAppUpdater
|
|
|
41
51
|
# We mark projects with their parent git commit using a tag with a
|
|
42
52
|
# well-known prefix. We only allow one tag with this prefix at once.
|
|
43
53
|
def read_parent_commit
|
|
44
|
-
git_tag, =
|
|
54
|
+
git_tag, = paginated_request(Phrase::TagsApi, :tags_list, @project_id, limit: 1) do |t|
|
|
45
55
|
t.name.start_with?(GIT_TAG_PREFIX)
|
|
46
56
|
end
|
|
57
|
+
|
|
47
58
|
raise MissingGitParentError.new if git_tag.nil?
|
|
48
59
|
|
|
49
60
|
git_tag.name.delete_prefix(GIT_TAG_PREFIX)
|
|
@@ -51,35 +62,28 @@ class PhraseAppUpdater
|
|
|
51
62
|
|
|
52
63
|
def update_parent_commit(commit_hash)
|
|
53
64
|
previous_parent = read_parent_commit
|
|
54
|
-
phraseapp_request
|
|
55
|
-
@client.tag_delete(@project_id, GIT_TAG_PREFIX + previous_parent)
|
|
56
|
-
end
|
|
65
|
+
phraseapp_request(Phrase::TagsApi, :tag_delete, @project_id, GIT_TAG_PREFIX + previous_parent)
|
|
57
66
|
store_parent_commit(commit_hash)
|
|
58
67
|
end
|
|
59
68
|
|
|
60
69
|
def fetch_locales
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
phraseapp_request { @client.locales_list(@project_id, 1, 100) }.map do |pa_locale|
|
|
64
|
-
Locale.new(pa_locale)
|
|
65
|
-
end
|
|
70
|
+
locales = paginated_request(Phrase::LocalesApi, :locales_list, @project_id)
|
|
71
|
+
locales.map { |pa_locale| Locale.new(pa_locale) }
|
|
66
72
|
end
|
|
67
73
|
|
|
68
74
|
def create_locale(name, default: false)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@client.locale_create(@project_id, params)
|
|
76
|
-
end
|
|
75
|
+
params = Phrase::LocaleCreateParameters.new(
|
|
76
|
+
name: name,
|
|
77
|
+
code: name,
|
|
78
|
+
default: default,
|
|
79
|
+
)
|
|
80
|
+
phraseapp_request(Phrase::LocalesApi, :locale_create, @project_id, params)
|
|
77
81
|
end
|
|
78
82
|
|
|
79
83
|
def download_files(locales, skip_unverified:)
|
|
80
84
|
results = threaded_request(locales) do |locale|
|
|
81
85
|
STDERR.puts "Downloading file for #{locale}"
|
|
82
|
-
|
|
86
|
+
download_locale(locale, skip_unverified)
|
|
83
87
|
end
|
|
84
88
|
|
|
85
89
|
locales.zip(results).map do |locale, file_contents|
|
|
@@ -87,18 +91,65 @@ class PhraseAppUpdater
|
|
|
87
91
|
end
|
|
88
92
|
end
|
|
89
93
|
|
|
94
|
+
# Empirically, PhraseApp fails to parse the uploaded files when uploaded in
|
|
95
|
+
# parallel. Give it a better chance by uploading them one at a time.
|
|
90
96
|
def upload_files(locale_files, default_locale:)
|
|
91
|
-
|
|
97
|
+
is_default = ->(l) { l.locale_name == default_locale }
|
|
92
98
|
|
|
99
|
+
# Ensure the locales all exist
|
|
100
|
+
STDERR.puts('Creating locales')
|
|
101
|
+
known_locales = fetch_locales.index_by(&:name)
|
|
93
102
|
threaded_request(locale_files) do |locale_file|
|
|
94
103
|
unless known_locales.has_key?(locale_file.locale_name)
|
|
95
|
-
create_locale(locale_file.locale_name,
|
|
96
|
-
|
|
104
|
+
create_locale(locale_file.locale_name, default: is_default.(locale_file))
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Upload the files in a stable order, ensuring the default locale is first.
|
|
109
|
+
locale_files.sort! do |a, b|
|
|
110
|
+
next -1 if is_default.(a)
|
|
111
|
+
next 1 if is_default.(b)
|
|
112
|
+
|
|
113
|
+
a.locale_name <=> b.locale_name
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
uploads = {}
|
|
117
|
+
|
|
118
|
+
uploads = locale_files.to_h do |locale_file|
|
|
119
|
+
STDERR.puts("Uploading #{locale_file}")
|
|
120
|
+
upload_id = upload_file(locale_file)
|
|
121
|
+
[upload_id, locale_file]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Validate the uploads, retrying failures as necessary
|
|
125
|
+
successful_upload_ids = {}
|
|
126
|
+
|
|
127
|
+
STDERR.puts('Verifying uploads...')
|
|
128
|
+
until uploads.empty?
|
|
129
|
+
threaded_request(uploads.to_a) do |upload_id, locale_file|
|
|
130
|
+
upload = phraseapp_request(Phrase::UploadsApi, :upload_show, @project_id, upload_id)
|
|
131
|
+
|
|
132
|
+
case upload.state
|
|
133
|
+
when "enqueued", "processing"
|
|
134
|
+
STDERR.puts("#{locale_file}: still processing")
|
|
135
|
+
when "success"
|
|
136
|
+
STDERR.puts("#{locale_file}: success")
|
|
137
|
+
successful_upload_ids[locale_file.locale_name] = upload_id
|
|
138
|
+
uploads.delete(upload_id)
|
|
139
|
+
when "error"
|
|
140
|
+
STDERR.puts("#{locale_file}: upload failure, retrying")
|
|
141
|
+
new_upload_id = upload_file(locale_file)
|
|
142
|
+
uploads.delete(upload_id)
|
|
143
|
+
uploads[new_upload_id] = locale_file
|
|
144
|
+
else
|
|
145
|
+
raise RuntimeError.new("Unknown upload state: #{upload.state}")
|
|
146
|
+
end
|
|
97
147
|
end
|
|
98
148
|
|
|
99
|
-
|
|
100
|
-
upload_file(locale_file)
|
|
149
|
+
sleep(2) unless uploads.empty?
|
|
101
150
|
end
|
|
151
|
+
|
|
152
|
+
successful_upload_ids
|
|
102
153
|
end
|
|
103
154
|
|
|
104
155
|
def remove_keys_not_in_uploads(upload_ids)
|
|
@@ -108,105 +159,101 @@ class PhraseAppUpdater
|
|
|
108
159
|
end
|
|
109
160
|
end
|
|
110
161
|
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
162
|
+
def download_locale(locale, skip_unverified)
|
|
163
|
+
opts = {
|
|
164
|
+
file_format: @locale_file_class.phraseapp_type,
|
|
165
|
+
skip_unverified_translations: skip_unverified,
|
|
166
|
+
}
|
|
116
167
|
|
|
117
|
-
|
|
168
|
+
# Avoid allocating a tempfile (and emitting unnecessary warnings) by using `return_type` of `String`
|
|
169
|
+
phraseapp_request(Phrase::LocalesApi, :locale_download, @project_id, locale.id, return_type: 'String', **opts)
|
|
118
170
|
end
|
|
119
171
|
|
|
120
172
|
def upload_file(locale_file)
|
|
121
|
-
upload_params = create_upload_params(locale_file.locale_name)
|
|
122
|
-
|
|
123
173
|
# The PhraseApp gem only accepts a filename to upload,
|
|
124
174
|
# so we need to write the file out and pass it the path
|
|
125
175
|
Tempfile.create([locale_file.locale_name, ".json"]) do |f|
|
|
126
176
|
f.write(locale_file.content)
|
|
127
177
|
f.close
|
|
128
178
|
|
|
129
|
-
|
|
130
|
-
|
|
179
|
+
opts = {
|
|
180
|
+
file: f,
|
|
181
|
+
file_encoding: 'UTF-8',
|
|
182
|
+
file_format: @locale_file_class.phraseapp_type,
|
|
183
|
+
locale_id: locale_file.locale_name,
|
|
184
|
+
skip_unverification: false,
|
|
185
|
+
update_translations: true,
|
|
186
|
+
tags: [generate_upload_tag],
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
result = phraseapp_request(Phrase::UploadsApi, :upload_create, @project_id, **opts)
|
|
190
|
+
|
|
191
|
+
result.id
|
|
131
192
|
end
|
|
132
193
|
end
|
|
133
194
|
|
|
134
195
|
def remove_keys_not_in_upload(upload_id)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
begin
|
|
139
|
-
phraseapp_request { @client.keys_delete(@project_id, delete_params) }
|
|
140
|
-
rescue RuntimeError => _e
|
|
141
|
-
# PhraseApp will accept but mark invalid uploads, however the gem
|
|
142
|
-
# returns the same response in both cases. If we call this API
|
|
143
|
-
# with the ID of an upload of a bad file, it will fail.
|
|
144
|
-
# This usually occurs when sending up an empty file, which is
|
|
145
|
-
# a case we can ignore. However, it'd be better to have a way
|
|
146
|
-
# to detect a bad upload and find the cause.
|
|
147
|
-
end
|
|
196
|
+
delete_pattern = "unmentioned_in_upload:#{upload_id}"
|
|
197
|
+
phraseapp_request(Phrase::KeysApi, :keys_delete_collection, @project_id, q: delete_pattern)
|
|
148
198
|
end
|
|
149
199
|
|
|
150
200
|
private
|
|
151
201
|
|
|
152
202
|
def store_parent_commit(commit_hash)
|
|
153
|
-
params =
|
|
154
|
-
|
|
155
|
-
|
|
203
|
+
params = Phrase::TagCreateParameters.new(name: GIT_TAG_PREFIX + commit_hash)
|
|
204
|
+
phraseapp_request(Phrase::TagsApi,:tag_create, @project_id, params)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def wrap_phrase_errors
|
|
208
|
+
yield
|
|
209
|
+
rescue Phrase::ApiError => e
|
|
210
|
+
if e.code == 401
|
|
211
|
+
raise BadAPIKeyError.new(e)
|
|
212
|
+
elsif e.message.match?(/not found/)
|
|
213
|
+
raise BadProjectIDError.new(e, @project_id)
|
|
214
|
+
elsif e.message.match?(/has already been taken/)
|
|
215
|
+
raise ProjectNameTakenError.new(e)
|
|
216
|
+
else
|
|
217
|
+
raise
|
|
218
|
+
end
|
|
156
219
|
end
|
|
157
220
|
|
|
158
|
-
def
|
|
221
|
+
def paginated_request(api_class, method, *params, limit: nil, **opts, &filter)
|
|
222
|
+
|
|
223
|
+
api_instance = api_class.new(@client)
|
|
159
224
|
page = 1
|
|
160
225
|
results = []
|
|
161
226
|
|
|
162
227
|
loop do
|
|
163
|
-
response =
|
|
164
|
-
|
|
228
|
+
response = wrap_phrase_errors do
|
|
229
|
+
api_instance.public_send(method, *params, opts.merge(page: page, page_size: PAGE_SIZE))
|
|
165
230
|
end
|
|
166
231
|
|
|
167
|
-
break if response.empty?
|
|
232
|
+
break if response.data.empty?
|
|
168
233
|
|
|
169
|
-
matches = response.
|
|
234
|
+
matches = response.data
|
|
235
|
+
matches = matches.filter(&filter) if filter
|
|
170
236
|
matches = matches[0, limit - results.size] if limit
|
|
171
237
|
|
|
172
|
-
unless matches.empty?
|
|
173
|
-
results.concat(matches)
|
|
238
|
+
results.concat(matches) unless matches.empty?
|
|
174
239
|
|
|
175
|
-
|
|
176
|
-
|
|
240
|
+
break if results.size == limit
|
|
241
|
+
break unless response.next_page?
|
|
177
242
|
|
|
178
|
-
page
|
|
243
|
+
page = response.next_page
|
|
179
244
|
end
|
|
180
245
|
|
|
181
246
|
results
|
|
182
247
|
end
|
|
183
248
|
|
|
184
|
-
def phraseapp_request(
|
|
185
|
-
|
|
249
|
+
def phraseapp_request(api_class, method, *params, **opts)
|
|
250
|
+
api_instance = api_class.new(@client)
|
|
186
251
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if err.respond_to?(:error)
|
|
190
|
-
err.error
|
|
191
|
-
else
|
|
192
|
-
err.errors.join('|')
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
raise RuntimeError.new(error)
|
|
252
|
+
response = wrap_phrase_errors do
|
|
253
|
+
api_instance.public_send(method, *params, opts)
|
|
196
254
|
end
|
|
197
255
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
rescue RuntimeError => e
|
|
201
|
-
if e.message.match?(/\(401\)/)
|
|
202
|
-
raise BadAPIKeyError.new(e)
|
|
203
|
-
elsif e.message.match?(/not found/)
|
|
204
|
-
raise BadProjectIDError.new(e, @project_id)
|
|
205
|
-
elsif e.message.match?(/has already been taken/)
|
|
206
|
-
raise ProjectNameTakenError.new(e)
|
|
207
|
-
else
|
|
208
|
-
raise
|
|
209
|
-
end
|
|
256
|
+
response.data
|
|
210
257
|
end
|
|
211
258
|
|
|
212
259
|
# PhraseApp allows two concurrent connections at a time.
|
|
@@ -216,17 +263,6 @@ class PhraseAppUpdater
|
|
|
216
263
|
Parallel.map(worklist, in_threads: THREAD_COUNT, &block)
|
|
217
264
|
end
|
|
218
265
|
|
|
219
|
-
def create_upload_params(locale_name)
|
|
220
|
-
upload_params = PhraseApp::RequestParams::UploadParams.new
|
|
221
|
-
upload_params.file_encoding = 'UTF-8'
|
|
222
|
-
upload_params.file_format = @locale_file_class.phraseapp_type
|
|
223
|
-
upload_params.locale_id = locale_name
|
|
224
|
-
upload_params.skip_unverification = false
|
|
225
|
-
upload_params.update_translations = true
|
|
226
|
-
upload_params.tags = [generate_upload_tag]
|
|
227
|
-
upload_params
|
|
228
|
-
end
|
|
229
|
-
|
|
230
266
|
def generate_upload_tag
|
|
231
267
|
"phraseapp_updater_upload_#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
|
232
268
|
end
|
data/lib/phraseapp_updater.rb
CHANGED
|
@@ -102,13 +102,14 @@ class PhraseAppUpdater
|
|
|
102
102
|
# We assert that the default locale contains all legitimate strings, and so
|
|
103
103
|
# we clean up orphaned content on PhraseApp post-upload by removing keys not
|
|
104
104
|
# in the default locale.
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
unless locale_files.find { |f| f.locale_name == @default_locale }
|
|
106
|
+
raise RuntimeError.new("Missing default locale")
|
|
107
|
+
end
|
|
107
108
|
|
|
108
109
|
upload_ids = @phraseapp_api.upload_files(locale_files, default_locale: @default_locale)
|
|
109
|
-
default_upload_id = upload_ids
|
|
110
|
+
default_upload_id = upload_ids.fetch(@default_locale)
|
|
110
111
|
|
|
111
|
-
STDERR.puts "Removing keys not in default locale upload #{default_upload_id}"
|
|
112
|
+
STDERR.puts "Removing keys not in default locale '#{@default_locale}' upload '#{default_upload_id}'"
|
|
112
113
|
@phraseapp_api.remove_keys_not_in_upload(default_upload_id)
|
|
113
114
|
end
|
|
114
115
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phraseapp_updater
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- iKnow Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-02-
|
|
11
|
+
date: 2023-02-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: thor
|
|
@@ -25,33 +25,33 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0.19'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: phrase
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 2.8.3
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 2.8.3
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: hashdiff
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: 1.0.1
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: 1.0.1
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: multi_json
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -167,23 +167,13 @@ dependencies:
|
|
|
167
167
|
description: A tool for merging data on PhraseApp with local changes (usually two
|
|
168
168
|
git revisions)
|
|
169
169
|
email:
|
|
170
|
-
-
|
|
170
|
+
- systems@iknow.jp
|
|
171
171
|
executables:
|
|
172
172
|
- phraseapp_updater
|
|
173
173
|
extensions: []
|
|
174
174
|
extra_rdoc_files: []
|
|
175
175
|
files:
|
|
176
|
-
- ".envrc"
|
|
177
|
-
- ".github/workflows/gem-push.yml"
|
|
178
|
-
- ".github/workflows/test.yml"
|
|
179
|
-
- ".gitignore"
|
|
180
|
-
- ".rspec"
|
|
181
|
-
- ".travis.yml"
|
|
182
|
-
- CODE_OF_CONDUCT.markdown
|
|
183
|
-
- Gemfile
|
|
184
176
|
- LICENSE.txt
|
|
185
|
-
- README.markdown
|
|
186
|
-
- Rakefile
|
|
187
177
|
- bin/console
|
|
188
178
|
- bin/phraseapp_common.sh
|
|
189
179
|
- bin/phraseapp_updater
|
|
@@ -198,13 +188,7 @@ files:
|
|
|
198
188
|
- lib/phraseapp_updater/phraseapp_api.rb
|
|
199
189
|
- lib/phraseapp_updater/version.rb
|
|
200
190
|
- lib/phraseapp_updater/yml_config_loader.rb
|
|
201
|
-
|
|
202
|
-
- nix/gem/Gemfile.lock
|
|
203
|
-
- nix/gem/gemset.nix
|
|
204
|
-
- nix/generate.rb
|
|
205
|
-
- phraseapp_updater.gemspec
|
|
206
|
-
- shell.nix
|
|
207
|
-
homepage: https://app.engoo.com
|
|
191
|
+
homepage: https://github.com/iknow/phraseapp_updater
|
|
208
192
|
licenses:
|
|
209
193
|
- MIT
|
|
210
194
|
metadata: {}
|
data/.envrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
eval "$(lorri direnv)"
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Publish Ruby Gem
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ "master" ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
build:
|
|
9
|
-
name: Build + Publish
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
packages: write
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v3
|
|
17
|
-
- name: Set up Ruby 2.7
|
|
18
|
-
uses: ruby/setup-ruby@v1
|
|
19
|
-
with:
|
|
20
|
-
ruby-version: 2.7
|
|
21
|
-
|
|
22
|
-
- name: Publish to RubyGems
|
|
23
|
-
run: |
|
|
24
|
-
mkdir -p $HOME/.gem
|
|
25
|
-
touch $HOME/.gem/credentials
|
|
26
|
-
chmod 0600 $HOME/.gem/credentials
|
|
27
|
-
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
28
|
-
gem build *.gemspec
|
|
29
|
-
gem push *.gem
|
|
30
|
-
env:
|
|
31
|
-
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
data/.github/workflows/test.yml
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: Run Tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: "**"
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read
|
|
9
|
-
checks: write
|
|
10
|
-
pull-requests: write
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
test:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
|
|
16
|
-
strategy:
|
|
17
|
-
matrix:
|
|
18
|
-
ruby-version: ['2.7', '3.0', '3.1']
|
|
19
|
-
|
|
20
|
-
steps:
|
|
21
|
-
- uses: actions/checkout@v3
|
|
22
|
-
- name: Set up Ruby
|
|
23
|
-
uses: ruby/setup-ruby@v1
|
|
24
|
-
with:
|
|
25
|
-
ruby-version: ${{ matrix.ruby-version }}
|
|
26
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
27
|
-
- name: Run tests
|
|
28
|
-
run: bundle exec rspec --profile 10 --format RspecJunitFormatter --out test_results/rspec.xml --format progress
|
|
29
|
-
- name: Upload result
|
|
30
|
-
uses: actions/upload-artifact@v3
|
|
31
|
-
if: always()
|
|
32
|
-
with:
|
|
33
|
-
name: rspec.xml
|
|
34
|
-
path: test_results/rspec.xml
|
|
35
|
-
- name: Test Report
|
|
36
|
-
uses: dorny/test-reporter@v1
|
|
37
|
-
if: always()
|
|
38
|
-
with:
|
|
39
|
-
name: Rspec Tests - ${{ matrix.ruby-version }}
|
|
40
|
-
path: test_results/rspec.xml
|
|
41
|
-
reporter: java-junit
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
data/CODE_OF_CONDUCT.markdown
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Contributor Code of Conduct
|
|
2
|
-
|
|
3
|
-
As contributors and maintainers of this project, and in the interest of
|
|
4
|
-
fostering an open and welcoming community, we pledge to respect all people who
|
|
5
|
-
contribute through reporting issues, posting feature requests, updating
|
|
6
|
-
documentation, submitting pull requests or patches, and other activities.
|
|
7
|
-
|
|
8
|
-
We are committed to making participation in this project a harassment-free
|
|
9
|
-
experience for everyone, regardless of level of experience, gender, gender
|
|
10
|
-
identity and expression, sexual orientation, disability, personal appearance,
|
|
11
|
-
body size, race, ethnicity, age, religion, or nationality.
|
|
12
|
-
|
|
13
|
-
Examples of unacceptable behavior by participants include:
|
|
14
|
-
|
|
15
|
-
* The use of sexualized language or imagery
|
|
16
|
-
* Personal attacks
|
|
17
|
-
* Trolling or insulting/derogatory comments
|
|
18
|
-
* Public or private harassment
|
|
19
|
-
* Publishing other's private information, such as physical or electronic
|
|
20
|
-
addresses, without explicit permission
|
|
21
|
-
* Other unethical or unprofessional conduct
|
|
22
|
-
|
|
23
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
24
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
25
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
26
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
27
|
-
threatening, offensive, or harmful.
|
|
28
|
-
|
|
29
|
-
By adopting this Code of Conduct, project maintainers commit themselves to
|
|
30
|
-
fairly and consistently applying these principles to every aspect of managing
|
|
31
|
-
this project. Project maintainers who do not follow or enforce the Code of
|
|
32
|
-
Conduct may be permanently removed from the project team.
|
|
33
|
-
|
|
34
|
-
This code of conduct applies both within project spaces and in public spaces
|
|
35
|
-
when an individual is representing the project or its community.
|
|
36
|
-
|
|
37
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
38
|
-
reported by contacting a project maintainer at kev@bibo.com.ph. All
|
|
39
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
40
|
-
is deemed necessary and appropriate to the circumstances. Maintainers are
|
|
41
|
-
obligated to maintain confidentiality with regard to the reporter of an
|
|
42
|
-
incident.
|
|
43
|
-
|
|
44
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
45
|
-
version 1.3.0, available at
|
|
46
|
-
[http://contributor-covenant.org/version/1/3/0/][version]
|
|
47
|
-
|
|
48
|
-
[homepage]: http://contributor-covenant.org
|
|
49
|
-
[version]: http://contributor-covenant.org/version/1/3/0/
|
|
50
|
-
|
data/Gemfile
DELETED
data/README.markdown
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# PhraseAppUpdater
|
|
2
|
-
|
|
3
|
-
[](https://travis-ci.org/iknow/phraseapp_updater)
|
|
4
|
-
|
|
5
|
-
**Version** 2.0.0
|
|
6
|
-
|
|
7
|
-
This is a tool for managing synchronization between locale data in
|
|
8
|
-
[PhraseApp](https://phraseapp.com) and committed in your project. It can perform
|
|
9
|
-
JSON-aware three-way merges with respect to a common ancestor, and maintains a
|
|
10
|
-
record of the common ancestor on PhraseApp using tags.
|
|
11
|
-
|
|
12
|
-
Our workflow considers localization data stored on PhraseApp to be a working
|
|
13
|
-
copy for a given branch. We expect developers working on the code and
|
|
14
|
-
translators working on PhraseApp to both be able to make changes and have them
|
|
15
|
-
integrated.
|
|
16
|
-
|
|
17
|
-
PhraseApp provides [APIs](https://phraseapp.com/docs/api/v2/) and a [Ruby
|
|
18
|
-
gem](https://github.com/phrase/phraseapp-ruby) for accessing them, but the API
|
|
19
|
-
only allows either a) completely overwriting PhraseApp's data with local data or
|
|
20
|
-
b) reapplying PhraseApp's data on top of the local data. Neither of these cases
|
|
21
|
-
is appropriate for integrating changes made on both sides.
|
|
22
|
-
|
|
23
|
-
What we want instead is a three way merge where the committed data wins on
|
|
24
|
-
conflict. Non-conflicting changes on PhraseApp are preserved, while changes to
|
|
25
|
-
the same key on both sides take the committed data. The result of the merge is
|
|
26
|
-
then applied to both sides, keeping them up to date with each other.
|
|
27
|
-
|
|
28
|
-
This is especially important when removing keys. Imagine we have the
|
|
29
|
-
following, no-longer useful key:
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
unused:
|
|
33
|
-
one: An unused
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
On PhraseApp, we've added another plural form:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```json
|
|
40
|
-
unused:
|
|
41
|
-
one: An unused
|
|
42
|
-
zero: No unused's
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
And in our feature branch, we remove it. The result we want is that the key
|
|
46
|
-
completely disappears, instead of getting a result like either of the above.
|
|
47
|
-
|
|
48
|
-
## Installation
|
|
49
|
-
|
|
50
|
-
This gem provides a command line interface for performing the
|
|
51
|
-
merge and uploading the result to PhraseApp. To use it, install the gem:
|
|
52
|
-
|
|
53
|
-
`gem install phraseapp_updater`
|
|
54
|
-
|
|
55
|
-
You may also use this gem programatically from your own application.
|
|
56
|
-
|
|
57
|
-
Add this line to your application's Gemfile:
|
|
58
|
-
|
|
59
|
-
```ruby
|
|
60
|
-
gem 'phraseapp_updater'
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
And then execute:
|
|
64
|
-
|
|
65
|
-
$ bundle
|
|
66
|
-
|
|
67
|
-
Or install it yourself as:
|
|
68
|
-
|
|
69
|
-
$ gem install phraseapp_updater
|
|
70
|
-
|
|
71
|
-
## Usage
|
|
72
|
-
|
|
73
|
-
CLI
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
**Setup**
|
|
77
|
-
|
|
78
|
-
`phraseapp_updater setup` creates and initializes a PhraseApp project
|
|
79
|
-
corresponding to your branch. It must be provided with the current git revision
|
|
80
|
-
of the branch and the path to the locale files.
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
phraseapp_updater setup --phraseapp_project_name=<yourbranch> --parent_commit=<yourhash> --phraseapp_api_key=<yourkey> --file-format=json <path_to_locales>
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**Synchronize**
|
|
87
|
-
|
|
88
|
-
`phraseapp_updater synchronize` synchronizes a git remote branch with its
|
|
89
|
-
corresponding PhraseApp project, incorporating changes from each side into the
|
|
90
|
-
other. If both sides were changed, a three-way merge is performed. The result is
|
|
91
|
-
uploaded to PhraseApp and committed and pushed to the git remote as appropriate.
|
|
92
|
-
|
|
93
|
-
The option `--no_commit` may be provided to restrict changes to the PhraseApp
|
|
94
|
-
side. If specified, then in the case that the branch was modified, the merge
|
|
95
|
-
result will be uploaded to PhraseApp and the common ancestor updated to the
|
|
96
|
-
branch head.
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
phraseapp_updater synchronize <checkout_path> --prefix=config/locales --phraseapp_project_id=<yourid> --phraseapp_api_key=<yourkey> --file-format=json
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**Download**
|
|
103
|
-
|
|
104
|
-
`phraseapp_updater download` downloads and normalizes locale files from
|
|
105
|
-
PhraseApp, saving them to the specified location. The revision of the recorded
|
|
106
|
-
common ancestor is printed to standard out.
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
phraseapp_updater download --phraseapp_project_id=<yourid> --phraseapp_api_key=<yourkey> --file-format=json <target_path>
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Upload**
|
|
113
|
-
|
|
114
|
-
`phraseapp_updater upload` uploads normalized locale files from your branch to
|
|
115
|
-
PhraseApp and resets the recorded common ancestor to the specified revision.
|
|
116
|
-
|
|
117
|
-
```
|
|
118
|
-
phraseapp_updater upload --phraseapp_project_id=<yourid> --phraseapp_api_key=<yourkey> --file-format=json <path_to_locales>
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
**Update Parent Commit**
|
|
122
|
-
`phraseapp_updater update_parent_commit` records a new common ancestor on
|
|
123
|
-
PhraseApp without changing the locales.
|
|
124
|
-
|
|
125
|
-
```
|
|
126
|
-
phraseapp_updater update_parent_commit --phraseapp_project_id=<yourid> --phraseapp_api_key=<yourkey> --parent_commit=<yournewhash>
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
**Merge**
|
|
130
|
-
|
|
131
|
-
`phraseapp_updater merge` performs a content-aware three-way merge between
|
|
132
|
-
locale files in three directories: `ancestor_path`, `our_path`, and
|
|
133
|
-
`their_path`. In the case of conflicts, the changes from `our_path` are
|
|
134
|
-
accepted. The results are normalized and written to the path specified with
|
|
135
|
-
`to`.
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
phraseapp_updater merge ancestor_path our_path their_path --to target_path --file-format=json
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
**Diff**
|
|
143
|
-
|
|
144
|
-
Performs a content-aware diff between locale files in two directories. Returns
|
|
145
|
-
with exit status 1 or 0 to signal differences or no differences respectively
|
|
146
|
-
|
|
147
|
-
```
|
|
148
|
-
phraseapp_updater diff path1 path2 --file-format=json
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Future Improvements
|
|
152
|
-
|
|
153
|
-
If you'd like to contribute, these would be very helpful!
|
|
154
|
-
|
|
155
|
-
* We'd like to use "unverified" translations on PhraseApp as the equivalent of
|
|
156
|
-
an unstaged working copy. For this to work, we need to be able to recover
|
|
157
|
-
previous translations at the same key. While PhraseApp doesn't itself keep
|
|
158
|
-
this history, we could do this by restoring the absent keys from the diff
|
|
159
|
-
between verified and unverified download from the common ancestor.
|
|
160
|
-
* Expose the changed files on the command line.
|
|
161
|
-
* Checking if PhraseApp files changed during execution before upload, to reduce the race condition window.
|
|
162
|
-
* More specs for the API and shell.
|
|
163
|
-
|
|
164
|
-
## Development
|
|
165
|
-
|
|
166
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
167
|
-
|
|
168
|
-
To install this gem onto your local machine, run `bundle exec rake install`. When everything is working, make a pull request.
|
|
169
|
-
|
|
170
|
-
## Contributing
|
|
171
|
-
|
|
172
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/iknow/phraseapp_updater. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
173
|
-
|
|
174
|
-
## License
|
|
175
|
-
|
|
176
|
-
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
177
|
-
|
data/Rakefile
DELETED
data/nix/gem/Gemfile
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
source "https://rubygems.org/"
|
|
2
|
-
|
|
3
|
-
gem "byebug", "11.0.1"
|
|
4
|
-
gem "coderay", "1.1.2"
|
|
5
|
-
gem "deep_merge", "1.2.1"
|
|
6
|
-
gem "diff-lcs", "1.3"
|
|
7
|
-
gem "hashdiff", "0.4.0"
|
|
8
|
-
gem "io-console", "0.5.4"
|
|
9
|
-
gem "irb", "1.2.1"
|
|
10
|
-
gem "method_source", "0.9.2"
|
|
11
|
-
gem "multi_json", "1.14.1"
|
|
12
|
-
gem "oj", "2.18.5"
|
|
13
|
-
gem "parallel", "1.19.1"
|
|
14
|
-
gem "phraseapp-ruby", "1.6.0"
|
|
15
|
-
gem "pry", "0.12.2"
|
|
16
|
-
gem "rake", "10.5.0"
|
|
17
|
-
gem "reline", "0.1.2"
|
|
18
|
-
gem "rspec", "3.8.0"
|
|
19
|
-
gem "rspec-core", "3.8.0"
|
|
20
|
-
gem "rspec-expectations", "3.8.3"
|
|
21
|
-
gem "rspec-mocks", "3.8.0"
|
|
22
|
-
gem "rspec-support", "3.8.0"
|
|
23
|
-
gem "rspec_junit_formatter", "0.4.1"
|
|
24
|
-
gem "thor", "0.20.3"
|
data/nix/gem/Gemfile.lock
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
GEM
|
|
2
|
-
remote: https://rubygems.org/
|
|
3
|
-
specs:
|
|
4
|
-
byebug (11.0.1)
|
|
5
|
-
coderay (1.1.2)
|
|
6
|
-
deep_merge (1.2.1)
|
|
7
|
-
diff-lcs (1.3)
|
|
8
|
-
hashdiff (0.4.0)
|
|
9
|
-
io-console (0.5.4)
|
|
10
|
-
irb (1.2.1)
|
|
11
|
-
reline (>= 0.0.1)
|
|
12
|
-
method_source (0.9.2)
|
|
13
|
-
multi_json (1.14.1)
|
|
14
|
-
oj (2.18.5)
|
|
15
|
-
parallel (1.19.1)
|
|
16
|
-
phraseapp-ruby (1.6.0)
|
|
17
|
-
pry (0.12.2)
|
|
18
|
-
coderay (~> 1.1.0)
|
|
19
|
-
method_source (~> 0.9.0)
|
|
20
|
-
rake (10.5.0)
|
|
21
|
-
reline (0.1.2)
|
|
22
|
-
io-console (~> 0.5)
|
|
23
|
-
rspec (3.8.0)
|
|
24
|
-
rspec-core (~> 3.8.0)
|
|
25
|
-
rspec-expectations (~> 3.8.0)
|
|
26
|
-
rspec-mocks (~> 3.8.0)
|
|
27
|
-
rspec-core (3.8.0)
|
|
28
|
-
rspec-support (~> 3.8.0)
|
|
29
|
-
rspec-expectations (3.8.3)
|
|
30
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
31
|
-
rspec-support (~> 3.8.0)
|
|
32
|
-
rspec-mocks (3.8.0)
|
|
33
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
34
|
-
rspec-support (~> 3.8.0)
|
|
35
|
-
rspec-support (3.8.0)
|
|
36
|
-
rspec_junit_formatter (0.4.1)
|
|
37
|
-
rspec-core (>= 2, < 4, != 2.12.0)
|
|
38
|
-
thor (0.20.3)
|
|
39
|
-
|
|
40
|
-
PLATFORMS
|
|
41
|
-
ruby
|
|
42
|
-
|
|
43
|
-
DEPENDENCIES
|
|
44
|
-
byebug (= 11.0.1)
|
|
45
|
-
coderay (= 1.1.2)
|
|
46
|
-
deep_merge (= 1.2.1)
|
|
47
|
-
diff-lcs (= 1.3)
|
|
48
|
-
hashdiff (= 0.4.0)
|
|
49
|
-
io-console (= 0.5.4)
|
|
50
|
-
irb (= 1.2.1)
|
|
51
|
-
method_source (= 0.9.2)
|
|
52
|
-
multi_json (= 1.14.1)
|
|
53
|
-
oj (= 2.18.5)
|
|
54
|
-
parallel (= 1.19.1)
|
|
55
|
-
phraseapp-ruby (= 1.6.0)
|
|
56
|
-
pry (= 0.12.2)
|
|
57
|
-
rake (= 10.5.0)
|
|
58
|
-
reline (= 0.1.2)
|
|
59
|
-
rspec (= 3.8.0)
|
|
60
|
-
rspec-core (= 3.8.0)
|
|
61
|
-
rspec-expectations (= 3.8.3)
|
|
62
|
-
rspec-mocks (= 3.8.0)
|
|
63
|
-
rspec-support (= 3.8.0)
|
|
64
|
-
rspec_junit_formatter (= 0.4.1)
|
|
65
|
-
thor (= 0.20.3)
|
|
66
|
-
|
|
67
|
-
BUNDLED WITH
|
|
68
|
-
1.17.3
|
data/nix/gem/gemset.nix
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
byebug = {
|
|
3
|
-
groups = ["default"];
|
|
4
|
-
platforms = [];
|
|
5
|
-
source = {
|
|
6
|
-
remotes = ["https://rubygems.org"];
|
|
7
|
-
sha256 = "1mmkls9n56l4gx2k0dnyianwz36z2zgpxli5bpsbr7jbw7hn2x6j";
|
|
8
|
-
type = "gem";
|
|
9
|
-
};
|
|
10
|
-
version = "11.0.1";
|
|
11
|
-
};
|
|
12
|
-
coderay = {
|
|
13
|
-
groups = ["default"];
|
|
14
|
-
platforms = [];
|
|
15
|
-
source = {
|
|
16
|
-
remotes = ["https://rubygems.org"];
|
|
17
|
-
sha256 = "15vav4bhcc2x3jmi3izb11l4d9f3xv8hp2fszb7iqmpsccv1pz4y";
|
|
18
|
-
type = "gem";
|
|
19
|
-
};
|
|
20
|
-
version = "1.1.2";
|
|
21
|
-
};
|
|
22
|
-
deep_merge = {
|
|
23
|
-
groups = ["default"];
|
|
24
|
-
platforms = [];
|
|
25
|
-
source = {
|
|
26
|
-
remotes = ["https://rubygems.org"];
|
|
27
|
-
sha256 = "1q3picw7zx1xdkybmrnhmk2hycxzaa0jv4gqrby1s90dy5n7fmsb";
|
|
28
|
-
type = "gem";
|
|
29
|
-
};
|
|
30
|
-
version = "1.2.1";
|
|
31
|
-
};
|
|
32
|
-
diff-lcs = {
|
|
33
|
-
groups = ["default"];
|
|
34
|
-
platforms = [];
|
|
35
|
-
source = {
|
|
36
|
-
remotes = ["https://rubygems.org"];
|
|
37
|
-
sha256 = "18w22bjz424gzafv6nzv98h0aqkwz3d9xhm7cbr1wfbyas8zayza";
|
|
38
|
-
type = "gem";
|
|
39
|
-
};
|
|
40
|
-
version = "1.3";
|
|
41
|
-
};
|
|
42
|
-
hashdiff = {
|
|
43
|
-
groups = ["default"];
|
|
44
|
-
platforms = [];
|
|
45
|
-
source = {
|
|
46
|
-
remotes = ["https://rubygems.org"];
|
|
47
|
-
sha256 = "1ncwxv7jbm3jj9phv6dd514463bkjwggxk10n2z100wf4cjcicrk";
|
|
48
|
-
type = "gem";
|
|
49
|
-
};
|
|
50
|
-
version = "0.4.0";
|
|
51
|
-
};
|
|
52
|
-
io-console = {
|
|
53
|
-
groups = ["default"];
|
|
54
|
-
platforms = [];
|
|
55
|
-
source = {
|
|
56
|
-
remotes = ["https://rubygems.org"];
|
|
57
|
-
sha256 = "109yzpv9kslwra2mxnjsg3r6mwxkbqmxihj266qdvccapghi05wg";
|
|
58
|
-
type = "gem";
|
|
59
|
-
};
|
|
60
|
-
version = "0.5.4";
|
|
61
|
-
};
|
|
62
|
-
irb = {
|
|
63
|
-
dependencies = ["reline"];
|
|
64
|
-
groups = ["default"];
|
|
65
|
-
platforms = [];
|
|
66
|
-
source = {
|
|
67
|
-
remotes = ["https://rubygems.org"];
|
|
68
|
-
sha256 = "1r1y8i46qd5izdszzzn5jxvwvq00m89rk0hm8cs8f21p7nlwmh5w";
|
|
69
|
-
type = "gem";
|
|
70
|
-
};
|
|
71
|
-
version = "1.2.1";
|
|
72
|
-
};
|
|
73
|
-
method_source = {
|
|
74
|
-
groups = ["default"];
|
|
75
|
-
platforms = [];
|
|
76
|
-
source = {
|
|
77
|
-
remotes = ["https://rubygems.org"];
|
|
78
|
-
sha256 = "1pviwzvdqd90gn6y7illcdd9adapw8fczml933p5vl739dkvl3lq";
|
|
79
|
-
type = "gem";
|
|
80
|
-
};
|
|
81
|
-
version = "0.9.2";
|
|
82
|
-
};
|
|
83
|
-
multi_json = {
|
|
84
|
-
groups = ["default"];
|
|
85
|
-
platforms = [];
|
|
86
|
-
source = {
|
|
87
|
-
remotes = ["https://rubygems.org"];
|
|
88
|
-
sha256 = "0xy54mjf7xg41l8qrg1bqri75agdqmxap9z466fjismc1rn2jwfr";
|
|
89
|
-
type = "gem";
|
|
90
|
-
};
|
|
91
|
-
version = "1.14.1";
|
|
92
|
-
};
|
|
93
|
-
oj = {
|
|
94
|
-
groups = ["default"];
|
|
95
|
-
platforms = [];
|
|
96
|
-
source = {
|
|
97
|
-
remotes = ["https://rubygems.org"];
|
|
98
|
-
sha256 = "1jli4mi1xpmm8564pc09bfvv7znzqghidwa3zfw21r365ihmbv2p";
|
|
99
|
-
type = "gem";
|
|
100
|
-
};
|
|
101
|
-
version = "2.18.5";
|
|
102
|
-
};
|
|
103
|
-
parallel = {
|
|
104
|
-
groups = ["default"];
|
|
105
|
-
platforms = [];
|
|
106
|
-
source = {
|
|
107
|
-
remotes = ["https://rubygems.org"];
|
|
108
|
-
sha256 = "12jijkap4akzdv11lm08dglsc8jmc87xcgq6947i1s3qb69f4zn2";
|
|
109
|
-
type = "gem";
|
|
110
|
-
};
|
|
111
|
-
version = "1.19.1";
|
|
112
|
-
};
|
|
113
|
-
phraseapp-ruby = {
|
|
114
|
-
groups = ["default"];
|
|
115
|
-
platforms = [];
|
|
116
|
-
source = {
|
|
117
|
-
remotes = ["https://rubygems.org"];
|
|
118
|
-
sha256 = "14n2hhwjn32xk0qk6rprs3awnrddhnd4zckyd0a4j8lv8k648pnn";
|
|
119
|
-
type = "gem";
|
|
120
|
-
};
|
|
121
|
-
version = "1.6.0";
|
|
122
|
-
};
|
|
123
|
-
pry = {
|
|
124
|
-
dependencies = ["coderay" "method_source"];
|
|
125
|
-
groups = ["default"];
|
|
126
|
-
platforms = [];
|
|
127
|
-
source = {
|
|
128
|
-
remotes = ["https://rubygems.org"];
|
|
129
|
-
sha256 = "00rm71x0r1jdycwbs83lf9l6p494m99asakbvqxh8rz7zwnlzg69";
|
|
130
|
-
type = "gem";
|
|
131
|
-
};
|
|
132
|
-
version = "0.12.2";
|
|
133
|
-
};
|
|
134
|
-
rake = {
|
|
135
|
-
groups = ["default"];
|
|
136
|
-
platforms = [];
|
|
137
|
-
source = {
|
|
138
|
-
remotes = ["https://rubygems.org"];
|
|
139
|
-
sha256 = "0jcabbgnjc788chx31sihc5pgbqnlc1c75wakmqlbjdm8jns2m9b";
|
|
140
|
-
type = "gem";
|
|
141
|
-
};
|
|
142
|
-
version = "10.5.0";
|
|
143
|
-
};
|
|
144
|
-
reline = {
|
|
145
|
-
dependencies = ["io-console"];
|
|
146
|
-
groups = ["default"];
|
|
147
|
-
platforms = [];
|
|
148
|
-
source = {
|
|
149
|
-
remotes = ["https://rubygems.org"];
|
|
150
|
-
sha256 = "0908ijrngc3wkn5iny7d0kxkp74w6ixk2nwzzngplplfla1vkp8x";
|
|
151
|
-
type = "gem";
|
|
152
|
-
};
|
|
153
|
-
version = "0.1.2";
|
|
154
|
-
};
|
|
155
|
-
rspec = {
|
|
156
|
-
dependencies = ["rspec-core" "rspec-expectations" "rspec-mocks"];
|
|
157
|
-
groups = ["default"];
|
|
158
|
-
platforms = [];
|
|
159
|
-
source = {
|
|
160
|
-
remotes = ["https://rubygems.org"];
|
|
161
|
-
sha256 = "15ppasvb9qrscwlyjz67ppw1lnxiqnkzx5vkx1bd8x5n3dhikxc3";
|
|
162
|
-
type = "gem";
|
|
163
|
-
};
|
|
164
|
-
version = "3.8.0";
|
|
165
|
-
};
|
|
166
|
-
rspec-core = {
|
|
167
|
-
dependencies = ["rspec-support"];
|
|
168
|
-
groups = ["default"];
|
|
169
|
-
platforms = [];
|
|
170
|
-
source = {
|
|
171
|
-
remotes = ["https://rubygems.org"];
|
|
172
|
-
sha256 = "1p1s5bnbqp3sxk67y0fh0x884jjym527r0vgmhbm81w7aq6b7l4p";
|
|
173
|
-
type = "gem";
|
|
174
|
-
};
|
|
175
|
-
version = "3.8.0";
|
|
176
|
-
};
|
|
177
|
-
rspec-expectations = {
|
|
178
|
-
dependencies = ["diff-lcs" "rspec-support"];
|
|
179
|
-
groups = ["default"];
|
|
180
|
-
platforms = [];
|
|
181
|
-
source = {
|
|
182
|
-
remotes = ["https://rubygems.org"];
|
|
183
|
-
sha256 = "1c4gs5ybf7km0qshdm92p38zvg32n1j2kr5fgs2icacz7xf2y6fy";
|
|
184
|
-
type = "gem";
|
|
185
|
-
};
|
|
186
|
-
version = "3.8.3";
|
|
187
|
-
};
|
|
188
|
-
rspec-mocks = {
|
|
189
|
-
dependencies = ["diff-lcs" "rspec-support"];
|
|
190
|
-
groups = ["default"];
|
|
191
|
-
platforms = [];
|
|
192
|
-
source = {
|
|
193
|
-
remotes = ["https://rubygems.org"];
|
|
194
|
-
sha256 = "06y508cjqycb4yfhxmb3nxn0v9xqf17qbd46l1dh4xhncinr4fyp";
|
|
195
|
-
type = "gem";
|
|
196
|
-
};
|
|
197
|
-
version = "3.8.0";
|
|
198
|
-
};
|
|
199
|
-
rspec-support = {
|
|
200
|
-
groups = ["default"];
|
|
201
|
-
platforms = [];
|
|
202
|
-
source = {
|
|
203
|
-
remotes = ["https://rubygems.org"];
|
|
204
|
-
sha256 = "0p3m7drixrlhvj2zpc38b11x145bvm311x6f33jjcxmvcm0wq609";
|
|
205
|
-
type = "gem";
|
|
206
|
-
};
|
|
207
|
-
version = "3.8.0";
|
|
208
|
-
};
|
|
209
|
-
rspec_junit_formatter = {
|
|
210
|
-
dependencies = ["rspec-core"];
|
|
211
|
-
groups = ["default"];
|
|
212
|
-
platforms = [];
|
|
213
|
-
source = {
|
|
214
|
-
remotes = ["https://rubygems.org"];
|
|
215
|
-
sha256 = "1aynmrgnv26pkprrajvp7advb8nbh0x4pkwk6jwq8qmwzarzk21p";
|
|
216
|
-
type = "gem";
|
|
217
|
-
};
|
|
218
|
-
version = "0.4.1";
|
|
219
|
-
};
|
|
220
|
-
thor = {
|
|
221
|
-
groups = ["default"];
|
|
222
|
-
platforms = [];
|
|
223
|
-
source = {
|
|
224
|
-
remotes = ["https://rubygems.org"];
|
|
225
|
-
sha256 = "1yhrnp9x8qcy5vc7g438amd5j9sw83ih7c30dr6g6slgw9zj3g29";
|
|
226
|
-
type = "gem";
|
|
227
|
-
};
|
|
228
|
-
version = "0.20.3";
|
|
229
|
-
};
|
|
230
|
-
}
|
data/nix/generate.rb
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
#! /usr/bin/env nix-shell
|
|
2
|
-
#! nix-shell -i ruby -p ruby -p bundler -p bundix
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
|
-
# Bundix doesn't support `gemspec` directive in Gemfiles, as it doesn't copy the
|
|
6
|
-
# gemspec (and its dependencies) into the store.
|
|
7
|
-
# This workaround is from https://github.com/manveru/bundix/issues/10#issuecomment-405879379
|
|
8
|
-
|
|
9
|
-
require 'shellwords'
|
|
10
|
-
|
|
11
|
-
def sh(*args)
|
|
12
|
-
warn args.shelljoin
|
|
13
|
-
system(*args) || raise
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
sh 'bundle', 'lock'
|
|
17
|
-
|
|
18
|
-
require 'fileutils'
|
|
19
|
-
require 'bundler'
|
|
20
|
-
|
|
21
|
-
lockfile = Bundler::LockfileParser.new(File.read('Gemfile.lock'))
|
|
22
|
-
gems = lockfile.specs.select { |spec| spec.source.is_a?(Bundler::Source::Rubygems) }
|
|
23
|
-
sources = [URI('https://rubygems.org/')] | gems.map(&:source).flat_map(&:remotes)
|
|
24
|
-
|
|
25
|
-
FileUtils.mkdir_p 'nix/gem'
|
|
26
|
-
Dir.chdir 'nix/gem' do
|
|
27
|
-
['Gemfile', 'Gemfile.lock', 'gemset.nix'].each do |f|
|
|
28
|
-
File.delete(f) if File.exist?(f)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
File.open('Gemfile', 'w') do |gemfile|
|
|
32
|
-
sources.each { |source| gemfile.puts "source #{source.to_s.inspect}" }
|
|
33
|
-
gemfile.puts
|
|
34
|
-
|
|
35
|
-
gems.each do |gem|
|
|
36
|
-
gemfile.puts "gem #{gem.name.inspect}, #{gem.version.to_s.inspect}"
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
sh 'bundix', '-l'
|
|
41
|
-
end
|
data/phraseapp_updater.gemspec
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require 'phraseapp_updater/version'
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = "phraseapp_updater"
|
|
8
|
-
spec.version = PhraseAppUpdater::VERSION
|
|
9
|
-
spec.authors = ["Kevin Griffin"]
|
|
10
|
-
spec.email = ["kev@bibo.com.ph"]
|
|
11
|
-
|
|
12
|
-
spec.summary = %q{A three-way differ for PhraseApp projects.}
|
|
13
|
-
spec.description = %q{A tool for merging data on PhraseApp with local changes (usually two git revisions)}
|
|
14
|
-
spec.homepage = "https://app.engoo.com"
|
|
15
|
-
spec.license = "MIT"
|
|
16
|
-
|
|
17
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
18
|
-
spec.bindir = "bin"
|
|
19
|
-
spec.executables = ["phraseapp_updater"]
|
|
20
|
-
spec.require_paths = ["lib"]
|
|
21
|
-
|
|
22
|
-
spec.add_dependency "thor", "~> 0.19"
|
|
23
|
-
spec.add_dependency "phraseapp-ruby", "~> 1.3"
|
|
24
|
-
spec.add_dependency "hashdiff", "~> 0.3"
|
|
25
|
-
spec.add_dependency "multi_json", "~> 1.12"
|
|
26
|
-
spec.add_dependency "oj", "~> 2.18"
|
|
27
|
-
spec.add_dependency "deep_merge", "~> 1.1"
|
|
28
|
-
spec.add_dependency "parallel", "~> 1.12"
|
|
29
|
-
|
|
30
|
-
spec.add_development_dependency "bundler", "~> 2.2"
|
|
31
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
|
32
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
|
33
|
-
spec.add_development_dependency "pry", "~> 0.10"
|
|
34
|
-
end
|
|
35
|
-
|