rosette-client 1.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.
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rosette
4
+ module Client
5
+
6
+ class Repo
7
+ attr_reader :path
8
+
9
+ def initialize(path)
10
+ @path = path
11
+ end
12
+
13
+ def get_head
14
+ execute_in_repo('git symbolic-ref --short HEAD').strip
15
+ end
16
+
17
+ def rev_parse(ref)
18
+ commit_id = execute_in_repo("git rev-parse #{ref}").strip
19
+ commit_id ? commit_id : nil
20
+ end
21
+
22
+ private
23
+
24
+ def execute_in_repo(cmd)
25
+ Dir.chdir(path) do
26
+ `#{cmd}`
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rosette
4
+ module Client
5
+
6
+ class Response
7
+ attr_reader :attributes
8
+
9
+ def self.from_api_response(hash)
10
+ new(hash)
11
+ end
12
+
13
+ def initialize(hash)
14
+ @attributes = hash
15
+ end
16
+
17
+ def error?
18
+ attributes.include?('error')
19
+ end
20
+
21
+ def success?
22
+ !error?
23
+ end
24
+
25
+ def method_missing(method, *args, &block)
26
+ if attributes.include?(method.to_s)
27
+ attributes[method.to_s]
28
+ end
29
+ end
30
+
31
+ # responds to everything, returns nil for any unset attributes
32
+ def respond_to?(method)
33
+ true
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'colorize'
4
+
5
+ module Rosette
6
+ module Client
7
+ class Terminal
8
+
9
+ attr_reader :stream
10
+
11
+ def initialize(stream = STDOUT)
12
+ @stream = stream
13
+ end
14
+
15
+ def say(str, color = :none)
16
+ stream.write(colorize(str, color))
17
+ stream.write("\n")
18
+ end
19
+
20
+ private
21
+
22
+ def colorize(str, color)
23
+ case color
24
+ when :none
25
+ str
26
+ else
27
+ str.colorize(color)
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rosette
4
+ module Client
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rosette/client/cli'
4
+ require 'rosette/client/repo'
5
+
6
+ module Rosette
7
+ module Client
8
+ autoload :Api, 'rosette/client/api'
9
+ autoload :Terminal, 'rosette/client/terminal'
10
+ autoload :Commands, 'rosette/client/commands'
11
+ autoload :Response, 'rosette/client/response'
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+ require 'rosette/client/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "rosette-client"
6
+ s.version = ::Rosette::Client::VERSION
7
+ s.authors = ["Cameron Dutro"]
8
+ s.email = ["camertron@gmail.com"]
9
+ s.homepage = "http://github.com/camertron"
10
+
11
+ s.description = s.summary = "Git command integration for the Rosette internationalization platform that manages the translatable content in the source files of a git repository."
12
+
13
+ s.platform = Gem::Platform::RUBY
14
+ s.has_rdoc = true
15
+
16
+ s.add_dependency 'colorize', '~> 0.7.0'
17
+ s.add_dependency 'json', '~> 1.8.0'
18
+
19
+ s.executables << 'git-rosette'
20
+
21
+ s.require_path = 'lib'
22
+ s.files = Dir["{lib,spec}/**/*", "Gemfile", "History.txt", "README.md", "Rakefile", "rosette-client.gemspec"]
23
+ end
data/spec/api_spec.rb ADDED
@@ -0,0 +1,96 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Client
6
+
7
+ describe Api do
8
+ let(:api_class) { Api }
9
+
10
+ it 'uses default options' do
11
+ api_class.new.tap do |api|
12
+ expect(api.host).to eq('localhost')
13
+ expect(api.port).to eq(8080)
14
+ expect(api.version).to eq('v1')
15
+ end
16
+ end
17
+
18
+ it 'uses only some default options' do
19
+ api_class.new(host: 'foo.com').tap do |api|
20
+ expect(api.host).to eq('foo.com')
21
+ expect(api.port).to eq(8080)
22
+ expect(api.version).to eq('v1')
23
+ end
24
+ end
25
+
26
+ shared_examples 'an api endpoint' do
27
+ let(:api) { api_class.new }
28
+ let(:params) { { param: 'value' } }
29
+ let(:endpoint) { method }
30
+
31
+ before(:each) do
32
+ url = "http://localhost:8080/v1/#{path}"
33
+
34
+ args = case verb
35
+ when :get
36
+ ["#{url}/#{endpoint_override rescue endpoint}.json/?param=value"]
37
+ else
38
+ ["#{url}/#{endpoint_override rescue endpoint}.json", params]
39
+ end
40
+
41
+ allow(api).to receive(verb).with(*args).and_return('{"foo":"bar"}')
42
+ end
43
+
44
+ it 'wraps the response in a Response object' do
45
+ expect(api.send(endpoint, params)).to be_a(Response)
46
+ end
47
+ end
48
+
49
+ context 'get requests' do
50
+ let(:verb) { :get }
51
+
52
+ describe '#diff' do
53
+ let(:path) { 'git' }
54
+ let(:method) { :diff }
55
+ it_behaves_like 'an api endpoint'
56
+ end
57
+
58
+ describe '#show' do
59
+ let(:path) { 'git' }
60
+ let(:method) { :show }
61
+ it_behaves_like 'an api endpoint'
62
+ end
63
+
64
+ describe '#status' do
65
+ let(:path) { 'git' }
66
+ let(:method) { :status }
67
+ it_behaves_like 'an api endpoint'
68
+ end
69
+
70
+ describe '#commit' do
71
+ let(:path) { 'git' }
72
+ let(:method) { :commit }
73
+ it_behaves_like 'an api endpoint'
74
+ end
75
+
76
+ describe '#snapshot' do
77
+ let(:path) { 'git' }
78
+ let(:method) { :snapshot }
79
+ it_behaves_like 'an api endpoint'
80
+ end
81
+
82
+ describe '#repo_snapshot' do
83
+ let(:path) { 'git' }
84
+ let(:method) { :repo_snapshot }
85
+ it_behaves_like 'an api endpoint'
86
+ end
87
+
88
+ describe '#add_or_update_translation' do
89
+ let(:path) { 'translations' }
90
+ let(:method) { :add_or_update_translation }
91
+ let(:endpoint_override) { 'add_or_update' }
92
+ let(:verb) { :post }
93
+ it_behaves_like 'an api endpoint'
94
+ end
95
+ end
96
+ end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Client
6
+
7
+ describe Cli do
8
+ let(:api) { double }
9
+ let(:base_repo) { TmpRepo.new }
10
+ let(:repo) { Repo.new(base_repo.working_dir) }
11
+ let(:terminal) { FakeTerminal.new }
12
+ let(:cli) { Cli.new(terminal, api, repo) }
13
+
14
+ before(:each) do
15
+ add_user_to(base_repo)
16
+ end
17
+
18
+ describe '#start' do
19
+ it 'resolves the command into a class and executes it' do
20
+ base_repo.create_file('file.txt') { |f| f.write('hello, world') }
21
+ base_repo.add_all
22
+ base_repo.commit('Initial commit')
23
+
24
+ expect(api).to receive(:commit).and_return(Response.new({ 'foo' => 'bar' }))
25
+ cli.start(['commit', base_repo.git('rev-parse HEAD').strip])
26
+ end
27
+
28
+ it "prints a message if the command isn't recognized" do
29
+ cli.start(['foobar'])
30
+ expect(terminal).to have_said("Command 'foobar' not recognized.")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Client
6
+ include Rosette::Client::Commands
7
+
8
+ describe CommitCommand do
9
+ let(:api) { double }
10
+ let(:base_repo) { TmpRepo.new }
11
+ let(:repo) { Repo.new(base_repo.working_dir) }
12
+ let(:terminal) { FakeTerminal.new }
13
+ let(:repo_name) { 'my_awesome_repo' }
14
+ let(:commit_id) { base_repo.git('rev-parse HEAD').strip }
15
+ let(:command) { CommitCommand.new(api, terminal, repo, [commit_id]) }
16
+
17
+ before(:each) do
18
+ add_user_to(base_repo)
19
+ base_repo.git("remote add origin git@github.com/camertron/#{repo_name}")
20
+ base_repo.create_file('file.txt') { |f| f.write('hello, world') }
21
+ base_repo.add_all
22
+ base_repo.commit('Initial commit')
23
+ end
24
+
25
+ around(:each) do |example|
26
+ Dir.chdir(base_repo.working_dir) do
27
+ example.run
28
+ end
29
+ end
30
+
31
+ describe '#execute' do
32
+ it 'makes a commit api call' do
33
+ expect(api).to receive(:commit)
34
+ .with(repo_name: repo_name, ref: commit_id)
35
+ .and_return(Response.new({}))
36
+
37
+ command.execute
38
+ end
39
+
40
+ it 'prints the number of phrases added, removed, and modified' do
41
+ expect(api).to receive(:commit)
42
+ .with(repo_name: repo_name, ref: commit_id)
43
+ .and_return(
44
+ Response.new(
45
+ { 'added' => 1, 'removed' => 2, 'modified' => 3 }
46
+ )
47
+ )
48
+
49
+ command.execute
50
+
51
+ expect(terminal).to have_said('Added: 1')
52
+ expect(terminal).to have_said('Removed: 2')
53
+ expect(terminal).to have_said('Modified: 3')
54
+ end
55
+
56
+ it 'prints the error if the api response contains one' do
57
+ expect(api).to receive(:commit)
58
+ .with(repo_name: repo_name, ref: commit_id)
59
+ .and_return(
60
+ Response.new({ 'error' => 'Jelly beans', 'added' => 1 })
61
+ )
62
+
63
+ command.execute
64
+
65
+ expect(terminal).to have_said('Jelly beans')
66
+ expect(terminal).to_not have_said('Added: 1')
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,151 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Client
6
+ include Rosette::Client::Commands
7
+
8
+ describe 'diff' do
9
+ let(:args) { DiffCommandArgs }
10
+ let(:base_repo) { TmpRepo.new }
11
+ let(:repo) { Repo.new(base_repo.working_dir) }
12
+ let(:repo_name) { 'my_awesome_repo' }
13
+ let(:new_branch) { 'new_branch' }
14
+ let(:new_branch_commit_id) { base_repo.git("rev-parse #{new_branch}").strip }
15
+ let(:master_commit_id) { base_repo.git("rev-parse master").strip }
16
+
17
+ before(:each) do
18
+ add_user_to(base_repo)
19
+ base_repo.git("remote add origin git@github.com/camertron/#{repo_name}")
20
+ base_repo.create_file('file.txt') { |f| f.write('hello, world') }
21
+ base_repo.add_all
22
+ base_repo.commit('Initial commit')
23
+ base_repo.create_branch(new_branch)
24
+ base_repo.create_file('file2.txt') { |f| f.write('another file') }
25
+ base_repo.add_all
26
+ base_repo.commit('Second file')
27
+ end
28
+
29
+ around(:each) do |example|
30
+ Dir.chdir(base_repo.working_dir) do
31
+ example.run
32
+ end
33
+ end
34
+
35
+ describe DiffCommandArgs do
36
+ it "uses the default head if one isn't provided" do
37
+ args.from_argv(['master'], repo).tap do |args|
38
+ expect(args.diff_point_ref).to eq(master_commit_id)
39
+ expect(args.head_ref).to eq(new_branch_commit_id)
40
+ expect(args.paths).to eq([])
41
+ end
42
+ end
43
+
44
+ it 'accepts both head and diff point as the first two arguments' do
45
+ args.from_argv(['master', new_branch], repo).tap do |args|
46
+ expect(args.diff_point_ref).to eq(master_commit_id)
47
+ expect(args.head_ref).to eq(new_branch)
48
+ expect(args.paths).to eq([])
49
+ end
50
+ end
51
+
52
+ it 'allows the second argument to be a path' do
53
+ args.from_argv(['master', '.'], repo).tap do |args|
54
+ expect(args.diff_point_ref).to eq(master_commit_id)
55
+ expect(args.head_ref).to eq(new_branch_commit_id)
56
+ expect(args.paths).to eq(['.'])
57
+ end
58
+ end
59
+
60
+ it 'allows multiple paths' do
61
+ args.from_argv(['master', 'file.txt', 'file2.txt'], repo).tap do |args|
62
+ expect(args.diff_point_ref).to eq(master_commit_id)
63
+ expect(args.head_ref).to eq(new_branch_commit_id)
64
+ expect(args.paths).to eq(['file.txt', 'file2.txt'])
65
+ end
66
+ end
67
+
68
+ it 'allows paths to be separated by --' do
69
+ args.from_argv(['master', '--', 'file.txt', 'file2.txt'], repo).tap do |args|
70
+ expect(args.diff_point_ref).to eq(master_commit_id)
71
+ expect(args.head_ref).to eq(new_branch_commit_id)
72
+ expect(args.paths).to eq(['file.txt', 'file2.txt'])
73
+ end
74
+ end
75
+
76
+ it 'allows a head and diff point followed by -- and paths' do
77
+ args.from_argv(['master', new_branch, '--', 'file.txt', 'file2.txt'], repo).tap do |args|
78
+ expect(args.diff_point_ref).to eq(master_commit_id)
79
+ expect(args.head_ref).to eq(new_branch)
80
+ expect(args.paths).to eq(['file.txt', 'file2.txt'])
81
+ end
82
+ end
83
+ end
84
+
85
+ describe DiffCommand do
86
+ let(:api) { double }
87
+ let(:command) { DiffCommand.new(api, terminal, repo, [master_commit_id, new_branch_commit_id]) }
88
+ let(:terminal) { FakeTerminal.new }
89
+
90
+ describe '#execute' do
91
+ it 'makes a diff api call' do
92
+ expect(api).to receive(:diff)
93
+ .with(
94
+ repo_name: repo_name,
95
+ head_ref: new_branch_commit_id,
96
+ diff_point_ref: master_commit_id,
97
+ paths: ''
98
+ )
99
+ .and_return(Response.new({}))
100
+
101
+ command.execute
102
+ end
103
+
104
+ it 'prints the number of phrases added, removed, and modified' do
105
+ expect(api).to receive(:diff)
106
+ .with(
107
+ repo_name: repo_name,
108
+ head_ref: new_branch_commit_id,
109
+ diff_point_ref: master_commit_id,
110
+ paths: ''
111
+ )
112
+ .and_return(
113
+ Response.new(
114
+ sample_diff(new_branch_commit_id)
115
+ )
116
+ )
117
+
118
+ command.execute
119
+
120
+ expect(terminal).to have_said("+ I'm a little teapot (about.training.teapot)", :green)
121
+ expect(terminal).to have_said('- The green albatross flitters in the moonlight (animals.birds.albatross.message)', :red)
122
+
123
+ expect(terminal).to have_said('+ Purple eggplants make delicious afternoon snacks (foods.vegetables.eggplant.snack_message)', :green)
124
+ expect(terminal).to have_said('- Blue eggplants make wonderful evening meals (foods.vegetables.eggplant.snack_message)', :red)
125
+
126
+ expect(terminal).to have_said('+ The Seattle Seahawks rock (sports.teams.football.best)', :green)
127
+ expect(terminal).to have_said('- The Seattle Seahawks rule (sports.teams.football.best)', :red)
128
+ end
129
+
130
+ it 'prints the error if the api response contains one' do
131
+ expect(api).to receive(:diff)
132
+ .with(
133
+ repo_name: repo_name,
134
+ head_ref: new_branch_commit_id,
135
+ diff_point_ref: master_commit_id,
136
+ paths: ''
137
+ )
138
+ .and_return(
139
+ Response.new({ 'error' => 'Jelly beans' }.merge(
140
+ sample_diff(new_branch_commit_id))
141
+ )
142
+ )
143
+
144
+ command.execute
145
+
146
+ expect(terminal).to have_said('Jelly beans')
147
+ expect(terminal).to_not have_said("+ I'm a little teapot (about.training.teapot)", :green)
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Client
6
+ include Rosette::Client::Commands
7
+
8
+ describe RepoSnapshotCommand do
9
+ let(:api) { double }
10
+ let(:base_repo) { TmpRepo.new }
11
+ let(:repo) { Repo.new(base_repo.working_dir) }
12
+ let(:terminal) { FakeTerminal.new }
13
+ let(:repo_name) { 'my_awesome_repo' }
14
+ let(:commit_id) { base_repo.git('rev-parse HEAD').strip }
15
+ let(:command) { RepoSnapshotCommand.new(api, terminal, repo, [commit_id]) }
16
+
17
+ before(:each) do
18
+ add_user_to(base_repo)
19
+ base_repo.git("remote add origin git@github.com/camertron/#{repo_name}")
20
+ base_repo.create_file('file.txt') { |f| f.write('hello, world') }
21
+ base_repo.add_all
22
+ base_repo.commit('Initial commit')
23
+ end
24
+
25
+ around(:each) do |example|
26
+ Dir.chdir(base_repo.working_dir) do
27
+ example.run
28
+ end
29
+ end
30
+
31
+ describe '#execute' do
32
+ it 'makes a repo_snapshot api call' do
33
+ expect(api).to receive(:repo_snapshot)
34
+ .with(repo_name: repo_name, ref: commit_id)
35
+ .and_return(Response.new({}))
36
+
37
+ command.execute
38
+ end
39
+
40
+ it 'prints the hash of files to commit ids' do
41
+ expect(api).to receive(:repo_snapshot)
42
+ .with(repo_name: repo_name, ref: commit_id)
43
+ .and_return(
44
+ Response.new({
45
+ 'file1.txt' => 'abc123',
46
+ 'path/file2.txt' => 'def456',
47
+ 'my/awesome/file3.rb' => 'ghi789'
48
+ })
49
+ )
50
+
51
+ command.execute
52
+
53
+ expect(terminal).to have_said('file1.txt: abc123')
54
+ expect(terminal).to have_said('path/file2.txt: def456')
55
+ expect(terminal).to have_said('my/awesome/file3.rb: ghi789')
56
+ end
57
+
58
+ it 'prints the error if the api response contains one' do
59
+ expect(api).to receive(:repo_snapshot)
60
+ .with(repo_name: repo_name, ref: commit_id)
61
+ .and_return(
62
+ Response.new({ 'error' => 'Jelly beans', 'file1.txt' => 'abc123' })
63
+ )
64
+
65
+ command.execute
66
+
67
+ expect(terminal).to have_said('Jelly beans')
68
+ expect(terminal).to_not have_said('file1.txt: abc123')
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Client
6
+ include Rosette::Client::Commands
7
+
8
+ describe ShowCommand do
9
+ let(:api) { double }
10
+ let(:base_repo) { TmpRepo.new }
11
+ let(:repo) { Repo.new(base_repo.working_dir) }
12
+ let(:terminal) { FakeTerminal.new }
13
+ let(:repo_name) { 'my_awesome_repo' }
14
+ let(:commit_id) { base_repo.git('rev-parse HEAD').strip }
15
+ let(:command) { ShowCommand.new(api, terminal, repo, [commit_id]) }
16
+
17
+ before(:each) do
18
+ add_user_to(base_repo)
19
+ base_repo.git("remote add origin git@github.com/camertron/#{repo_name}")
20
+ base_repo.create_file('file.txt') { |f| f.write('hello, world') }
21
+ base_repo.add_all
22
+ base_repo.commit('Initial commit')
23
+ end
24
+
25
+ around(:each) do |example|
26
+ Dir.chdir(base_repo.working_dir) do
27
+ example.run
28
+ end
29
+ end
30
+
31
+ describe '#execute' do
32
+ it 'makes a commit api call' do
33
+ expect(api).to receive(:show)
34
+ .with(repo_name: repo_name, ref: commit_id)
35
+ .and_return(Response.new({}))
36
+
37
+ command.execute
38
+ end
39
+
40
+ it 'prints the phrases that were added, removed, and modified' do
41
+ expect(api).to receive(:show)
42
+ .with(repo_name: repo_name, ref: commit_id)
43
+ .and_return(
44
+ Response.new(sample_diff(commit_id))
45
+ )
46
+
47
+ command.execute
48
+
49
+ expect(terminal).to have_said("+ I'm a little teapot (about.training.teapot)", :green)
50
+ expect(terminal).to have_said('- The green albatross flitters in the moonlight (animals.birds.albatross.message)', :red)
51
+
52
+ expect(terminal).to have_said('+ Purple eggplants make delicious afternoon snacks (foods.vegetables.eggplant.snack_message)', :green)
53
+ expect(terminal).to have_said('- Blue eggplants make wonderful evening meals (foods.vegetables.eggplant.snack_message)', :red)
54
+
55
+ expect(terminal).to have_said('+ The Seattle Seahawks rock (sports.teams.football.best)', :green)
56
+ expect(terminal).to have_said('- The Seattle Seahawks rule (sports.teams.football.best)', :red)
57
+ end
58
+
59
+ it 'prints the error if the api response contains one' do
60
+ expect(api).to receive(:show)
61
+ .with(repo_name: repo_name, ref: commit_id)
62
+ .and_return(
63
+ Response.new({ 'error' => 'Jelly beans' }.merge(sample_diff(commit_id)))
64
+ )
65
+
66
+ command.execute
67
+
68
+ expect(terminal).to have_said('Jelly beans')
69
+ expect(terminal).to_not have_said("+ I'm a little teapot (about.training.teapot)", :green)
70
+ end
71
+ end
72
+ end