txgh 5.5.0 → 6.0.0.beta1

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
  SHA1:
3
- metadata.gz: e50a7507eac0482d0fabdbdcbad319fcdd93d605
4
- data.tar.gz: 58a5c723849579e212366c40b0400d253de0997b
3
+ metadata.gz: a63c65881f6f00e2479a19d8ff925581cc8b2c10
4
+ data.tar.gz: e309c3690f95a66a36f5d9b3e743e160dc8a78f4
5
5
  SHA512:
6
- metadata.gz: ec756e7c971f476d6764b834928eee25b35f98e3d9491a1cb861d781e883b0d5918ff22b92d70405ae04dc28db31b0c19a28389525a28d8961fce90e1df32e0a
7
- data.tar.gz: af7377cfef99d9b2908f52a69d888d1b6e7ca8a361c99da3b17da2fd21ccaa3c65b1afe58791d0fa07394ebf0d4e5bc2dcaf1e8e467b16891bce1ef4ec03207d
6
+ metadata.gz: c41e8fc0e628f7c00078046a2cc467fbd62777ba7ff848eafcce1503bdc37c05dc5ac7a5aaa342c01636ca7feae4ee04e9848bb10203862db9f5c4b440819df6
7
+ data.tar.gz: 254e2b871687f9023df759b2df134976a93270eb179c9a1471c11bfc4d6f34933ff9771678868f668a2ef9914bc5144330544d718ab17798e8fde8bcc15c2ba0
data/README.md ADDED
@@ -0,0 +1,334 @@
1
+ Transifex Txgh (Lumos Labs fork)
2
+ ====
3
+
4
+ [![Build Status](https://travis-ci.org/lumoslabs/txgh.svg?branch=master)](https://travis-ci.org/lumoslabs/txgh)
5
+
6
+ Txgh, a mashup of "Transifex" and "Github", is a lightweight server that connects Transifex and Github via webhooks. It enables automatic translation of new content pushed to your Github repository, and supports single-resource as well as branch-based git workflows.
7
+
8
+
9
+ How Does it Work?
10
+ ---
11
+
12
+ 1. When a source file is pushed to Github, the Txgh service will update the corresponding Transifex resource with the contents of the new file. Configuration options exist to process only certain branches and tags.
13
+
14
+ 2. When a resource in Transifex reaches 100% translated, the Txgh service will download the translations and commit them to the target repository. Configuration options exist to protect certain branches or tags from automatic commits.
15
+
16
+ <br>
17
+ For the more visually inclined:
18
+ ![Txgh Use Cases](https://www.gliffy.com/go/publish/image/9483799/L.png)
19
+ <br>
20
+ <br>
21
+
22
+ Supported Workflows
23
+ ---
24
+
25
+ Use the following table to determine if Txgh will work for your git and translation workflow:
26
+
27
+ |Workflow|Comments|
28
+ |:--------|:----------|
29
+ |**Basic**<br>* You maintain one master version of your translations<br>* Translations may not be under source control<br>* New content is translated before each release and does not change until the next release|This is the default. Txgh <br> can also be configured to only<br> listen for changes that happen<br> on a certain branch or tag.|
30
+ |**Multi-branch**<br>* Your team is small or everyone works from the same branch<br>* Translations should change when code changes|You might want to consider <br>multi-branch with diffs (below)<br> since your translators may see<br> a number of duplicate strings<br> in Transifex using this workflow.|
31
+ |**Multi-branch with Diffs**<br>* Your team uses git branches for feature development<br>* Translations should change when code changes|This is the recommended workflow<br> if you'd like to manage translations<br> in an agile way, i.e. "continuous<br> translation." Only new and changed<br> phrases are uploaded to Transifex.|
32
+
33
+ Getting Started
34
+ ---
35
+
36
+ Txgh supports a significant number of configuration options, and you'll need to familiarize yourself with them to ensure you're setting Txgh up to serve your particular needs. That said, we've whipped up a couple of templates with sensible defaults to get you started more quickly. If you're thinking about deploying with Docker, take a look at our [Docker template](https://github.com/lumoslabs/txgh-docker-template). If you want more flexibility (i.e. the ability to add custom middleware, etc), take a look at our [ruby template](https://github.com/lumoslabs/txgh-ruby-template). The rest of the setup steps below assume you're using one of these templates.
37
+
38
+ 1. Open a terminal window and run `./bin/configure`. Follow the instructions to add a new project to `config.yml`. You'll need to have some version of Ruby installed on your system to run the configuration script. Refer to the section marked "Configuring Txgh" below for a detailed explanation of each option.
39
+
40
+ 2. Create a file in your repository named `.tx/config` and add appropriate tx config. Txgh uses this information to know which files should be watched for changes. Refer to the section marked "Tx Config" below for more information.
41
+
42
+ 3. If you've configured Txgh to upload diffs, visit your project's page in Transifex and upload each of the files described in your tx config. Use Transifex's categories feature to add a category of `branch:heads/master` to each resource. These full resources will provide the base set of translations for your project.
43
+
44
+ 3. At this point, you're ready to deploy Txgh. There are a number of ways to do this, including using a host like AWS or Heroku. It's important your Txgh instance is publicly accessible over the Internet, because the next few steps involve setting up webhooks, which rely on being able to reach it.
45
+
46
+ 4. Visit the settings page for your Github repository, click on "Webhooks and Services," then click the "Add webhook" button. Under payload URL, fill in the URL of your publicly accessible Txgh instance and the path to the Github hook. For example, `http://mytxgh.herokuapp.com/hooks/github`. Fill in the "Secret" field with the Github `webhook_secret` generated for you in `config.yml`. Make sure to enable the "push" event, and also the "delete" event if you have configured Txgh to automatically delete resources. When the webhook is first created, Github will send your Txgh instance a "ping" test event. Your Txgh instance should respond with a 200 OK.
47
+
48
+ 5. Visit the Manage -> Edit Project page for your Transifex project. Scroll down to the "Features" header and look for the "Web Hook URL" field. Fill it in with the URL of your publicly accessible Txgh instance and the path to the Transifex hook. For example, `http://mytxgh.herokuapp.com/hooks/transifex`. Fill in the "Secret Key" field with the Transifex `webhook_secret` generated for you in `config.yml`.
49
+
50
+ 6. Congratulations, you now have a running, fully configured Txgh instance! Note that the configuration script you ran in step 1 automatically configured Txgh to process all branches, so you should be able to create a test branch, modify some translations, and push your changes. Txgh is configured correctly if a new resource appears in Transifex with the new branch name attached.
51
+
52
+ Available Endpoints
53
+ ---
54
+
55
+ Txgh exposes the following endpoints:
56
+
57
+ * **`POST /hooks/github`**: Receives and processes Github webhook requests. Request body is expected to be a Github webhook payload in JSON format. Uploads any modified translatable content to Transifex. This endpoint is protected by shared secret signature authorization.
58
+
59
+ * **`POST /hooks/transifex`**: Receives and processes Transifex webhook requests. Request body is expected to be a Transifex webhook payload in JSON format. Commits translations back to the Github repository. This endpoint is protected by shared secret signature authorization.
60
+
61
+ * **`PATCH /push?project_slug=[slug]&branch=[branch]`**: Causes translatable content from Github to be pushed to Transifex. This endpoint is designed to emulate receiving a Github webhook, but doesn't require the usual massive Github webhook payload. Currently this endpoint is not protected (but it should be).
62
+
63
+ * **`PATCH /pull?project_slug=[slug]&branch=[branch]`**: Causes translations from Transifex to be committed to Github. This endpoint is designed to emulate receiving a Transifex webhook, but doesn't require the usual Transifex webhook payload. Currently this endpoint is not protected (but it should be).
64
+
65
+ * **`GET /config?project_slug=[slug]&branch=[branch]`**: Returns the tx config in JSON format for the given project and branch.
66
+
67
+ * **`GET /health_check`**: Simply returns an HTTP 200 OK.
68
+
69
+ Configuring Txgh
70
+ ---
71
+
72
+ Config is written in the YAML markup language and is comprised of two sections, one for Github options and one for Transifex options:
73
+
74
+ ```yaml
75
+ github:
76
+ repos:
77
+ organization/repo:
78
+ api_username: github username
79
+ api_token: abcdefghijklmnopqrstuvwxyz github api token
80
+ push_source_to: transifex project slug
81
+ branch: branch to watch for changes, or "all" to watch all of them
82
+ tag: tag to watch for changes, or "all" to watch all of them
83
+ webhook_secret: 123abcdef456ghi github webhook secret
84
+ diff_point: branch to diff against (usually master)
85
+ transifex:
86
+ projects:
87
+ project-slug:
88
+ tx_config: map of transifex resources to file paths
89
+ api_username: transifex username
90
+ api_password: transifex password (transifex doesn't support token-based auth)
91
+ push_translations_to: organization/repo
92
+ protected_branches: branches that should not receive automatic commits
93
+ webhook_secret: 123abcdef456ghi transifex webhook secret
94
+ auto_delete_resources: 'true' to delete resource when branch is deleted
95
+ ```
96
+
97
+ ### Github Configuration
98
+
99
+ * **`api_username`**: Your Github account username. You might want to create a new dev Github account for Txgh to use instead of providing someone's actual credentials here. Keep in mind that the username you specify must have access to the repository in question, or Github will reject all Txgh's API requests.
100
+
101
+ * **`api_token`**: A valid Github access token. The token should be generated by the username specified by `api_username`. In Github, visit your account settings and generate a personal access token. Give the token all the "repo" permissions.
102
+
103
+ * **`push_source_to`**: The slug of the Transifex project you want to push new translatable content to. The slug is basically the name of the project, but with URL-unfriendly characters removed. You can find the slug of your project by inspecting the URL on any Transifex project page.
104
+
105
+ * **`branch`**: The Github branch to watch for new translatable content. If you want Txgh to watch all branches, use the special value "all". By default, branch is `master`.
106
+
107
+ * **`tag`**: The Github tag to watch for new translatable content. If you want Txgh to watch all tags, use the special value "all".
108
+
109
+ * **`webhook_secret`**: A user-defined string that Github will use to sign webhook requests. If present, Txgh will use this value to verify the authenticity of these webhook requests and reject those that are improperly signed. Make sure you use this same value when configuring the webhook in the Github UI.
110
+
111
+ * **`diff_point`**: The branch to compare against when submitting new translatable content to Transifex, usually `master`. Set this option to enable diffing. If not set, Txgh will upload changed files in their entirety.
112
+
113
+ ### Transifex Configuration
114
+
115
+ * **`tx_config`**: Configuration specifying which files to watch for changes. See the section labeled "Tx Config" below for more information.
116
+
117
+ * **`api_username`**: Your Transifex account username. You might want to create a new dev Transifex account for Txgh to use instead of providing someone's actual credentials here. Keep in mind that the username you specify must have access to the project in question, or Transifex will reject all Txgh's API requests.
118
+
119
+ * **`api_password`**: The Transifex account password associated with `api_username`. Transifex does not support token-based authentication or OAuth.
120
+
121
+ * **`push_translations_to`**: The Github repository to commit completed translations to. If configured to process a branch or branches, Txgh will commit translations back to the branch they came from.
122
+
123
+ * **`protected_branches`**: A comma-separated list of branches Txgh should never make automatic commits on. It can be useful to blacklist certain branches so as not to disrupt a release cycle or surprise your QA team.
124
+
125
+ * **`webhook_secret`**: A user-defined string that Transifex will use to sign webhook requests. If present, Txgh will use this value to verify the authenticity of these webhook requests and reject those that are improperly signed. Make sure to use this same value when configuring the webhook in the Transifex UI.
126
+
127
+ * **`auto_delete_resources`**: If set to "true", Txgh will automatically delete Transifex resources when the corresponding branch is deleted from git.
128
+
129
+ ### Loading Config
130
+
131
+ Txgh supports two different ways of accessing configuration, raw text and a file path. In both cases, config is passed via the `TXGH_CONFIG` environment variable. Prefix the raw text or file path with the appropriate scheme, `raw://` or `file://`, to indicate which strategy Txgh should use.
132
+
133
+ #### Raw Config
134
+
135
+ Passing raw config to Txgh can be done like this:
136
+
137
+ ```bash
138
+ export TXGH_CONFIG="raw://big_yaml_string_here"
139
+ ```
140
+
141
+ When Txgh starts up, it will use the YAML payload that starts after `raw://`.
142
+
143
+ #### File Config
144
+
145
+ It might make more sense to store all your config in a file. Pass the path to Txgh like this:
146
+
147
+ ```bash
148
+ export TXGH_CONFIG="file://path/to/config.yml"
149
+ ```
150
+
151
+ When Txgh runs, it will read and parse the file at the path that comes after `file://`.
152
+
153
+ Of course, in both the file and the raw cases, environment variables can be specified via `export` or inline when starting Txgh. See the "Running Txgh" section below for more information.
154
+
155
+ Tx Config
156
+ ---
157
+
158
+ In addition to the YAML configuration described above, Txgh needs to know which files to watch for changes. Txgh uses the same [ini-style config format](http://docs.transifex.com/client/config/#txconfig) as the Transifex CLI client, meaning you can simply point Txgh at this existing config and things will Just Work™. If you don't already have the CLI client configured, then keep reading.
159
+
160
+ You'll probably have to do some research to find out which formats Transifex supports in order to put together your tx config. You'll also need to know which files contain translatable content. Once you have all this information, constructing your tx config should be fairly straightforward.
161
+
162
+ ### Format
163
+
164
+ By way of example, the tx config for a basic Rails app might look like this:
165
+
166
+ ```ini
167
+ [main]
168
+ host = https://www.transifex.com
169
+ lang_map =
170
+
171
+ # Create one such section per file/resource
172
+ [myproject.enyml]
173
+ file_filter = config/locales/<lang>.yml
174
+ source_file = config/locales/en.yml
175
+ source_lang = en
176
+ type = YML
177
+ ```
178
+
179
+ For every file you'd like Txgh to watch for changes, add another section to the config. The section header enclosed in square brackets is comprised of the project slug, a period, and the resource slug. The project slug can be found by inspecting the URL on Transifex project pages, while the resource slug is something you can make up. Keep in mind that resource slugs in the same project must be unique. Try to choose a name that makes it easy to identify the resource at-a-glance later.
180
+
181
+ Here's a description of each of the fields:
182
+
183
+ * **`file_filter`**: I'm not sure why this field is called `file_filter` since a more appropriate name would be "translation\_file" or "translation\_path\_template". Basically this field is a template that indicates where translations should be saved. The `<lang>` part functions as a placeholder and gets swapped out for a language code. The Spanish translation file for example would be written to config/locales/es.yml.
184
+
185
+ * **`source_file`**: The file to watch for changes.
186
+
187
+ * **`source_lang`**: The language the strings inside the `source_file` are written in.
188
+
189
+ * **`type`**: The format the strings in both the `source_file` and `file_filter` are stored in. This format must be supported by Transifex. For a full list of supported i18n types, see the [Transifex documentation](http://docs.transifex.com/formats/). Rails stores translations in the YAML file format. For a JavaScript project you might store translations in JSON and choose the KEYVALUEJSON i18n type. For Android XML, the ANDROID i18n type, etc.
190
+
191
+ ### Loading Tx Config
192
+
193
+ Tx config is loaded in a similar fashion to Txgh config. There are three supported schemes, `raw`, `file`, and `git`. Both `raw` and `file` behave the same as their Txgh config counterparts, but the `git` scheme is different. It allows tx config to be downloaded dynamically from a git repository instead of read from a static string or file. This means you can store tx config in your git repository itself, where it can be versioned and changed on a per-branch basis. There are several benefits to this. First, any time you add a file to the tx config in a feature branch, that file will be identified and uploaded for that branch only without any additional configuration changes. Second, it places the responsibility of maintaining translated resources with the engineers working in the repo itself rather than on the engineers maintaining your translation infrastructure.
194
+
195
+ Loading tx config from git is straightforward. Use the `git://` scheme followed by the path to the config file inside the repository, eg. `git://.tx/config`.
196
+
197
+ For example, the Transifex section of your Txgh config might look like this:
198
+
199
+ ```yaml
200
+ transifex:
201
+ projects:
202
+ project-slug:
203
+ tx_config: git://.tx/config
204
+ ...
205
+ ```
206
+
207
+ Every time a request is made, Txgh will download `.tx/config` from the given branch and use it to identify changed files.
208
+
209
+ Running Txgh
210
+ ---
211
+
212
+ Txgh is distributed as a [Docker image](https://quay.io/repository/lumoslabs/txgh) and as a [Rubygem](https://rubygems.org/gems/txgh). You can choose to run it via Docker, install and run it as a Rubygem, or run it straight from a local clone of this repository.
213
+
214
+ ### With Docker
215
+
216
+ Using Docker to run Txgh is pretty straightforward (keep in mind you'll need to have the Docker server set up wherever you want to run Txgh).
217
+
218
+ NOTE: You might consider using this [Docker template](https://github.com/lumoslabs/txgh-docker-template) instead of following the instructions below. The template contains all the files and scripts you need to get up and running quickly.
219
+
220
+ First, pull the Txgh image:
221
+
222
+ ```bash
223
+ docker pull quay.io/lumoslabs/txgh:latest
224
+ ```
225
+
226
+ Run the image in a new container:
227
+
228
+ ```bash
229
+ docker run
230
+ -p 9292:9292
231
+ -e "TXGH_CONFIG=raw://$(cat path/to/config.yml)"
232
+ quay.io/lumoslabs/txgh:latest
233
+ ```
234
+
235
+ At this point, Txgh should be up and running. To test it, try hitting the `health_check` endpoint. You should get a 200 response:
236
+
237
+ ```bash
238
+ curl -v localhost:9292/health_check
239
+ ....
240
+ < HTTP/1.1 200 OK
241
+ ```
242
+
243
+ Note that Txgh might not be available on localhost depending on how your Docker client is configured. On a Mac with [docker-machine](https://docs.docker.com/machine/) for instance, you might try this instead:
244
+
245
+ ```bash
246
+ curl -v 192.168.99.100:9292/health_check
247
+ ```
248
+
249
+ (Where 192.168.99.100 is the IP of your docker machine instance).
250
+
251
+ ### From Rubygems
252
+
253
+ Docker is by far the easiest way to run Txgh, but a close runner-up is via Rubygems. You'll need to have at least Ruby 2.1 installed as well as the [bundler gem](http://bundler.io/). Installing ruby and bundler are outside the scope of this README, but I'd suggest using a ruby installer like [rbenv](https://github.com/rbenv/rbenv) or [rvm](https://rvm.io/) to get the job done. Once ruby is installed, executing `gem install bundler` should be enough to install the bundler gem.
254
+
255
+ NOTE: You might consider using this [ruby template](https://github.com/lumoslabs/txgh-ruby-template) instead of following the instructions below. The template contains all the files and scripts you need to get up and running quickly.
256
+
257
+ 1. Create a new directory for your Txgh instance.
258
+
259
+ 2. Inside the new directory, create a file named `Gemfile`. This file is a manifest of all your ruby dependencies.
260
+
261
+ 3. Inside `Gemfile`, add the following lines:
262
+
263
+ ```ruby
264
+ source 'http://rubygems.org'
265
+ gem 'txgh', '~> 1.0'
266
+ ```
267
+ When bundler parses this file, it will know to fetch dependencies from rubygems.org, the most popular and ubiquitous gem host. It will also know to fetch and install the txgh gem.
268
+ 4. Create another file next to `Gemfile` named `config.ru`. This file describes how to run the Txgh server, including where to mount the various endpoints.
269
+ 5. Inside `config.ru` add the following lines:
270
+
271
+ ```ruby
272
+ require 'txgh'
273
+
274
+ map '/' do
275
+ use Txgh::Application
276
+ use Txgh::Triggers
277
+ run Sinatra::Base
278
+ end
279
+
280
+ map '/hooks' do
281
+ use Txgh::Hooks
282
+ run Sinatra::Base
283
+ end
284
+ ```
285
+
286
+ Where each endpoint is mounted is entirely configurable inside this file, as is any additional middleware or your own custom endpoints you might want to add. Txgh is built on the [Rack](http://rack.github.io/) webserver stack, meaning the wide world of Rack is available to you inside this file. The `map`, `use`, and `run` methods are part of Rack's builder syntax.
287
+
288
+ 6. Run `bundle install` to install gem dependencies.
289
+
290
+ 7. Run `TXGH_CONFIG=file://path/to/config.yml bundle exec rackup`. The Txgh instance should start running in the foreground.
291
+
292
+ 8. Test your Txgh instance by hitting the `health_check` endpoint as described above in the "With Docker" section, i.e. `curl -v localhost:9292/health_check`. You should get an HTTP 200 response.
293
+
294
+ ### Local Clone
295
+
296
+ Running Txgh from a local copy of the source code requires almost the same setup as running it from Rubygems. Notably however the `config.ru` file has already been written for you.
297
+
298
+ Refer to the "From Rubygems" section above to get ruby and bundler installed before continuing.
299
+
300
+ 1. Clone Txgh locally:
301
+
302
+ ```bash
303
+ git clone git@github.com:lumoslabs/txgh.git
304
+ ```
305
+
306
+ 2. Change directory into the newly cloned repo (`cd txgh`) and run `bundle install` to install gem dependencies.
307
+ 3. Run `TXGH_CONFIG=file://path/to/config.yml bundle exec rackup`. The Txgh instance should start running in the foreground.
308
+
309
+ 4. Test your Txgh instance by hitting the `health_check` endpoint as described above in the "With Docker" section, i.e. `curl -v localhost:9292/health_check`. You should get an HTTP 200 response.
310
+
311
+ Running Tests
312
+ ---
313
+
314
+ Txgh uses the popular RSpec test framework and has a comprehensive set of unit and integration tests. To run the full test suite, run `bundle exec rake spec:full`, or alternatively `FULL_SPEC=true bundle exec rspec`. To run only the unit tests (which is faster), run `bundle exec rspec`.
315
+
316
+ Requirements
317
+ ---
318
+
319
+ Txgh requires an Internet connection to run, since its primary function is to connect two web services via webhooks and API calls. Other than that, it does not have any other external requirements like a database or cache.
320
+
321
+ Compatibility
322
+ ---
323
+
324
+ Txgh was developed with Ruby 2.1.6, but is probably compatible with all versions between 2.0 and 2.3, and maybe even 1.9. Your mileage may vary when running on older versions.
325
+
326
+ Authors
327
+ ---
328
+
329
+ This repository is a fork of Transifex's [original](https://github.com/transifex/txgh) and is maintained by [Cameron Dutro](https://github.com/camertron) from Lumos Labs.
330
+
331
+ License
332
+ ---
333
+
334
+ Licensed under the Apache License, Version 2.0. See the LICENSE file included in this repository for the full text.
@@ -0,0 +1,62 @@
1
+ # Taken from https://github.com/fringd/zipline
2
+ # Didn't include zipline gem b/c it depends directly on rails and brings in a
3
+ # ton of useless dependencies
4
+
5
+ require 'stringio'
6
+ require 'zip'
7
+
8
+ # a ZipOutputStream that never rewinds output
9
+ # in order for that to be possible we store only uncompressed files
10
+ module Zipline
11
+ class OutputStream < Zip::OutputStream
12
+
13
+ #we need to be able to hand out own custom output in order to stream to browser
14
+ def initialize(io)
15
+ # Create an io stream thing
16
+ super StringIO.new, true
17
+ # Overwrite it with my own
18
+ @output_stream = io
19
+ end
20
+
21
+ def stream
22
+ @output_stream
23
+ end
24
+
25
+ def put_next_entry(entry_name, size)
26
+ new_entry = Zip::Entry.new(@file_name, entry_name)
27
+
28
+ #THIS IS THE MAGIC, tells zip to look after data for size, crc
29
+ new_entry.gp_flags = new_entry.gp_flags | 0x0008
30
+
31
+ super(new_entry)
32
+
33
+ # Uncompressed size in the local file header must be zero when bit 3
34
+ # of the general purpose flags is set, so set the size after the header
35
+ # has been written.
36
+ new_entry.size = size
37
+ end
38
+
39
+ # just reset state, no rewinding required
40
+ def finalize_current_entry
41
+ if current_entry
42
+ entry = current_entry
43
+ super
44
+ write_local_footer(entry)
45
+ end
46
+ end
47
+
48
+ def write_local_footer(entry)
49
+ @output_stream << [ 0x08074b50, entry.crc, entry.compressed_size, entry.size].pack('VVVV')
50
+ end
51
+
52
+ #never need to do this because we set correct sizes up front
53
+ def update_local_headers
54
+ nil
55
+ end
56
+
57
+ # helper to deal with difference between rubyzip 1.0 and 1.1
58
+ def current_entry
59
+ @currentEntry || @current_entry
60
+ end
61
+ end
62
+ end
@@ -90,9 +90,14 @@ module Txgh
90
90
  end
91
91
 
92
92
  def download(repo, path, branch)
93
- contents = client.contents(repo, { path: path, ref: branch })
94
- return contents[:content] if contents[:encoding] == 'utf-8'
95
- return Base64.decode64(contents[:content])
93
+ master = client.ref(repo, branch)
94
+ commit = client.commit(repo, master[:object][:sha])
95
+ tree = client.tree(repo, commit[:commit][:tree][:sha], recursive: 1)
96
+
97
+ if found = tree[:tree].find { |t| t[:path] == path }
98
+ b = blob(repo, found[:sha])
99
+ b['encoding'] == 'utf-8' ? b['content'] : Base64.decode64(b['content'])
100
+ end
96
101
  end
97
102
 
98
103
  def create_status(repo, sha, state, options = {})
@@ -37,7 +37,7 @@ module Txgh
37
37
 
38
38
  def phrases
39
39
  @phrases ||= extractor.from_string(raw) do |extractor|
40
- extractor.extract_each(preserve_arrays: true).map do |key, value|
40
+ extractor.extract_each.map do |key, value|
41
41
  { 'key' => key, 'string' => value }
42
42
  end
43
43
  end
@@ -56,7 +56,7 @@ module Txgh
56
56
  serializer.from_stream(stream, language) do |serializer|
57
57
  phrases.each do |phrase|
58
58
  serializer.write_key_value(
59
- phrase['key'], str(phrase['string'] || '')
59
+ phrase['key'], (phrase['string'] || '').to_s
60
60
  )
61
61
  end
62
62
  end
@@ -95,15 +95,6 @@ module Txgh
95
95
 
96
96
  attr_reader :raw
97
97
 
98
- def str(obj)
99
- case obj
100
- when Array
101
- obj
102
- else
103
- obj.to_s
104
- end
105
- end
106
-
107
98
  def extractor
108
99
  id = EXTRACTOR_MAP.fetch(tx_resource.type) do
109
100
  raise TxghInternalError,
data/lib/txgh/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Txgh
2
- VERSION = '5.5.0'
2
+ VERSION = '6.0.0.beta1'
3
3
  end
@@ -35,29 +35,6 @@ describe DiffCalculator do
35
35
  end
36
36
  end
37
37
 
38
- context 'with an array added to HEAD' do
39
- let(:head_phrases) do
40
- diff_point_phrases + [
41
- phrase('villains', %w(Khan Chang Valeris Shinzon))
42
- ]
43
- end
44
-
45
- let(:diff_point_phrases) do
46
- [
47
- phrase('Bajor', 'Bajoran'),
48
- phrase('Cardassia', 'Cardassian')
49
- ]
50
- end
51
-
52
- it 'includes the new array' do
53
- expect(diff[:added].size).to eq(1)
54
- expect(diff[:modified].size).to eq(0)
55
- phrase = diff[:added].first
56
- expect(phrase['key']).to eq('villains')
57
- expect(phrase['string']).to eq(%w(Khan Chang Valeris Shinzon))
58
- end
59
- end
60
-
61
38
  context 'with phrases removed from HEAD' do
62
39
  let(:head_phrases) do
63
40
  []
@@ -73,21 +50,6 @@ describe DiffCalculator do
73
50
  end
74
51
  end
75
52
 
76
- context 'with an array removed from HEAD' do
77
- let(:head_phrases) do
78
- []
79
- end
80
-
81
- let(:diff_point_phrases) do
82
- phrase('villains', %w(Khan Chang Valeris Shinzon))
83
- end
84
-
85
- it 'does not include the array' do
86
- expect(diff[:added].size).to eq(0)
87
- expect(diff[:modified].size).to eq(0)
88
- end
89
- end
90
-
91
53
  context 'with phrases modified in HEAD' do
92
54
  let(:head_phrases) do
93
55
  [phrase('TheNextGeneration', 'Jean Luc Picard (rocks)')]
@@ -106,24 +68,6 @@ describe DiffCalculator do
106
68
  end
107
69
  end
108
70
 
109
- context 'with an array modified in HEAD' do
110
- let(:head_phrases) do
111
- [phrase('villains', %w(Khan Chang Valeris Shinzon))]
112
- end
113
-
114
- let(:diff_point_phrases) do
115
- [phrase('villains', %w(Khan Chang Valeris))]
116
- end
117
-
118
- it 'includes the entire array' do
119
- expect(diff[:added].size).to eq(0)
120
- expect(diff[:modified].size).to eq(1)
121
- phrase = diff[:modified].first
122
- expect(phrase['key']).to eq('villains')
123
- expect(phrase['string']).to eq(%w(Khan Chang Valeris Shinzon))
124
- end
125
- end
126
-
127
71
  context 'with no phrases modified, added, or removed' do
128
72
  let(:head_phrases) do
129
73
  [
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'base64'
3
2
 
4
3
  include Txgh
5
4
 
@@ -179,30 +178,20 @@ describe GithubApi do
179
178
  end
180
179
 
181
180
  describe '#download' do
182
- let(:path) { 'path/to/file.xyz' }
183
-
184
181
  it 'downloads the file from the given branch' do
185
- expect(client).to(
186
- receive(:contents)
187
- .with(repo, path: path, ref: branch)
188
- .and_return(
189
- content: 'content', encoding: 'utf-8'
190
- )
191
- )
182
+ path = 'path/to/file.xyz'
192
183
 
193
- expect(api.download(repo, path, branch)).to eq('content')
194
- end
184
+ expect(client).to receive(:ref).with(repo, branch).and_return(object: { sha: :branch_sha })
185
+ expect(client).to receive(:commit).with(repo, :branch_sha).and_return(commit: { tree: { sha: :base_tree_sha } })
186
+ expect(client).to receive(:tree).with(repo, :base_tree_sha, recursive: 1).and_return(
187
+ tree: [{ path: path, sha: :blob_sha }]
188
+ )
195
189
 
196
- it 'automatically decodes base64-encoded content' do
197
- expect(client).to(
198
- receive(:contents)
199
- .with(repo, path: path, ref: branch)
200
- .and_return(
201
- content: Base64.encode64('content'), encoding: 'base64'
202
- )
190
+ expect(client).to receive(:blob).with(repo, :blob_sha).and_return(
191
+ { 'content' => :blob, 'encoding' => 'utf-8' }
203
192
  )
204
193
 
205
- expect(api.download(repo, path, branch)).to eq('content')
194
+ expect(api.download(repo, path, branch)).to eq(:blob)
206
195
  end
207
196
  end
208
197
  end
@@ -46,22 +46,6 @@ describe MergeCalculator do
46
46
  end
47
47
  end
48
48
 
49
- context 'with an array added in HEAD' do
50
- let(:diff_point_phrases) do
51
- [phrase('planet.earth', 'Human')]
52
- end
53
-
54
- let(:head_phrases) do
55
- diff_point_phrases + [
56
- phrase('villains', %w(Kahn Chang Valeris Shinzon))
57
- ]
58
- end
59
-
60
- it 'includes the added array' do
61
- expect(merge_result.phrases).to eq(head_phrases)
62
- end
63
- end
64
-
65
49
  context 'with phrases removed from HEAD' do
66
50
  let(:diff_point_phrases) do
67
51
  head_phrases + [
@@ -78,22 +62,6 @@ describe MergeCalculator do
78
62
  end
79
63
  end
80
64
 
81
- context 'with an array removed from HEAD' do
82
- let(:diff_point_phrases) do
83
- head_phrases + [
84
- phrase('villains', %w(Kahn Chang Valeris Shinzon))
85
- ]
86
- end
87
-
88
- let(:head_phrases) do
89
- [phrase('planet.earth', 'Human')]
90
- end
91
-
92
- it 'does not include the removed array' do
93
- expect(merge_result.phrases).to eq(head_phrases)
94
- end
95
- end
96
-
97
65
  context 'with phrases modified in HEAD' do
98
66
  let(:diff_point_phrases) do
99
67
  [phrase('planet.bajor', 'Cardassian')]
@@ -108,20 +76,6 @@ describe MergeCalculator do
108
76
  end
109
77
  end
110
78
 
111
- context 'with an array modified in HEAD' do
112
- let(:diff_point_phrases) do
113
- [phrase('villains', %w(Kahn Chang Valeris))]
114
- end
115
-
116
- let(:head_phrases) do
117
- [phrase('villains', %w(Kahn Chang Valeris Shinzon))]
118
- end
119
-
120
- it 'includes the modified phrase' do
121
- expect(merge_result.phrases).to eq(head_phrases)
122
- end
123
- end
124
-
125
79
  context 'with no phrases modified, added, or removed' do
126
80
  let(:diff_point_phrases) do
127
81
  [phrase('planet.bajor', 'Bajoran')]
@@ -11,29 +11,18 @@ describe ResourceContents do
11
11
  )
12
12
  end
13
13
 
14
- let(:default_contents) do
14
+ let(:raw_contents) do
15
15
  outdent(%Q(
16
16
  en:
17
17
  welcome:
18
- message: "Hello!"
18
+ message: Hello!
19
19
  goodbye:
20
- message: "Goodbye!"
21
- ))
22
- end
23
-
24
- let(:array_contents) do
25
- outdent(%Q(
26
- en:
27
- captains:
28
- - "Janeway"
29
- - "Picard"
30
- - "Sisko"
31
- - "Kirk"
20
+ message: Goodbye!
32
21
  ))
33
22
  end
34
23
 
35
24
  let(:contents) do
36
- ResourceContents.from_string(tx_resource, default_contents)
25
+ ResourceContents.from_string(tx_resource, raw_contents)
37
26
  end
38
27
 
39
28
  describe '#phrases' do
@@ -43,13 +32,6 @@ describe ResourceContents do
43
32
  { 'key' => 'goodbye.message', 'string' => 'Goodbye!' }
44
33
  ])
45
34
  end
46
-
47
- it 'preserves arrays' do
48
- rsrc_contents = ResourceContents.from_string(tx_resource, array_contents)
49
- expect(rsrc_contents.phrases).to eq([
50
- { 'key' => 'captains', 'string' => %w(Janeway Picard Sisko Kirk) }
51
- ])
52
- end
53
35
  end
54
36
 
55
37
  describe '#add' do
@@ -65,14 +47,13 @@ describe ResourceContents do
65
47
  it 'serializes the phrases to the given stream' do
66
48
  stream = StringIO.new
67
49
  contents.write_to(stream)
68
- expect(stream.string).to eq(default_contents)
69
- end
70
-
71
- it 'serializes arrays correctly' do
72
- stream = StringIO.new
73
- rsrc_contents = ResourceContents.from_string(tx_resource, array_contents)
74
- rsrc_contents.write_to(stream)
75
- expect(stream.string).to eq(array_contents)
50
+ expect(stream.string).to eq(outdent(%Q(
51
+ en:
52
+ welcome:
53
+ message: "Hello!"
54
+ goodbye:
55
+ message: "Goodbye!"
56
+ )))
76
57
  end
77
58
 
78
59
  it 'includes phrases that were added after the fact' do
data/txgh.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.platform = Gem::Platform::RUBY
14
14
  s.has_rdoc = true
15
15
 
16
- s.add_dependency 'abroad', '~> 4.1'
16
+ s.add_dependency 'abroad', '~> 4.0'
17
17
  s.add_dependency 'faraday', '~> 0.9'
18
18
  s.add_dependency 'faraday_middleware', '~> 0.10'
19
19
  s.add_dependency 'json', '~> 1.8'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: txgh
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.0
4
+ version: 6.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Jackowski
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-08-17 00:00:00.000000000 Z
12
+ date: 2016-08-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: abroad
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '4.1'
20
+ version: '4.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '4.1'
27
+ version: '4.0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: faraday
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +104,8 @@ extensions: []
104
104
  extra_rdoc_files: []
105
105
  files:
106
106
  - LICENSE
107
+ - README.md
108
+ - lib/ext/zipline/output_stream.rb
107
109
  - lib/txgh.rb
108
110
  - lib/txgh/category_support.rb
109
111
  - lib/txgh/config.rb
@@ -186,12 +188,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
188
  version: '0'
187
189
  required_rubygems_version: !ruby/object:Gem::Requirement
188
190
  requirements:
189
- - - ">="
191
+ - - ">"
190
192
  - !ruby/object:Gem::Version
191
- version: '0'
193
+ version: 1.3.1
192
194
  requirements: []
193
195
  rubyforge_project:
194
- rubygems_version: 2.6.6
196
+ rubygems_version: 2.2.3
195
197
  signing_key:
196
198
  specification_version: 4
197
199
  summary: A library for syncing translation resources between Github and Transifex.