shift-client 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/Gemfile +9 -0
- data/Gemfile.lock +100 -0
- data/README.md +187 -0
- data/Rakefile +4 -0
- data/bin/shift-client +133 -0
- data/lib/shift_client.rb +132 -0
- data/lib/shift_client/version.rb +3 -0
- data/shift-client.gemspec +28 -0
- data/spec/client_spec.rb +70 -0
- data/spec/unit_helper.rb +8 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 07021bd3baceae897cab260d54bfa16bc277941a
|
4
|
+
data.tar.gz: 54234ff75fba07bc2d216f2ee739428fbf8e7276
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cbe652fbbb545248a7e8d11ea8c7b8a3ccb2777b778ce6bee416a311156e781a1991938581501965253457d87d9e512fc1cae48347eb9158bdfa551bdb71fe44
|
7
|
+
data.tar.gz: 2a864e2b1b9394418d7cf1c4aa7fb855aa2fef6af137b44186620397dc74e7781c680ff26f8d099d8339162ee6422d67064990d26ea8e3c10cb5f16203b97ea7
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionpack (5.0.0)
|
5
|
+
actionview (= 5.0.0)
|
6
|
+
activesupport (= 5.0.0)
|
7
|
+
rack (~> 2.0)
|
8
|
+
rack-test (~> 0.6.3)
|
9
|
+
rails-dom-testing (~> 2.0)
|
10
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
11
|
+
actionview (5.0.0)
|
12
|
+
activesupport (= 5.0.0)
|
13
|
+
builder (~> 3.1)
|
14
|
+
erubis (~> 2.7.0)
|
15
|
+
rails-dom-testing (~> 2.0)
|
16
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
17
|
+
activesupport (5.0.0)
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
19
|
+
i18n (~> 0.7)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
tzinfo (~> 1.1)
|
22
|
+
builder (3.2.2)
|
23
|
+
colored (1.2)
|
24
|
+
commander (4.4.0)
|
25
|
+
highline (~> 1.7.2)
|
26
|
+
concurrent-ruby (1.0.2)
|
27
|
+
diff-lcs (1.2.5)
|
28
|
+
domain_name (0.5.20160310)
|
29
|
+
unf (>= 0.0.5, < 1.0.0)
|
30
|
+
erubis (2.7.0)
|
31
|
+
highline (1.7.8)
|
32
|
+
http-cookie (1.0.2)
|
33
|
+
domain_name (~> 0.5)
|
34
|
+
i18n (0.7.0)
|
35
|
+
loofah (2.0.3)
|
36
|
+
nokogiri (>= 1.5.9)
|
37
|
+
method_source (0.8.2)
|
38
|
+
mime-types (2.99.1)
|
39
|
+
mini_portile2 (2.1.0)
|
40
|
+
minitest (5.9.0)
|
41
|
+
netrc (0.11.0)
|
42
|
+
nokogiri (1.6.8)
|
43
|
+
mini_portile2 (~> 2.1.0)
|
44
|
+
pkg-config (~> 1.1.7)
|
45
|
+
pkg-config (1.1.7)
|
46
|
+
rack (2.0.1)
|
47
|
+
rack-test (0.6.3)
|
48
|
+
rack (>= 1.0)
|
49
|
+
rails-dom-testing (2.0.1)
|
50
|
+
activesupport (>= 4.2.0, < 6.0)
|
51
|
+
nokogiri (~> 1.6.0)
|
52
|
+
rails-html-sanitizer (1.0.3)
|
53
|
+
loofah (~> 2.0)
|
54
|
+
railties (5.0.0)
|
55
|
+
actionpack (= 5.0.0)
|
56
|
+
activesupport (= 5.0.0)
|
57
|
+
method_source
|
58
|
+
rake (>= 0.8.7)
|
59
|
+
thor (>= 0.18.1, < 2.0)
|
60
|
+
rake (11.2.2)
|
61
|
+
rest-client (1.8.0)
|
62
|
+
http-cookie (>= 1.0.2, < 2.0)
|
63
|
+
mime-types (>= 1.16, < 3.0)
|
64
|
+
netrc (~> 0.7)
|
65
|
+
rspec-core (3.5.0)
|
66
|
+
rspec-support (~> 3.5.0)
|
67
|
+
rspec-expectations (3.5.0)
|
68
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
69
|
+
rspec-support (~> 3.5.0)
|
70
|
+
rspec-mocks (3.5.0)
|
71
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
72
|
+
rspec-support (~> 3.5.0)
|
73
|
+
rspec-rails (3.5.0)
|
74
|
+
actionpack (>= 3.0)
|
75
|
+
activesupport (>= 3.0)
|
76
|
+
railties (>= 3.0)
|
77
|
+
rspec-core (~> 3.5.0)
|
78
|
+
rspec-expectations (~> 3.5.0)
|
79
|
+
rspec-mocks (~> 3.5.0)
|
80
|
+
rspec-support (~> 3.5.0)
|
81
|
+
rspec-support (3.5.0)
|
82
|
+
thor (0.19.1)
|
83
|
+
thread_safe (0.3.5)
|
84
|
+
tzinfo (1.2.2)
|
85
|
+
thread_safe (~> 0.1)
|
86
|
+
unf (0.1.4)
|
87
|
+
unf_ext
|
88
|
+
unf_ext (0.0.7.2)
|
89
|
+
|
90
|
+
PLATFORMS
|
91
|
+
ruby
|
92
|
+
|
93
|
+
DEPENDENCIES
|
94
|
+
colored
|
95
|
+
commander
|
96
|
+
rest-client
|
97
|
+
rspec-rails
|
98
|
+
|
99
|
+
BUNDLED WITH
|
100
|
+
1.12.5
|
data/README.md
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
Description
|
2
|
+
------
|
3
|
+
shift-client is a command-line interface for shift. It interacts with the shift API and can be used to do all of the same actions that can be done from the ui
|
4
|
+
|
5
|
+
Installation
|
6
|
+
------
|
7
|
+
Run the shift-client executable directly
|
8
|
+
```
|
9
|
+
./shift/ui/shift-client/bin/shift-client --help
|
10
|
+
```
|
11
|
+
Or install it directly
|
12
|
+
```
|
13
|
+
$ gem install shift-client
|
14
|
+
$ shift-client --help
|
15
|
+
```
|
16
|
+
|
17
|
+
Usage
|
18
|
+
------
|
19
|
+
Running with --help shows you all of the available commands and global options
|
20
|
+
```
|
21
|
+
$ shift-client --help
|
22
|
+
NAME:
|
23
|
+
|
24
|
+
shift-client
|
25
|
+
|
26
|
+
DESCRIPTION:
|
27
|
+
|
28
|
+
Interact with the shift API from the command-line
|
29
|
+
|
30
|
+
COMMANDS:
|
31
|
+
|
32
|
+
approve migration Approve a migration
|
33
|
+
cancel migration Cancel a migration
|
34
|
+
create migration Create a migration
|
35
|
+
delete migration Delete a migration
|
36
|
+
dequeue migration Dequeue a migration
|
37
|
+
enqueue migration Enqueue a migration
|
38
|
+
get migration Get a migration
|
39
|
+
help Display global or [command] help documentation
|
40
|
+
pause migration Pause a migration
|
41
|
+
rename migration Rename a migration
|
42
|
+
resume migration Resume a migration
|
43
|
+
start migration Start a migration
|
44
|
+
unapprove migration Unapprove a migratio
|
45
|
+
|
46
|
+
GLOBAL OPTIONS:
|
47
|
+
|
48
|
+
--url URL
|
49
|
+
The API URL for shift (default: http://localhost:3000)
|
50
|
+
|
51
|
+
--ssl-cert SSL CERT
|
52
|
+
An SSL cert for authenticating against the shift api
|
53
|
+
|
54
|
+
--ssl-key SSL KEY
|
55
|
+
An SSL key for authenticating against the shift api
|
56
|
+
|
57
|
+
--ssl-ca SSL CA
|
58
|
+
An SSL CA cert for authenticating against the shift api
|
59
|
+
|
60
|
+
-h, --help
|
61
|
+
Display help documentation
|
62
|
+
|
63
|
+
-v, --version
|
64
|
+
Display version information
|
65
|
+
|
66
|
+
-t, --trace
|
67
|
+
Display backtrace when an error occurs
|
68
|
+
```
|
69
|
+
|
70
|
+
Running with --help on a specific command shows you the specific options for that command
|
71
|
+
```
|
72
|
+
$ shift-client approve migration --help
|
73
|
+
|
74
|
+
NAME:
|
75
|
+
|
76
|
+
approve migration
|
77
|
+
|
78
|
+
SYNOPSIS:
|
79
|
+
|
80
|
+
shift-client approve migration [options]
|
81
|
+
|
82
|
+
DESCRIPTION:
|
83
|
+
|
84
|
+
Approve a migration
|
85
|
+
|
86
|
+
OPTIONS:
|
87
|
+
|
88
|
+
--id ID
|
89
|
+
The id of the migration
|
90
|
+
|
91
|
+
--lock-version LOCK VERSION
|
92
|
+
The most recent lock version of the migration
|
93
|
+
|
94
|
+
--runtype RUNTYPE
|
95
|
+
The type of run to approve (options are: short, long, nocheckalter)
|
96
|
+
|
97
|
+
--approver APPROVER
|
98
|
+
The username of the approver
|
99
|
+
|
100
|
+
```
|
101
|
+
|
102
|
+
## Global Options
|
103
|
+
Without specifying any global options, shift-cli will try to talk to the shift API at localhost:3000 without SSL. If that's where the shift ui is running, you don't need to pass any global options. If it's running at a different URL, or requires valid SSL certs to access it, you can supply any of the following: `--url`, `--ssl-cert`, `--ssl-key`, and `--ssl-ca`
|
104
|
+
|
105
|
+
## Responses
|
106
|
+
The standard response for most successful commands is a JSON object that looks like the following
|
107
|
+
```
|
108
|
+
$ shift-client get migration --id 25
|
109
|
+
{
|
110
|
+
"migration": {
|
111
|
+
"id": 25,
|
112
|
+
"created_at": "2016-06-07T01:20:10.000Z",
|
113
|
+
"updated_at": "2016-06-07T01:21:19.000Z",
|
114
|
+
"completed_at": null,
|
115
|
+
"requestor": "developer",
|
116
|
+
"cluster_name": "default-cluster-001",
|
117
|
+
"database": "shift_development",
|
118
|
+
"ddl_statement": "alter table migrations add column mfinch int",
|
119
|
+
"final_insert": "",
|
120
|
+
"pr_url": "github.com/pr",
|
121
|
+
"table_rows_start": 25,
|
122
|
+
"table_rows_end": null,
|
123
|
+
"table_size_start": 16384,
|
124
|
+
"table_size_end": null,
|
125
|
+
"index_size_start": 16384,
|
126
|
+
"index_size_end": null,
|
127
|
+
"approved_by": "mfinch",
|
128
|
+
"approved_at": "2016-07-02T00:40:29.000Z",
|
129
|
+
"work_directory": null,
|
130
|
+
"started_at": "2016-07-02T01:08:34.000Z",
|
131
|
+
"copy_percentage": null,
|
132
|
+
"staged": true,
|
133
|
+
"status": 3,
|
134
|
+
"error_message": null,
|
135
|
+
"run_host": null,
|
136
|
+
"lock_version": 7,
|
137
|
+
"editable": false,
|
138
|
+
"runtype": 1,
|
139
|
+
"meta_request_id": null,
|
140
|
+
"initial_runtype": 1,
|
141
|
+
"auto_run": true
|
142
|
+
},
|
143
|
+
"available_actions": [
|
144
|
+
"pause",
|
145
|
+
"cancel"
|
146
|
+
]
|
147
|
+
}
|
148
|
+
```
|
149
|
+
As you can see, it contains a dump of the migration, as well as the actions that are available to run on it.
|
150
|
+
|
151
|
+
The only other type of response you will get from a successful command is an empty JSON object when you delete a migration
|
152
|
+
```
|
153
|
+
$ shift-client delete migration --id 24 --lock-version 7
|
154
|
+
{
|
155
|
+
}
|
156
|
+
```
|
157
|
+
|
158
|
+
Commands that run into errors will return JSON objects that look like the following
|
159
|
+
```
|
160
|
+
$ shift-client start migration --id 25 --lock-version 8
|
161
|
+
{
|
162
|
+
"status": 400,
|
163
|
+
"errors": [
|
164
|
+
"Invalid action.",
|
165
|
+
"Incorrect lock_version supplied."
|
166
|
+
]
|
167
|
+
}
|
168
|
+
```
|
169
|
+
|
170
|
+
## Option descriptions
|
171
|
+
* `--id`: the id of the migration you want to act on. Can get this from the response of a successful `shift-client create migration` command
|
172
|
+
* `--lock-version`: the most recent lock-version of a migration. This is used so that we know a migration's status hasn't changed without you knowing. Can get this from the response of any successful command
|
173
|
+
* `--runtype`: the type of run to approve a migration with (options are: short, long, nocheckalter). When you run `shift-client get migration` on a migration that is in the "awaiting_approval" step, the available actions in the JSON response will look something like `["approve_short", "approve_long"]`. That means that when you run `shift-client approve migration`, you must supply either `--runtype short` or `--runtype long`. A short run is one that runs an alter directly on a table. A long run is one that uses pt-osc. A nocheckalter run is one that uses pt-osc with the --nocheck-alter flag.
|
174
|
+
* `--auto-run`: this option can be passed to `shift-client start migration` and `shift-client resume migration`. When it is used, the migration will automatically rename tables after it is done copying all of its rows (instead of waiting for human interaction). `shift-client enqueue migration` automatically sets this to true
|
175
|
+
* All of the other options should be pretty self explanatory
|
176
|
+
|
177
|
+
Development
|
178
|
+
------
|
179
|
+
Run the tests
|
180
|
+
```
|
181
|
+
bundle exec rake spec
|
182
|
+
```
|
183
|
+
|
184
|
+
## License
|
185
|
+
|
186
|
+
Copyright (c) 2016 Square Inc. Distributed under the Apache 2.0 License.
|
187
|
+
See LICENSE file for further details.
|
data/Rakefile
ADDED
data/bin/shift-client
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
|
5
|
+
require "commander/import"
|
6
|
+
require "colored"
|
7
|
+
|
8
|
+
require "shift_client"
|
9
|
+
require "shift_client/version"
|
10
|
+
|
11
|
+
program :name, 'shift-client'
|
12
|
+
program :version, ShiftClient::VERSION
|
13
|
+
program :description, 'Interact with the shift API from the command-line'
|
14
|
+
|
15
|
+
class ShiftClientCLI
|
16
|
+
include Commander::Methods
|
17
|
+
DEFAULT_SHIFT_URL = "http://localhost:3000"
|
18
|
+
|
19
|
+
global_option "--url URL", String, "The API URL for shift (default: #{DEFAULT_SHIFT_URL})"
|
20
|
+
global_option "--ssl-cert SSL CERT", String, "An SSL cert for authenticating against the shift api"
|
21
|
+
global_option "--ssl-key SSL KEY", String, "An SSL key for authenticating against the shift api"
|
22
|
+
global_option "--ssl-ca SSL CA", String, "An SSL CA cert for authenticating against the shift api"
|
23
|
+
|
24
|
+
def run
|
25
|
+
command :'get migration' do |get_migration|
|
26
|
+
get_migration.syntax = "shift-client get migration [options]"
|
27
|
+
get_migration.description = "Get a migration"
|
28
|
+
get_migration.option "--id ID", String, "The id of the migration"
|
29
|
+
|
30
|
+
get_migration.action do |args, options|
|
31
|
+
raise "Must provide --id" unless options.id
|
32
|
+
|
33
|
+
client = shift_client_with_auth(options)
|
34
|
+
display client.get_migration(options.id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
command :'create migration' do |create_migration|
|
39
|
+
create_migration.syntax = "shift-client create migration [options]"
|
40
|
+
create_migration.description = "Create a migration"
|
41
|
+
create_migration.option "--cluster CLUSTER", String, "The cluster to run a migration on"
|
42
|
+
create_migration.option "--database DATABASE", String, "The database to run a migration on"
|
43
|
+
create_migration.option "--ddl-statement DDL STATEMENT", String, "The ddl statement to run"
|
44
|
+
create_migration.option "--pr-url PR URL", String, "The pull request URL associated with the migration"
|
45
|
+
create_migration.option "--requestor REQUESTOR", String, "Username of the person creating the migration"
|
46
|
+
create_migration.option "--final-insert FINAL INSERT", String, "A final insert statement"
|
47
|
+
|
48
|
+
create_migration.action do |args, options|
|
49
|
+
raise "Must provide --cluster" unless options.cluster
|
50
|
+
raise "Must provide --database" unless options.database
|
51
|
+
raise "Must provide --ddl-statement" unless options.ddl_statement
|
52
|
+
raise "Must provide --pr-url" unless options.pr_url
|
53
|
+
raise "Must provide --requestor" unless options.requestor
|
54
|
+
|
55
|
+
client = shift_client_with_auth(options)
|
56
|
+
display client.create_migration(options.cluster, options.database, options.ddl_statement, options.pr_url, options.requestor, final_insert: options.final_insert)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# generic actions
|
61
|
+
%w(approve unapprove start enqueue dequeue pause rename resume cancel).each do |action|
|
62
|
+
command :"#{action} migration" do |c|
|
63
|
+
c.syntax = "shift-client #{action} migration [options]"
|
64
|
+
c.description = "#{action.capitalize} a migration"
|
65
|
+
|
66
|
+
c.option "--id ID", String, "The id of the migration"
|
67
|
+
if %w(approve unapprove start enqueue dequeue rename resume).include?(action)
|
68
|
+
c.option "--lock-version LOCK VERSION", String, "The most recent lock version of the migration"
|
69
|
+
end
|
70
|
+
if %w(approve).include?(action)
|
71
|
+
c.option "--runtype RUNTYPE", String, "The type of run to approve (options are: short, long, nocheckalter)"
|
72
|
+
c.option "--approver APPROVER", String, "The username of the approver"
|
73
|
+
end
|
74
|
+
if %w(start resume).include?(action)
|
75
|
+
c.option "--auto-run", String, "If passed, this migration will automatically rename tables after completing the copy step"
|
76
|
+
end
|
77
|
+
|
78
|
+
c.action do |args, options|
|
79
|
+
raise "Must provide --id" unless options.id
|
80
|
+
if %w(approve unapprove start enqueue dequeue rename resume).include?(action)
|
81
|
+
raise "Must provide --lock-version" unless options.lock_version
|
82
|
+
end
|
83
|
+
if %w(approve).include?(action)
|
84
|
+
raise "Must provide --runtype" unless options.runtype
|
85
|
+
raise "Must provide --approver" unless options.approver
|
86
|
+
end
|
87
|
+
|
88
|
+
client = shift_client_with_auth(options)
|
89
|
+
# use the correct cancel endpoint
|
90
|
+
action = "cancel_cli" if action == "cancel"
|
91
|
+
display client.generic_migration_action_post(action, options)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
command :'delete migration' do |delete_migration|
|
97
|
+
delete_migration.syntax = "shift-client delete migration [options]"
|
98
|
+
delete_migration.description = "Delete a migration"
|
99
|
+
|
100
|
+
delete_migration.option "--id ID", String, "The id of the migration"
|
101
|
+
delete_migration.option "--lock-version LOCK VERSION", String, "The most recent lock version of the migration"
|
102
|
+
|
103
|
+
delete_migration.action do |args, options|
|
104
|
+
raise "Must provide --id" unless options.id
|
105
|
+
raise "Must provide --lock-version" unless options.lock_version
|
106
|
+
|
107
|
+
client = shift_client_with_auth(options)
|
108
|
+
display client.delete_migration(options.id, options.lock_version)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
run!
|
113
|
+
end
|
114
|
+
|
115
|
+
def shift_client_with_auth(options)
|
116
|
+
url = options.api || DEFAULT_SHIFT_URL
|
117
|
+
insecure = (options.ssl_cert && options.ssl_key && options.ssl_ca).nil?
|
118
|
+
|
119
|
+
ShiftClient.new(
|
120
|
+
url: url,
|
121
|
+
insecure: insecure,
|
122
|
+
ssl_cert: options.ssl_cert,
|
123
|
+
ssl_key: options.ssl_key,
|
124
|
+
ssl_ca: options.ssl_ca,
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def display(output)
|
129
|
+
puts JSON.pretty_generate output
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
ShiftClientCLI.new.run
|
data/lib/shift_client.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class ShiftClient
|
5
|
+
attr_reader :insecure, :url
|
6
|
+
def initialize(url: raise, ssl_cert: nil, ssl_key: nil, ssl_ca: nil, insecure: true)
|
7
|
+
@ssl_cert = ssl_cert
|
8
|
+
@ssl_key = ssl_key
|
9
|
+
@ssl_ca = ssl_ca
|
10
|
+
@insecure = insecure
|
11
|
+
|
12
|
+
@url = url
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_migration(migration_id)
|
16
|
+
shift_get("/api/v1/migrations/#{migration_id}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_migration(cluster, database, ddl_statement, pr_url, requestor, final_insert: nil)
|
20
|
+
params = {
|
21
|
+
:cluster_name => cluster,
|
22
|
+
:database => database,
|
23
|
+
:ddl_statement => ddl_statement,
|
24
|
+
:pr_url => pr_url,
|
25
|
+
:requestor => requestor,
|
26
|
+
:final_insert => final_insert || "",
|
27
|
+
}
|
28
|
+
|
29
|
+
shift_post("/api/v1/migrations", params)
|
30
|
+
end
|
31
|
+
|
32
|
+
def generic_migration_action_post(action, options)
|
33
|
+
params = {}
|
34
|
+
params[:id] = options.id
|
35
|
+
params[:lock_version] = options.lock_version if options.lock_version
|
36
|
+
params[:runtype] = options.runtype if options.runtype
|
37
|
+
params[:approver] = options.approver if options.approver
|
38
|
+
params[:auto_run] = options.auto_run if options.auto_run
|
39
|
+
|
40
|
+
shift_post("/api/v1/migrations/#{action}", params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete_migration(migration_id, lock_version)
|
44
|
+
params = {
|
45
|
+
:lock_version => lock_version,
|
46
|
+
}
|
47
|
+
shift_delete("/api/v1/migrations/#{migration_id}", params)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def shift_get(route, params = nil)
|
53
|
+
headers = get_headers
|
54
|
+
headers.merge!(params: params) if params
|
55
|
+
begin
|
56
|
+
response = resource_for_route(route).get(
|
57
|
+
headers
|
58
|
+
)
|
59
|
+
rescue RestClient::BadRequest, RestClient::ResourceNotFound => e
|
60
|
+
response = e.http_body
|
61
|
+
end
|
62
|
+
|
63
|
+
parse_response(response)
|
64
|
+
end
|
65
|
+
|
66
|
+
def shift_post(route, params = nil)
|
67
|
+
begin
|
68
|
+
response = resource_for_route(route).post(
|
69
|
+
params.to_json,
|
70
|
+
post_headers,
|
71
|
+
)
|
72
|
+
rescue RestClient::BadRequest, RestClient::ResourceNotFound => e
|
73
|
+
response = e.http_body
|
74
|
+
end
|
75
|
+
|
76
|
+
parse_response(response)
|
77
|
+
end
|
78
|
+
|
79
|
+
def shift_delete(route, params = nil)
|
80
|
+
# have to do some different stuff here because RestClient::Resource
|
81
|
+
# doesn't support extra params for deleting
|
82
|
+
headers = delete_headers
|
83
|
+
headers.merge!(params: params) if params
|
84
|
+
opts = {
|
85
|
+
method: :delete,
|
86
|
+
url: @url + route,
|
87
|
+
headers: headers,
|
88
|
+
}
|
89
|
+
opts.merge!(ssl_options) unless @insecure
|
90
|
+
begin
|
91
|
+
response = RestClient::Request.execute(opts)
|
92
|
+
rescue RestClient::BadRequest, RestClient::ResourceNotFound => e
|
93
|
+
response = e.http_body
|
94
|
+
end
|
95
|
+
|
96
|
+
parse_response(response)
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_headers
|
100
|
+
{:accept => 'application/json'}
|
101
|
+
end
|
102
|
+
|
103
|
+
def post_headers
|
104
|
+
get_headers.merge!(:content_type => 'application/json')
|
105
|
+
end
|
106
|
+
|
107
|
+
def delete_headers
|
108
|
+
get_headers
|
109
|
+
end
|
110
|
+
|
111
|
+
def resource_for_route(route)
|
112
|
+
opts = {}
|
113
|
+
opts.merge!(ssl_options) unless @insecure
|
114
|
+
RestClient::Resource.new(
|
115
|
+
@url + route,
|
116
|
+
opts
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def ssl_options
|
121
|
+
{
|
122
|
+
:ssl_client_cert => OpenSSL::X509::Certificate.new(File.read(@ssl_cert)),
|
123
|
+
:ssl_client_key => OpenSSL::PKey::RSA.new(File.read(@ssl_key)),
|
124
|
+
:ssl_ca_file => @ssl_ca,
|
125
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse_response(response)
|
130
|
+
JSON.parse(response)
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'shift_client/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'shift-client'
|
9
|
+
spec.version = ShiftClient::VERSION
|
10
|
+
spec.authors = ['Michael Finch']
|
11
|
+
spec.email = ['mfinch@squareup.com']
|
12
|
+
spec.summary = 'Client gem for interacting with the shift API'
|
13
|
+
spec.homepage = 'https://github.com/square/shift/tree/master/ui/shift-client'
|
14
|
+
spec.required_ruby_version = '>= 2.0.0'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'json'
|
22
|
+
spec.add_runtime_dependency 'rest-client', '>= 1.8.0'
|
23
|
+
spec.add_runtime_dependency 'colored'
|
24
|
+
spec.add_runtime_dependency 'commander', '~> 4.2'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'shift_client'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe ShiftClient do
|
5
|
+
let(:shift_client) { ShiftClient.new(url: "http://localhost:3000", insecure: true) }
|
6
|
+
let(:get_headers) { {:accept => "application/json"} }
|
7
|
+
let(:post_headers) { get_headers.merge({:content_type => "application/json"}) }
|
8
|
+
let(:delete_headers) { get_headers }
|
9
|
+
let(:migration_id) { 3 }
|
10
|
+
let(:cluster) { "cluster-001" }
|
11
|
+
let(:database) { "db_01" }
|
12
|
+
let(:ddl_statement) { "alter table slug" }
|
13
|
+
let(:pr_url) { "github.com/pr" }
|
14
|
+
let(:requestor) { "michael" }
|
15
|
+
let(:final_insert) { "" }
|
16
|
+
let(:lock_version) { 7 }
|
17
|
+
let(:runtype) { "long" }
|
18
|
+
let(:approver) { "frank" }
|
19
|
+
|
20
|
+
it "#get_migration" do
|
21
|
+
path = shift_client.url + "/api/v1/migrations/#{migration_id}"
|
22
|
+
resource_double = instance_double(RestClient::Resource)
|
23
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
24
|
+
expect(resource_double).to receive(:get).with(get_headers).and_return("{}")
|
25
|
+
expect(shift_client.get_migration(migration_id)).to eq({})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "#create_migration" do
|
29
|
+
path = shift_client.url + "/api/v1/migrations"
|
30
|
+
params = {
|
31
|
+
:cluster_name => cluster,
|
32
|
+
:database => database,
|
33
|
+
:ddl_statement => ddl_statement,
|
34
|
+
:pr_url => pr_url,
|
35
|
+
:requestor => requestor,
|
36
|
+
:final_insert => final_insert,
|
37
|
+
}
|
38
|
+
resource_double = instance_double(RestClient::Resource)
|
39
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
40
|
+
expect(resource_double).to receive(:post).with(params.to_json, post_headers).and_return("{}")
|
41
|
+
expect(shift_client.create_migration(
|
42
|
+
cluster, database, ddl_statement, pr_url, requestor)).to eq({})
|
43
|
+
end
|
44
|
+
|
45
|
+
it "#generic_migration_action_post" do
|
46
|
+
action = "approve"
|
47
|
+
options = OpenStruct.new \
|
48
|
+
:id => migration_id,
|
49
|
+
:lock_version => lock_version,
|
50
|
+
:runtype => runtype,
|
51
|
+
:approver => approver
|
52
|
+
path = shift_client.url + "/api/v1/migrations/" + action
|
53
|
+
resource_double = instance_double(RestClient::Resource)
|
54
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
55
|
+
expect(resource_double).to receive(:post).with(options.to_h.to_json, post_headers).and_return("{}")
|
56
|
+
expect(shift_client.generic_migration_action_post(action, options)).to eq({})
|
57
|
+
end
|
58
|
+
|
59
|
+
it "#delete_migration" do
|
60
|
+
path = shift_client.url + "/api/v1/migrations/#{migration_id}"
|
61
|
+
params = {:lock_version => lock_version}
|
62
|
+
opts = {
|
63
|
+
method: :delete,
|
64
|
+
url: path,
|
65
|
+
headers: delete_headers.merge!({params: params}),
|
66
|
+
}
|
67
|
+
expect(RestClient::Request).to receive(:execute).with(opts).and_return("{}")
|
68
|
+
expect(shift_client.delete_migration(migration_id, lock_version)).to eq({})
|
69
|
+
end
|
70
|
+
end
|
data/spec/unit_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shift-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Finch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
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: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: colored
|
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: commander
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
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: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- mfinch@squareup.com
|
100
|
+
executables:
|
101
|
+
- shift-client
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- Gemfile
|
106
|
+
- Gemfile.lock
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- bin/shift-client
|
110
|
+
- lib/shift_client.rb
|
111
|
+
- lib/shift_client/version.rb
|
112
|
+
- shift-client.gemspec
|
113
|
+
- spec/client_spec.rb
|
114
|
+
- spec/unit_helper.rb
|
115
|
+
homepage: https://github.com/square/shift/tree/master/ui/shift-client
|
116
|
+
licenses: []
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 2.0.0
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.5.1
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Client gem for interacting with the shift API
|
138
|
+
test_files:
|
139
|
+
- spec/client_spec.rb
|
140
|
+
- spec/unit_helper.rb
|