fci 0.0.1
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 +7 -0
- data/.gitignore +36 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +111 -0
- data/Rakefile +44 -0
- data/bin/fci +80 -0
- data/fci.gemspec +27 -0
- data/fci.yml.example +20 -0
- data/features/fci.feature +8 -0
- data/features/step_definitions/fci_steps.rb +6 -0
- data/features/support/env.rb +15 -0
- data/lib/fci/commands/01_init.rb +29 -0
- data/lib/fci/commands/02_import.rb +170 -0
- data/lib/fci/commands/03_download.rb +32 -0
- data/lib/fci/commands/04_export.rb +207 -0
- data/lib/fci/download.rb +31 -0
- data/lib/fci/export.rb +31 -0
- data/lib/fci/helpers.rb +6 -0
- data/lib/fci/import.rb +66 -0
- data/lib/fci/init.rb +62 -0
- data/lib/fci/version.rb +3 -0
- data/lib/fci.rb +14 -0
- data/test/default_test.rb +14 -0
- data/test/test_helper.rb +8 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d3a1f7a7cdd1414f54ea6bcb540c2773d5d6d709
|
4
|
+
data.tar.gz: 4f9966373cceb847965fa8e14fee574327882b48
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 35fdca0463444bdcb87d78e7226fef51544d585e5c3f90d9b3474e091a7c92b9db5a7e4020fd179a9862dbd7a87260f66be4ccefce0fc807b1f4e812d99dd317
|
7
|
+
data.tar.gz: 30abeaba691a5d96ed8a25bbf5c6baf895716add0c4d1da12f671b8ba748bab7135644a65213529673ef5fb76a8a754ebd7b0ecac35d79625280a55ec2dd407c
|
data/.gitignore
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
/fci.yml
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalisation:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
# Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
freshdesk_api
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.1
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Anton Maminov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# FCI
|
2
|
+
|
3
|
+
Freshdesk and Crowdin integration Command Line Interface (CLI)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```
|
10
|
+
gem 'fci'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
```
|
15
|
+
$ bundle
|
16
|
+
```
|
17
|
+
|
18
|
+
Or install it manually as:
|
19
|
+
|
20
|
+
```
|
21
|
+
$ gem install fci
|
22
|
+
```
|
23
|
+
|
24
|
+
## Use
|
25
|
+
|
26
|
+
The simplest way to get started is to create a scaffold project:
|
27
|
+
|
28
|
+
```
|
29
|
+
> fci init todo
|
30
|
+
```
|
31
|
+
|
32
|
+
A new ./todo directory is created containing the sample config `fci.yml`. View the basic output of the scaffold with:
|
33
|
+
|
34
|
+
```
|
35
|
+
> cd todo
|
36
|
+
> fci help
|
37
|
+
```
|
38
|
+
|
39
|
+
Which will output:
|
40
|
+
|
41
|
+
```
|
42
|
+
NAME
|
43
|
+
fci - is a command line tool that allows you to manage and synchronize your Freshdesk localization with Crowdin project
|
44
|
+
|
45
|
+
SYNOPSIS
|
46
|
+
fci [global options] command [command options] [arguments...]
|
47
|
+
|
48
|
+
VERSION
|
49
|
+
0.0.1
|
50
|
+
|
51
|
+
GLOBAL OPTIONS
|
52
|
+
-c, --config=<s> - Project-specific configuration file (default: /home/user/project/fci.yml)
|
53
|
+
--version - Display the program version
|
54
|
+
-v, --verbose - Be verbose
|
55
|
+
--help - Show this message
|
56
|
+
|
57
|
+
COMMANDS
|
58
|
+
help - Shows a list of commands or help for one command
|
59
|
+
init:project - Create a new FCI-based project
|
60
|
+
import:sources - Read folders/articles from Freshdesk and upload resource files to Crowdin
|
61
|
+
download:translations - Build and download last exported translation resources from Crowdin
|
62
|
+
export:translations - Add or update localized resource files(folders and articles) in Freshdesk
|
63
|
+
```
|
64
|
+
|
65
|
+
## Configuration
|
66
|
+
|
67
|
+
The scaffold project that was created in ./todo comes with a `fci.yml` shell.
|
68
|
+
|
69
|
+
```
|
70
|
+
---
|
71
|
+
crowdin_project_id: '<%your-crowdin-project-id%>'
|
72
|
+
crowdin_api_key: '<%your-crowdin-api-key%>'
|
73
|
+
crowdin_base_url: 'https://api.crowdin.com'
|
74
|
+
|
75
|
+
freshdesk_base_url: 'https://<%subdomain%>.freshdesk.com'
|
76
|
+
freshdesk_username: '<%your-freshdek-username%>'
|
77
|
+
freshdesk_password: '<%your-freshdesk-password%>'
|
78
|
+
|
79
|
+
freshdesk_category: '<%category-id%>'
|
80
|
+
|
81
|
+
translations:
|
82
|
+
-
|
83
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
84
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
85
|
+
-
|
86
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
87
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
88
|
+
|
89
|
+
```
|
90
|
+
|
91
|
+
## Supported Rubies
|
92
|
+
|
93
|
+
Tested with the following Ruby versions:
|
94
|
+
|
95
|
+
- MRI 2.2.0
|
96
|
+
|
97
|
+
## Contributing
|
98
|
+
|
99
|
+
1. Fork it
|
100
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
101
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
102
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
103
|
+
5. Create new Pull Request
|
104
|
+
|
105
|
+
## License and Author
|
106
|
+
|
107
|
+
Author: Anton Maminov (anton.maminov@gmail.com)
|
108
|
+
|
109
|
+
Copyright: 2015 [crowdin.com](http://crowdin.com/)
|
110
|
+
|
111
|
+
This project is licensed under the MIT license, a copy of which can be found in the LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'cucumber'
|
6
|
+
require 'cucumber/rake/task'
|
7
|
+
Rake::RDocTask.new do |rd|
|
8
|
+
rd.main = "README.rdoc"
|
9
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
10
|
+
rd.title = 'Your application title'
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = eval(File.read('fci.gemspec'))
|
14
|
+
|
15
|
+
Gem::PackageTask.new(spec) do |pkg|
|
16
|
+
end
|
17
|
+
CUKE_RESULTS = 'results.html'
|
18
|
+
CLEAN << CUKE_RESULTS
|
19
|
+
desc 'Run features'
|
20
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
21
|
+
opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
|
22
|
+
opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
|
23
|
+
t.cucumber_opts = opts
|
24
|
+
t.fork = false
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run features tagged as work-in-progress (@wip)'
|
28
|
+
Cucumber::Rake::Task.new('features:wip') do |t|
|
29
|
+
tag_opts = ' --tags ~@pending'
|
30
|
+
tag_opts = ' --tags @wip'
|
31
|
+
t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
|
32
|
+
t.fork = false
|
33
|
+
end
|
34
|
+
|
35
|
+
task :cucumber => :features
|
36
|
+
task 'cucumber:wip' => 'features:wip'
|
37
|
+
task :wip => 'features:wip'
|
38
|
+
require 'rake/testtask'
|
39
|
+
Rake::TestTask.new do |t|
|
40
|
+
t.libs << "test"
|
41
|
+
t.test_files = FileList['test/*_test.rb']
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => [:test,:features]
|
data/bin/fci
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'gli'
|
3
|
+
begin # XXX: Remove this begin/rescue before distributing your app
|
4
|
+
require 'fci'
|
5
|
+
rescue LoadError
|
6
|
+
STDERR.puts "In development, you need to use `bundle exec bin/fci` to run your app"
|
7
|
+
STDERR.puts "At install-time, RubyGems will make sure lib, etc. are in the load path"
|
8
|
+
STDERR.puts "Feel free to remove this message from bin/fci now"
|
9
|
+
exit 64
|
10
|
+
end
|
11
|
+
|
12
|
+
include GLI::App
|
13
|
+
include FCI
|
14
|
+
|
15
|
+
program_desc 'is a command line tool that allows you to manage and synchronize your Freshdesk localization with Crowdin project'
|
16
|
+
|
17
|
+
sort_help :manually # help commands are ordered in the order declared
|
18
|
+
|
19
|
+
version FCI::VERSION
|
20
|
+
|
21
|
+
subcommand_option_handling :normal
|
22
|
+
arguments :strict
|
23
|
+
|
24
|
+
desc 'Be verbose'
|
25
|
+
switch [:v, :verbose], negatable: false
|
26
|
+
|
27
|
+
desc 'Project-specific configuration file'
|
28
|
+
default_value File.join(Dir.pwd, 'fci.yml')
|
29
|
+
arg_name '<s>'
|
30
|
+
flag [:c, :config]
|
31
|
+
|
32
|
+
commands_from 'fci/commands'
|
33
|
+
|
34
|
+
pre do |global, command, options, args|
|
35
|
+
# Pre logic here
|
36
|
+
# Return true to proceed; false to abort and not call the
|
37
|
+
# chosen command
|
38
|
+
# Use skips_pre before a command to skip this block
|
39
|
+
# on that command only
|
40
|
+
|
41
|
+
unless File.exists?(global[:config])
|
42
|
+
exit_now! <<-EOS.strip_heredoc
|
43
|
+
Can't find configuration file (default `fci.yml').
|
44
|
+
Type `fci help` to know how to specify custom configuration file
|
45
|
+
EOS
|
46
|
+
end
|
47
|
+
|
48
|
+
# load project-specific configuration
|
49
|
+
begin
|
50
|
+
@fci_config = YAML.load(File.read(global[:config])) || {}
|
51
|
+
rescue Psych::SyntaxError => err
|
52
|
+
exit_now! <<-EOS
|
53
|
+
Could not parse YAML: #{err.message}
|
54
|
+
EOS
|
55
|
+
end
|
56
|
+
|
57
|
+
@freshdesk = FreshdeskAPI::Client.new do |c|
|
58
|
+
c.base_url = @fci_config['freshdesk_base_url']
|
59
|
+
c.username = @fci_config['freshdesk_username']
|
60
|
+
c.password = @fci_config['freshdesk_password']
|
61
|
+
end
|
62
|
+
|
63
|
+
@crowdin = Crowdin::API.new(api_key: @fci_config['crowdin_api_key'], project_id: @fci_config['crowdin_project_id'], base_url: @fci_config['crowdin_base_url'])
|
64
|
+
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
post do |global,command,options,args|
|
69
|
+
# Post logic here
|
70
|
+
# Use skips_post before a command to skip this
|
71
|
+
# block on that command only
|
72
|
+
end
|
73
|
+
|
74
|
+
on_error do |exception|
|
75
|
+
# Error logic here
|
76
|
+
# return false to skip default error handling
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
exit run(ARGV)
|
data/fci.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Ensure we require the local version and not one we might have installed already
|
2
|
+
require File.join([File.dirname(__FILE__),'lib','fci','version.rb'])
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = 'fci'
|
5
|
+
s.version = FCI::VERSION
|
6
|
+
s.author = 'Anton Maminov'
|
7
|
+
s.email = 'anton.maminov@gmail.com'
|
8
|
+
s.homepage = 'https://github.com/mamantoha/fci'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'Freshdesk and Crowdin integration Command Line Interface (CLI)'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.require_paths << 'lib'
|
13
|
+
# s.has_rdoc = true
|
14
|
+
# s.extra_rdoc_files = ['README.rdoc','fci.rdoc']
|
15
|
+
# s.rdoc_options << '--title' << 'fci' << '--main' << 'README.rdoc' << '-ri'
|
16
|
+
s.bindir = 'bin'
|
17
|
+
s.executables << 'fci'
|
18
|
+
s.add_runtime_dependency('nokogiri')
|
19
|
+
s.add_runtime_dependency('rubyzip')
|
20
|
+
s.add_runtime_dependency('byebug')
|
21
|
+
s.add_runtime_dependency('crowdin-api')
|
22
|
+
s.add_runtime_dependency('freshdesk_api')
|
23
|
+
s.add_development_dependency('rake')
|
24
|
+
s.add_development_dependency('rdoc')
|
25
|
+
s.add_development_dependency('aruba')
|
26
|
+
s.add_runtime_dependency('gli','2.13.0')
|
27
|
+
end
|
data/fci.yml.example
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
# Crowdin API credentials
|
3
|
+
crowdin_project_id: '<%your-crowdin-project-id%>'
|
4
|
+
crowdin_api_key: '<%your-crowdin-api-key%>'
|
5
|
+
crowdin_base_url: 'https://api.crowdin.com'
|
6
|
+
|
7
|
+
# Freshdesk API credentials
|
8
|
+
freshdesk_base_url: 'https://<%subdomain%>.freshdesk.com'
|
9
|
+
freshdesk_username: '<%your-freshdek-username%>'
|
10
|
+
freshdesk_password: '<%your-freshdesk-password%>'
|
11
|
+
|
12
|
+
freshdesk_category: '<%freshdesk-category-id%>'
|
13
|
+
|
14
|
+
translations:
|
15
|
+
-
|
16
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
17
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
18
|
+
-
|
19
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
20
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
|
3
|
+
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
4
|
+
LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
|
5
|
+
|
6
|
+
Before do
|
7
|
+
# Using "announce" causes massive warnings on 1.9.2
|
8
|
+
@puts = true
|
9
|
+
@original_rubylib = ENV['RUBYLIB']
|
10
|
+
ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ENV['RUBYLIB'] = @original_rubylib
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
desc 'Create a new FCI-based project'
|
3
|
+
arg 'project_name'
|
4
|
+
arg_name 'project_name'
|
5
|
+
skips_pre
|
6
|
+
command :'init:project' do |c|
|
7
|
+
c.desc 'Root dir of project'
|
8
|
+
c.long_desc <<-EOS.strip_heredoc
|
9
|
+
This is the directory where the project's directory will be made, so if you
|
10
|
+
specify a project name `foo` and the root dir of `.`, the directory
|
11
|
+
`./foo` will be created
|
12
|
+
EOS
|
13
|
+
c.flag :r, :root, :default_value => '.'
|
14
|
+
|
15
|
+
c.switch :force, :desc => 'Overwrite/ignore existing files and directories'
|
16
|
+
|
17
|
+
c.action do |global_options, options, args|
|
18
|
+
if args.length < 1
|
19
|
+
raise 'You must specify the name of your project'
|
20
|
+
end
|
21
|
+
|
22
|
+
root_dir = options[:root]
|
23
|
+
force = options[:force]
|
24
|
+
project_name = args.first
|
25
|
+
|
26
|
+
create_scaffold(root_dir, project_name, force)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,170 @@
|
|
1
|
+
desc 'Read folders/articles from Freshdesk and upload resource files to Crowdin'
|
2
|
+
command :'import:sources' do |c|
|
3
|
+
c.desc 'Directory of resource files'
|
4
|
+
c.long_desc <<-EOS.strip_heredoc
|
5
|
+
This is the directory where the project's files will be store.
|
6
|
+
EOS
|
7
|
+
c.default_value 'resources'
|
8
|
+
c.arg_name 'dir'
|
9
|
+
c.flag [:resources_dir]
|
10
|
+
|
11
|
+
c.desc 'Resources config file'
|
12
|
+
c.long_desc <<-EOS.strip_heredoc
|
13
|
+
This is the config file where the information about project's files will be store.
|
14
|
+
EOS
|
15
|
+
c.default_value 'resources/.resources.yml'
|
16
|
+
c.arg_name 'file'
|
17
|
+
c.flag [:resources_config]
|
18
|
+
|
19
|
+
c.action do |global_options, options, args|
|
20
|
+
resources_dir = options[:resources_dir]
|
21
|
+
unless File.exists?(resources_dir)
|
22
|
+
FileUtils.mkdir(resources_dir)
|
23
|
+
end
|
24
|
+
resources_config_file = options[:resources_config]
|
25
|
+
|
26
|
+
File.open(resources_config_file, 'a+') do |f|
|
27
|
+
config = YAML.load(f)
|
28
|
+
unless config # config file empty
|
29
|
+
config = {}
|
30
|
+
# initialize empty config file
|
31
|
+
f.write config.to_yaml
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# for store information about folders/articles ids
|
36
|
+
resources_config = YAML.load(File.open(resources_config_file))
|
37
|
+
|
38
|
+
# Source Category
|
39
|
+
source_category_id = @fci_config['freshdesk_category'].to_i
|
40
|
+
|
41
|
+
# Check if Category exists in Freshdesk
|
42
|
+
source_category = FreshdeskAPI::SolutionCategory.find!(@freshdesk, id: source_category_id)
|
43
|
+
raise('No such category') unless source_category.id == source_category_id
|
44
|
+
|
45
|
+
# Get category's folders in Freshdesk
|
46
|
+
puts "[Freshdesk] Get folders for Category with id #{source_category_id}"
|
47
|
+
folders = @freshdesk.solution_folders(category_id: source_category_id).all!
|
48
|
+
|
49
|
+
folders_builder = []
|
50
|
+
folders.each do |folder|
|
51
|
+
folder_xml = build_folder_xml(folder)
|
52
|
+
|
53
|
+
# write to resources config file
|
54
|
+
unless folder_xml.nil?
|
55
|
+
resources_config[:folders] = [] unless resources_config[:folders]
|
56
|
+
unless resources_config[:folders].detect { |f| f[:id] == folder.id }
|
57
|
+
resources_config[:folders] << { id: folder.id }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
unless folder_xml.nil?
|
62
|
+
folders_builder << build_folder_hash(folder).merge({ xml: folder_xml })
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Get folders articles
|
67
|
+
articles_builder = []
|
68
|
+
folders.each do |folder|
|
69
|
+
puts "[Freshdesk] Get articles for Folder with id #{folder.id}"
|
70
|
+
articles = @freshdesk.solution_articles(category_id: source_category_id, folder_id: folder.id).all!
|
71
|
+
|
72
|
+
articles.each do |article|
|
73
|
+
article_xml = build_article_xml(article)
|
74
|
+
|
75
|
+
# write to resources config file
|
76
|
+
if config_folder = resources_config[:folders].detect { |f| f[:id] == folder.id }
|
77
|
+
(config_folder[:articles] ||= []) << { id: article.id }
|
78
|
+
else
|
79
|
+
abort 'No such folder!'
|
80
|
+
end
|
81
|
+
|
82
|
+
unless article_xml.nil?
|
83
|
+
articles_builder << build_article_hash(article).merge({ xml: article_xml })
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
crowdin_project_info = @crowdin.project_info
|
90
|
+
|
91
|
+
# Creates xml files for folders and upload to Crowdin
|
92
|
+
folders_builder.each do |folder|
|
93
|
+
file_name = "folder_#{folder[:id]}.xml"
|
94
|
+
|
95
|
+
o = File.new(File.join(resources_dir, file_name), 'w')
|
96
|
+
o.write folder[:xml].to_xml
|
97
|
+
o.close
|
98
|
+
|
99
|
+
if crowdin_project_info['files'].detect { |file| file['name'] == file_name }
|
100
|
+
puts "[Crowdin] Update file `#{file_name}`"
|
101
|
+
@crowdin.update_file(
|
102
|
+
files = [
|
103
|
+
{
|
104
|
+
source: File.join(resources_dir, file_name),
|
105
|
+
dest: file_name,
|
106
|
+
export_pattert: '/%two_letters_code%/%original_file_name%',
|
107
|
+
title: folder[:name]
|
108
|
+
}
|
109
|
+
], type: 'webxml'
|
110
|
+
)
|
111
|
+
else
|
112
|
+
puts "[Crowdin] Add file `#{file_name}`"
|
113
|
+
@crowdin.add_file(
|
114
|
+
files = [
|
115
|
+
{
|
116
|
+
source: File.join(resources_dir, file_name),
|
117
|
+
dest: file_name,
|
118
|
+
export_pattert: '/%two_letters_code%/%original_file_name%',
|
119
|
+
title: folder[:name]
|
120
|
+
}
|
121
|
+
], type: 'webxml'
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Creates xml files for articles and upload to Crowdin
|
127
|
+
articles_builder.each do |article|
|
128
|
+
file_name = "article_#{article[:id]}.xml"
|
129
|
+
|
130
|
+
o = File.new(File.join(resources_dir, file_name), 'w')
|
131
|
+
o.write article[:xml].to_xml
|
132
|
+
o.close
|
133
|
+
|
134
|
+
if crowdin_project_info['files'].detect { |file| file['name'] == file_name }
|
135
|
+
puts "[Crowdin] Update file `#{file_name}`"
|
136
|
+
@crowdin.update_file(
|
137
|
+
files = [
|
138
|
+
{
|
139
|
+
source: File.join(resources_dir, file_name),
|
140
|
+
dest: file_name,
|
141
|
+
export_pattert: '/%two_letters_code%/%original_file_name%',
|
142
|
+
title: article[:title]
|
143
|
+
}
|
144
|
+
], type: 'webxml'
|
145
|
+
)
|
146
|
+
else
|
147
|
+
puts "[Crowdin] Add file `#{file_name}`"
|
148
|
+
@crowdin.add_file(
|
149
|
+
files = [
|
150
|
+
{
|
151
|
+
source: File.join(resources_dir, file_name),
|
152
|
+
dest: file_name,
|
153
|
+
export_pattert: '/%two_letters_code%/%original_file_name%',
|
154
|
+
title: article[:title]
|
155
|
+
}
|
156
|
+
], type: 'webxml'
|
157
|
+
)
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Write resources config file
|
163
|
+
puts "Write config file"
|
164
|
+
File.open(resources_config_file, 'w') do |f|
|
165
|
+
f.write resources_config.to_yaml
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
desc 'Build and download last exported translation resources from Crowdin'
|
2
|
+
command :'download:translations' do |c|
|
3
|
+
c.desc 'Directory of resource files'
|
4
|
+
c.long_desc <<-EOS.strip_heredoc
|
5
|
+
This is the directory where the project's files will be store.
|
6
|
+
EOS
|
7
|
+
c.default_value 'resources'
|
8
|
+
c.arg_name 'dir'
|
9
|
+
c.flag [:resources_dir]
|
10
|
+
|
11
|
+
c.action do |global_options, options, args|
|
12
|
+
language = 'all'
|
13
|
+
tempfile = Tempfile.new(language)
|
14
|
+
zipfile_name = tempfile.path
|
15
|
+
resources_dir = options[:resources_dir]
|
16
|
+
|
17
|
+
base_path = File.join(Dir.pwd, resources_dir)
|
18
|
+
begin
|
19
|
+
export_translations!(@crowdin)
|
20
|
+
|
21
|
+
puts 'Downloading translations'
|
22
|
+
@crowdin.download_translation(language, output: zipfile_name)
|
23
|
+
|
24
|
+
base_path = File.join(Dir.pwd, resources_dir)
|
25
|
+
unzip_file_with_translations(zipfile_name, base_path)
|
26
|
+
ensure
|
27
|
+
tempfile.close
|
28
|
+
tempfile.unlink # delete the tempfile
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
desc 'Add or update localized resource files(folders and articles) in Freshdesk'
|
2
|
+
command :'export:translations' do |c|
|
3
|
+
c.desc 'Directory of resource files'
|
4
|
+
c.long_desc <<-EOS.strip_heredoc
|
5
|
+
This is the directory where the project's files will be store.
|
6
|
+
EOS
|
7
|
+
c.default_value 'resources'
|
8
|
+
c.arg_name 'dir'
|
9
|
+
c.flag [:resources_dir]
|
10
|
+
|
11
|
+
c.desc 'Resources config file'
|
12
|
+
c.long_desc <<-EOS.strip_heredoc
|
13
|
+
This is the config file where the information about project's files will be store.
|
14
|
+
EOS
|
15
|
+
c.default_value 'resources/.resources.yml'
|
16
|
+
c.arg_name 'file'
|
17
|
+
c.flag [:resources_config]
|
18
|
+
|
19
|
+
c.action do |global_options, options, args|
|
20
|
+
# DO NOT EDIT THIS FILE BY HAND!
|
21
|
+
resources_config_file = options[:resources_config]
|
22
|
+
resources_dir = options[:resources_dir]
|
23
|
+
|
24
|
+
# for store information about folders/articles ids
|
25
|
+
unless File.exists?(resources_config_file)
|
26
|
+
raise "Error! Config file does not exist. First run `push` command"
|
27
|
+
end
|
28
|
+
|
29
|
+
resources_config = YAML.load(File.open(resources_config_file))
|
30
|
+
|
31
|
+
if !resources_config || resources_config.nil? || resources_config.empty?
|
32
|
+
raise "Error! Resources config empty. First run `push` command"
|
33
|
+
end
|
34
|
+
|
35
|
+
@fci_config['translations'].each do |lang|
|
36
|
+
folder_xml_files = Dir["#{resources_dir}/#{lang['crowdin_language_code']}/folder_*.xml"]
|
37
|
+
article_xml_files = Dir["#{resources_dir}/#{lang['crowdin_language_code']}/article_*.xml"]
|
38
|
+
|
39
|
+
unless freshdesk_category = FreshdeskAPI::SolutionCategory.find(@freshdesk, id: lang['freshdesk_category_id'].to_i)
|
40
|
+
raise "Not such Category ID for language `#{lang['crowdin_language_code']}`in Freshdesk. Please create new one and set ID in config file."
|
41
|
+
end
|
42
|
+
|
43
|
+
all_folders = []
|
44
|
+
all_articles = []
|
45
|
+
|
46
|
+
# Read folders from XML files
|
47
|
+
folder_xml_files.each do |file|
|
48
|
+
# Load the xml file into a String
|
49
|
+
folder_xml_file = File.read(file)
|
50
|
+
|
51
|
+
folder = parse_folder_xml(folder_xml_file)
|
52
|
+
|
53
|
+
all_folders << folder
|
54
|
+
end
|
55
|
+
|
56
|
+
# Read articles from XML filse
|
57
|
+
article_xml_files.each do |file|
|
58
|
+
article_xml_file = File.read(file)
|
59
|
+
|
60
|
+
article = parse_article_xml(article_xml_file)
|
61
|
+
|
62
|
+
all_articles << article
|
63
|
+
end
|
64
|
+
|
65
|
+
### Folders ###
|
66
|
+
#
|
67
|
+
all_folders.each do |folder|
|
68
|
+
if config_folder = resources_config[:folders].detect { |f| f[:id].to_s == folder[:id].to_s }
|
69
|
+
|
70
|
+
config_folder[:translations] = [] unless config_folder[:translations]
|
71
|
+
|
72
|
+
# if Folder translation ID exists in config
|
73
|
+
if folder_translation = config_folder[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
74
|
+
# Get folder from Freshdesk and update it
|
75
|
+
freshdesk_folder = FreshdeskAPI::SolutionFolder.find(
|
76
|
+
@freshdesk,
|
77
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
78
|
+
id: folder_translation[:id]
|
79
|
+
)
|
80
|
+
|
81
|
+
# Remove Folder translation from config it it not found in Freshdesk
|
82
|
+
if freshdesk_folder.nil?
|
83
|
+
puts "Remove undefined Folder from config"
|
84
|
+
config_folder[:translations].delete_if { |tr| tr[:lang] == lang['crowdin_language_code'] }
|
85
|
+
|
86
|
+
puts "[Freshdesk] Create new Folder"
|
87
|
+
freshdesk_folder = FreshdeskAPI::SolutionFolder.create!(
|
88
|
+
@freshdesk,
|
89
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
90
|
+
name: folder[:name],
|
91
|
+
description: folder[:description],
|
92
|
+
visibility: 1
|
93
|
+
)
|
94
|
+
|
95
|
+
config_folder[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_folder.id }
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
if freshdesk_folder.attributes[:name] != folder[:name] || freshdesk_folder.attributes[:description] != folder[:description]
|
100
|
+
puts "[Freshdesk] Update existing Folder"
|
101
|
+
freshdesk_folder.update!(name: folder[:name], description: folder[:description])
|
102
|
+
else
|
103
|
+
puts "[Freshdesk] Nothing to update. An existing Folder still the same."
|
104
|
+
end
|
105
|
+
|
106
|
+
else
|
107
|
+
# create new folder in Freshdesk and save id to config file
|
108
|
+
puts "[Freshdesk] Create new Folder"
|
109
|
+
freshdesk_folder = FreshdeskAPI::SolutionFolder.create!(
|
110
|
+
@freshdesk,
|
111
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
112
|
+
name: folder[:name],
|
113
|
+
description: folder[:description],
|
114
|
+
visibility: 1
|
115
|
+
)
|
116
|
+
|
117
|
+
config_folder[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_folder.id }
|
118
|
+
end
|
119
|
+
else
|
120
|
+
abort "No such folder!"
|
121
|
+
end
|
122
|
+
end # all_folders
|
123
|
+
|
124
|
+
### Articles ###
|
125
|
+
#
|
126
|
+
all_articles.each do |article|
|
127
|
+
if config_folder = resources_config[:folders].detect { |f| f[:id].to_s == article[:folder_id].to_s }
|
128
|
+
unless folder_translation = config_folder[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
129
|
+
abort "No `#{lang['crowdin_language_code']}` translations for folder"
|
130
|
+
end
|
131
|
+
|
132
|
+
if config_article = config_folder[:articles].detect { |f| f[:id].to_s == article[:id].to_s }
|
133
|
+
config_article[:translations] = [] unless config_article[:translations]
|
134
|
+
|
135
|
+
# if Article translation ID exists in config - update article on Freshdesk
|
136
|
+
if article_translation = config_article[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
137
|
+
freshdesk_article = FreshdeskAPI::SolutionArticle.find(
|
138
|
+
@freshdesk,
|
139
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
140
|
+
folder_id: folder_translation[:id],
|
141
|
+
id: article_translation[:id]
|
142
|
+
)
|
143
|
+
|
144
|
+
# Remove Article translation from config if it not found in Freshdesk
|
145
|
+
if freshdesk_article.nil?
|
146
|
+
puts "Remove undefined Article from config"
|
147
|
+
config_article[:translations].delete_if { |tr| tr[:lang] == lang['crowdin_language_code'] }
|
148
|
+
|
149
|
+
puts "[Freshdesk] Create new Article"
|
150
|
+
freshdesk_article = FreshdeskAPI::SolutionArticle.create!(
|
151
|
+
@freshdesk,
|
152
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
153
|
+
folder_id: folder_translation[:id],
|
154
|
+
title: article[:title],
|
155
|
+
description: article[:description]
|
156
|
+
)
|
157
|
+
config_article[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_article.id }
|
158
|
+
next
|
159
|
+
end
|
160
|
+
|
161
|
+
if freshdesk_article.attributes[:title] != article[:title] || freshdesk_article.attributes[:description] != article[:description]
|
162
|
+
puts "[Freshdesk] Update existing Article"
|
163
|
+
|
164
|
+
freshdesk_article.update!(
|
165
|
+
title: article[:title],
|
166
|
+
description: article[:description]
|
167
|
+
)
|
168
|
+
else
|
169
|
+
puts "[Freshdesk] Nothing to update. An existing Article still the same."
|
170
|
+
end
|
171
|
+
|
172
|
+
else
|
173
|
+
# creates new article on Freshdesk and save ID to config file
|
174
|
+
if folder_translation = config_folder[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
175
|
+
# do nothing for now
|
176
|
+
else
|
177
|
+
abort "No translation for this folder"
|
178
|
+
end
|
179
|
+
|
180
|
+
puts "[Freshdesk] Create new Article"
|
181
|
+
freshdesk_article = FreshdeskAPI::SolutionArticle.create!(
|
182
|
+
@freshdesk,
|
183
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
184
|
+
folder_id: folder_translation[:id],
|
185
|
+
title: article[:title],
|
186
|
+
description: article[:description]
|
187
|
+
)
|
188
|
+
config_article[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_article.id }
|
189
|
+
end
|
190
|
+
else
|
191
|
+
abort "No such article!"
|
192
|
+
end
|
193
|
+
else
|
194
|
+
abort "No such folder!"
|
195
|
+
end
|
196
|
+
end # all_articles
|
197
|
+
|
198
|
+
puts "Write info about localization to config"
|
199
|
+
File.open(resources_config_file, 'w') do |f|
|
200
|
+
f.write resources_config.to_yaml
|
201
|
+
end
|
202
|
+
|
203
|
+
end # @fci_config['translations']
|
204
|
+
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
data/lib/fci/download.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module FCI
|
2
|
+
def unzip_file_with_translations(zipfile_name, dest_path)
|
3
|
+
# overwrite files if they already exist inside of the extracted path
|
4
|
+
Zip.on_exists_proc = true
|
5
|
+
|
6
|
+
Zip::File.open(zipfile_name) do |zip_file|
|
7
|
+
zip_file.select { |zip_entry| zip_entry.file? }.each do |f|
|
8
|
+
# `f' - relative path in archive
|
9
|
+
fpath = File.join(dest_path, f.name)
|
10
|
+
FileUtils.mkdir_p(File.dirname(fpath))
|
11
|
+
puts "Extracting: `#{dest_path}/#{f.name}'"
|
12
|
+
zip_file.extract(f, fpath)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# use export API method before to download the most recent translations
|
18
|
+
def export_translations!(crowdin)
|
19
|
+
print 'Building ZIP archive with the latest translations '
|
20
|
+
export_translations = crowdin.export_translations
|
21
|
+
if export_translations['success']
|
22
|
+
if export_translations['success']['status'] == 'built'
|
23
|
+
puts "- OK"
|
24
|
+
elsif export_translations['success']['status'] == 'skipped'
|
25
|
+
puts "- Skipped"
|
26
|
+
puts "Warning: Export was skipped. Please note that this method can be invoked only once per 30 minutes."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/fci/export.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module FCI
|
2
|
+
def parse_folder_xml(folder_xml_file)
|
3
|
+
doc = Nokogiri::XML.parse(folder_xml_file)
|
4
|
+
folder_xml = doc.xpath("//folder").first
|
5
|
+
|
6
|
+
folder = {
|
7
|
+
id: folder_xml[:id],
|
8
|
+
name: folder_xml.xpath('name').text,
|
9
|
+
description: folder_xml.xpath('name').text,
|
10
|
+
position: folder_xml[:position],
|
11
|
+
}
|
12
|
+
|
13
|
+
return folder
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_article_xml(article_xml_file)
|
17
|
+
doc = Nokogiri::XML.parse(article_xml_file)
|
18
|
+
article_xml = doc.xpath('//article').first
|
19
|
+
|
20
|
+
article = {
|
21
|
+
id: article_xml[:id],
|
22
|
+
position: article_xml[:position],
|
23
|
+
folder_id: article_xml[:folder_id],
|
24
|
+
title: article_xml.xpath('title').text,
|
25
|
+
description: article_xml.xpath('description').text,
|
26
|
+
}
|
27
|
+
|
28
|
+
return article
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/fci/helpers.rb
ADDED
data/lib/fci/import.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module FCI
|
2
|
+
def build_folder_xml(folder)
|
3
|
+
attr = folder.attributes
|
4
|
+
|
5
|
+
folder_xml = Nokogiri::XML::Builder.new do |xml|
|
6
|
+
xml.root {
|
7
|
+
# id - id of the original folder
|
8
|
+
xml.folder(id: folder.id, position: attr[:position], identifier: 'folder', type: 'document') {
|
9
|
+
xml.name {
|
10
|
+
xml.cdata attr[:name]
|
11
|
+
}
|
12
|
+
xml.description {
|
13
|
+
xml.cdata attr[:description]
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
return folder_xml
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_article_xml(article)
|
23
|
+
attr = article.attributes
|
24
|
+
|
25
|
+
article_xml = Nokogiri::XML::Builder.new do |xml|
|
26
|
+
xml.root {
|
27
|
+
# id - id of the original acticle
|
28
|
+
# folder_id - id of the original folder
|
29
|
+
xml.article(id: article.id, folder_id: attr[:folder_id], position: attr[:position], identifier: 'article', type: 'document') {
|
30
|
+
xml.title {
|
31
|
+
xml.cdata attr[:title]
|
32
|
+
}
|
33
|
+
xml.description {
|
34
|
+
xml.cdata attr[:description]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
return article_xml
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_folder_hash(folder)
|
44
|
+
attr = folder.attributes
|
45
|
+
|
46
|
+
return {
|
47
|
+
id: folder.id,
|
48
|
+
position: attr[:position],
|
49
|
+
name: attr[:name],
|
50
|
+
description: attr[:description],
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_article_hash(article)
|
55
|
+
attr = article.attributes
|
56
|
+
|
57
|
+
return {
|
58
|
+
id: article.id,
|
59
|
+
folder_id: attr[:folder_id],
|
60
|
+
position: attr[:position],
|
61
|
+
title: attr[:title],
|
62
|
+
description: attr[:description],
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/lib/fci/init.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module FCI
|
4
|
+
def create_scaffold(root_dir, project_name, force)
|
5
|
+
dir = File.join(root_dir, project_name)
|
6
|
+
|
7
|
+
if mkdir(dir, force)
|
8
|
+
mk_config(root_dir, project_name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def mkdir(dir, force)
|
13
|
+
exists = false
|
14
|
+
if !force
|
15
|
+
if File.exist? dir
|
16
|
+
raise "#{dir} exists; use --force to override"
|
17
|
+
exists = true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if !exists
|
22
|
+
puts "Creating dir #{dir}..."
|
23
|
+
FileUtils.mkdir_p dir
|
24
|
+
else
|
25
|
+
puts "Exiting..."
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def mk_config(root_dir, project_name)
|
33
|
+
config = <<-EOS.strip_heredoc
|
34
|
+
---
|
35
|
+
# Crowdin API credentials
|
36
|
+
crowdin_project_id: '<%your-crowdin-project-id%>'
|
37
|
+
crowdin_api_key: '<%your-crowdin-api-key%>'
|
38
|
+
crowdin_base_url: 'https://api.crowdin.com'
|
39
|
+
|
40
|
+
# Freshdesk API credentials
|
41
|
+
freshdesk_base_url: 'https://<%subdomain%>.freshdesk.com'
|
42
|
+
freshdesk_username: '<%your-freshdek-username%>'
|
43
|
+
freshdesk_password: '<%your-freshdesk-password%>'
|
44
|
+
|
45
|
+
freshdesk_category: '<%freshdesk-category-id%>'
|
46
|
+
|
47
|
+
translations:
|
48
|
+
-
|
49
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
50
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
51
|
+
-
|
52
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
53
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
54
|
+
EOS
|
55
|
+
|
56
|
+
File.open("#{root_dir}/#{project_name}/fci.yml", 'w') do |file|
|
57
|
+
file << config
|
58
|
+
end
|
59
|
+
|
60
|
+
puts "Created #{root_dir}/#{project_name}/fci.yml"
|
61
|
+
end
|
62
|
+
end
|
data/lib/fci/version.rb
ADDED
data/lib/fci.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'freshdesk_api'
|
2
|
+
require 'crowdin-api'
|
3
|
+
require 'byebug'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'zip'
|
6
|
+
require 'fci/version.rb'
|
7
|
+
|
8
|
+
# Add requires for other files you add to your project here, so
|
9
|
+
# you just need to require this one file in your bin file
|
10
|
+
require 'fci/helpers.rb'
|
11
|
+
require 'fci/init.rb'
|
12
|
+
require 'fci/import.rb'
|
13
|
+
require 'fci/download.rb'
|
14
|
+
require 'fci/export.rb'
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fci
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anton Maminov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubyzip
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: crowdin-api
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: freshdesk_api
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rdoc
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: aruba
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: gli
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 2.13.0
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 2.13.0
|
139
|
+
description:
|
140
|
+
email: anton.maminov@gmail.com
|
141
|
+
executables:
|
142
|
+
- fci
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".ruby-gemset"
|
148
|
+
- ".ruby-version"
|
149
|
+
- Gemfile
|
150
|
+
- LICENSE
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- bin/fci
|
154
|
+
- fci.gemspec
|
155
|
+
- fci.yml.example
|
156
|
+
- features/fci.feature
|
157
|
+
- features/step_definitions/fci_steps.rb
|
158
|
+
- features/support/env.rb
|
159
|
+
- lib/fci.rb
|
160
|
+
- lib/fci/commands/01_init.rb
|
161
|
+
- lib/fci/commands/02_import.rb
|
162
|
+
- lib/fci/commands/03_download.rb
|
163
|
+
- lib/fci/commands/04_export.rb
|
164
|
+
- lib/fci/download.rb
|
165
|
+
- lib/fci/export.rb
|
166
|
+
- lib/fci/helpers.rb
|
167
|
+
- lib/fci/import.rb
|
168
|
+
- lib/fci/init.rb
|
169
|
+
- lib/fci/version.rb
|
170
|
+
- test/default_test.rb
|
171
|
+
- test/test_helper.rb
|
172
|
+
homepage: https://github.com/mamantoha/fci
|
173
|
+
licenses: []
|
174
|
+
metadata: {}
|
175
|
+
post_install_message:
|
176
|
+
rdoc_options: []
|
177
|
+
require_paths:
|
178
|
+
- lib
|
179
|
+
- lib
|
180
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
requirements: []
|
191
|
+
rubyforge_project:
|
192
|
+
rubygems_version: 2.4.6
|
193
|
+
signing_key:
|
194
|
+
specification_version: 4
|
195
|
+
summary: Freshdesk and Crowdin integration Command Line Interface (CLI)
|
196
|
+
test_files: []
|