turbot 0.1.36 → 0.2.3

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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +15 -0
  5. data/.yardopts +3 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +22 -0
  8. data/README.md +44 -25
  9. data/Rakefile +16 -0
  10. data/appveyor.yml +35 -0
  11. data/bin/turbot +2 -16
  12. data/data/schema.json +134 -0
  13. data/{templates → data/templates}/LICENSE.txt +0 -0
  14. data/{templates → data/templates}/manifest.json +0 -0
  15. data/{templates → data/templates}/python/scraper.py +0 -0
  16. data/{templates → data/templates}/ruby/scraper.rb +0 -0
  17. data/dist/deb.rake +32 -0
  18. data/dist/gem.rake +16 -0
  19. data/dist/manifest.rake +9 -0
  20. data/dist/pkg.rake +60 -0
  21. data/dist/resources/deb/control +10 -0
  22. data/dist/resources/deb/postinst +45 -0
  23. data/dist/resources/deb/turbot +25 -0
  24. data/dist/resources/deb/turbot-release-key.txt +30 -0
  25. data/dist/resources/pkg/Distribution.erb +15 -0
  26. data/dist/resources/pkg/PackageInfo.erb +6 -0
  27. data/dist/resources/pkg/postinstall +45 -0
  28. data/dist/resources/pkg/turbot +24 -0
  29. data/dist/resources/tgz/turbot +24 -0
  30. data/dist/rpm.rake +35 -0
  31. data/dist/tgz.rake +26 -0
  32. data/dist/zip.rake +40 -0
  33. data/lib/turbot.rb +18 -15
  34. data/lib/turbot/cli.rb +10 -27
  35. data/lib/turbot/command.rb +59 -212
  36. data/lib/turbot/command/auth.rb +72 -34
  37. data/lib/turbot/command/base.rb +22 -61
  38. data/lib/turbot/command/bots.rb +251 -300
  39. data/lib/turbot/command/help.rb +57 -110
  40. data/lib/turbot/command/version.rb +6 -10
  41. data/lib/turbot/handlers/base_handler.rb +21 -0
  42. data/lib/turbot/handlers/dump_handler.rb +10 -0
  43. data/lib/turbot/handlers/preview_handler.rb +30 -0
  44. data/lib/turbot/handlers/validation_handler.rb +17 -0
  45. data/lib/turbot/helpers.rb +14 -482
  46. data/lib/turbot/helpers/api_helper.rb +41 -0
  47. data/lib/turbot/helpers/netrc_helper.rb +66 -0
  48. data/lib/turbot/helpers/shell_helper.rb +36 -0
  49. data/lib/turbot/version.rb +1 -1
  50. data/spec/fixtures/bad_permissions +0 -0
  51. data/spec/fixtures/empty +0 -0
  52. data/spec/fixtures/netrc +6 -0
  53. data/spec/spec_helper.rb +17 -219
  54. data/spec/support/bot_helper.rb +102 -0
  55. data/spec/support/command_helper.rb +20 -0
  56. data/spec/support/custom_matchers.rb +5 -0
  57. data/spec/support/fixture_helper.rb +9 -0
  58. data/spec/support/netrc_helper.rb +21 -0
  59. data/spec/turbot/command/auth_spec.rb +202 -20
  60. data/spec/turbot/command/base_spec.rb +22 -58
  61. data/spec/turbot/command/bots_spec.rb +580 -89
  62. data/spec/turbot/command/help_spec.rb +32 -75
  63. data/spec/turbot/command/version_spec.rb +11 -10
  64. data/spec/turbot/command_spec.rb +55 -87
  65. data/spec/turbot/helpers_spec.rb +28 -44
  66. data/turbot.gemspec +31 -0
  67. metadata +88 -178
  68. data/data/cacert.pem +0 -3988
  69. data/lib/turbot/auth.rb +0 -315
  70. data/lib/turbot/client.rb +0 -757
  71. data/lib/turbot/client/cisaurus.rb +0 -25
  72. data/lib/turbot/client/pgbackups.rb +0 -113
  73. data/lib/turbot/client/rendezvous.rb +0 -111
  74. data/lib/turbot/client/ssl_endpoint.rb +0 -25
  75. data/lib/turbot/client/turbot_postgresql.rb +0 -148
  76. data/lib/turbot/command/ssl.rb +0 -43
  77. data/lib/turbot/deprecated.rb +0 -5
  78. data/lib/turbot/deprecated/help.rb +0 -38
  79. data/lib/turbot/distribution.rb +0 -9
  80. data/lib/turbot/errors.rb +0 -28
  81. data/lib/turbot/excon.rb +0 -11
  82. data/lib/turbot/helpers/log_displayer.rb +0 -70
  83. data/lib/turbot/helpers/pg_dump_restore.rb +0 -115
  84. data/lib/turbot/helpers/turbot_postgresql.rb +0 -213
  85. data/lib/turbot/plugin.rb +0 -165
  86. data/lib/turbot/updater.rb +0 -171
  87. data/lib/vendor/turbot/okjson.rb +0 -598
  88. data/spec/helper/legacy_help.rb +0 -16
  89. data/spec/helper/pg_dump_restore_spec.rb +0 -67
  90. data/spec/spec.opts +0 -1
  91. data/spec/support/display_message_matcher.rb +0 -49
  92. data/spec/support/dummy_api.rb +0 -120
  93. data/spec/support/openssl_mock_helper.rb +0 -8
  94. data/spec/support/organizations_mock_helper.rb +0 -11
  95. data/spec/turbot/auth_spec.rb +0 -214
  96. data/spec/turbot/client/pgbackups_spec.rb +0 -43
  97. data/spec/turbot/client/rendezvous_spec.rb +0 -62
  98. data/spec/turbot/client/ssl_endpoint_spec.rb +0 -48
  99. data/spec/turbot/client/turbot_postgresql_spec.rb +0 -71
  100. data/spec/turbot/client_spec.rb +0 -548
  101. data/spec/turbot/helpers/turbot_postgresql_spec.rb +0 -181
  102. data/spec/turbot/plugin_spec.rb +0 -172
  103. data/spec/turbot/updater_spec.rb +0 -44
@@ -1,5 +0,0 @@
1
- require "turbot"
2
-
3
- module Turbot::Deprecated
4
- end
5
-
@@ -1,38 +0,0 @@
1
- require "turbot/deprecated"
2
-
3
- module Turbot::Deprecated::Help
4
- def self.included(base)
5
- base.extend ClassMethods
6
- end
7
-
8
- class HelpGroup < Array
9
- attr_reader :title
10
-
11
- def initialize(title)
12
- @title = title
13
- end
14
-
15
- def command(name, description)
16
- self << [name, description]
17
- end
18
-
19
- def space
20
- self << ['', '']
21
- end
22
- end
23
-
24
- module ClassMethods
25
- def groups
26
- @groups ||= []
27
- end
28
-
29
- def group(title, &block)
30
- groups << begin
31
- group = HelpGroup.new(title)
32
- yield group
33
- group
34
- end
35
- end
36
- end
37
- end
38
-
@@ -1,9 +0,0 @@
1
- module Turbot
2
- module Distribution
3
- def self.files
4
- (Dir[File.expand_path("../../../{Gemfile,turbot.gemspec,.gitmodules,schema}", __FILE__)] + Dir[File.expand_path("../../../{.git,bin,data,lib,templates}/**/*", __FILE__)]).select do |file|
5
- File.file?(file)
6
- end
7
- end
8
- end
9
- end
data/lib/turbot/errors.rb DELETED
@@ -1,28 +0,0 @@
1
- module Turbot
2
- class API
3
- module Errors
4
- class Error < StandardError; end
5
-
6
- class ErrorWithResponse < Error
7
- attr_reader :response
8
-
9
- def initialize(message, response=nil)
10
- message = message << "\nbody: #{response.body.inspect}" if response
11
- super message
12
- @response = response
13
- end
14
- end
15
-
16
- class Unauthorized < ErrorWithResponse; end
17
- class VerificationRequired < ErrorWithResponse; end
18
- class Forbidden < ErrorWithResponse; end
19
- class NotFound < ErrorWithResponse; end
20
- class Timeout < ErrorWithResponse; end
21
- class Locked < ErrorWithResponse; end
22
- class RateLimitExceeded < ErrorWithResponse; end
23
- class RequestFailed < ErrorWithResponse; end
24
- class NilApp < ErrorWithResponse; end
25
- class MissingManifest < ErrorWithResponse; end
26
- end
27
- end
28
- end
data/lib/turbot/excon.rb DELETED
@@ -1,11 +0,0 @@
1
- module Excon
2
-
3
- def self.get_with_redirect(url, options={})
4
- res = Excon.get(url, options)
5
- if [301, 302].include?(res.status)
6
- return self.get_with_redirect(res.headers["Location"], options)
7
- end
8
- res
9
- end
10
-
11
- end
@@ -1,70 +0,0 @@
1
- require "turbot/helpers"
2
-
3
- module Turbot::Helpers
4
- class LogDisplayer
5
-
6
- include Turbot::Helpers
7
-
8
- attr_reader :api, :bot, :opts
9
-
10
- def initialize(api, bot, opts)
11
- @api, @bot, @opts = api, bot, opts
12
- end
13
-
14
- def display_logs
15
- @assigned_colors = {}
16
- @line_start = true
17
- @token = nil
18
-
19
- api.read_logs(bot, opts).each do |chunk|
20
- unless chunk.empty?
21
- if STDOUT.isatty && ENV.has_key?("TERM")
22
- display(colorize(chunk))
23
- else
24
- display(chunk)
25
- end
26
- end
27
- end
28
- rescue Errno::EPIPE
29
- rescue Interrupt => interrupt
30
- if STDOUT.isatty && ENV.has_key?("TERM")
31
- display("\e[0m")
32
- end
33
- raise(interrupt)
34
- end
35
-
36
- COLORS = %w( cyan yellow green magenta red )
37
- COLOR_CODES = {
38
- "red" => 31,
39
- "green" => 32,
40
- "yellow" => 33,
41
- "magenta" => 35,
42
- "cyan" => 36,
43
- }
44
-
45
- def colorize(chunk)
46
- lines = []
47
- chunk.split("\n").map do |line|
48
- if parsed_line = parse_log(line)
49
- header, identifier, body = parsed_line
50
- @assigned_colors[identifier] ||= COLORS[@assigned_colors.size % COLORS.size]
51
- lines << [
52
- "\e[#{COLOR_CODES[@assigned_colors[identifier]]}m",
53
- header,
54
- "\e[0m",
55
- body,
56
- ].join("")
57
- elsif not line.empty?
58
- lines << line
59
- end
60
- end
61
- lines.join("\n")
62
- end
63
-
64
- def parse_log(log)
65
- return unless parsed = log.match(/^(.*?\[([\w-]+)([\d\.]+)?\]:)(.*)?$/)
66
- [1, 2, 4].map { |i| parsed[i] }
67
- end
68
-
69
- end
70
- end
@@ -1,115 +0,0 @@
1
- require 'uri'
2
- class PgDumpRestore
3
- attr_reader :command
4
-
5
- def initialize(source, target, command)
6
- @source = URI.parse(source)
7
- @target = URI.parse(target)
8
- @command = command
9
-
10
- fill_in_shorthand_uris!
11
- end
12
-
13
- def execute
14
- prepare
15
- run
16
- verify
17
- end
18
-
19
- def prepare
20
- if @target.host == 'localhost'
21
- create_local_db
22
- else
23
- ensure_remote_db_empty
24
- end
25
- end
26
-
27
- def verify
28
- verify_extensions_match
29
- end
30
-
31
- def dump_restore_cmd
32
- pg_restore = gen_pg_restore_command(@target)
33
- pg_dump = gen_pg_dump_command(@source)
34
- "#{pg_dump} | #{pg_restore}"
35
- end
36
-
37
- private
38
-
39
- def create_local_db
40
- dbname = @target.path[1..-1]
41
- cdb_output = `createdb #{dbname} 2>&1`
42
- if $?.exitstatus != 0
43
- if cdb_output =~ /already exists/
44
- command.error(cdb_output + "\nPlease drop the local database (`dropdb #{dbname}`) and try again.")
45
- else
46
- command.error(cdb_output + "\nUnable to create new local database. Ensure your local Postgres is working and try again.")
47
- end
48
- end
49
- end
50
-
51
- def ensure_remote_db_empty
52
- sql = 'select count(*) = 0 from pg_stat_user_tables;'
53
- result = exec_sql_on_uri(sql, @target)
54
- unless result == " ?column? \n----------\n t\n(1 row)\n\n"
55
- command.error("Remote database is not empty.\nPlease create a new database, or use `turbot pg:reset`")
56
- end
57
- end
58
-
59
- def gen_pg_dump_command(uri)
60
- # It is occasionally necessary to override PGSSLMODE, as when the server
61
- # wasn't built to support SSL.
62
- %{ env PGPASSWORD=#{uri.password} PGSSLMODE=prefer pg_dump --verbose -F c -Z 0 #{connstring(uri, :skip_d_flag)} }
63
- end
64
-
65
- def gen_pg_restore_command(uri)
66
- %{ env PGPASSWORD=#{uri.password} pg_restore --verbose --no-acl --no-owner #{connstring(uri)} }
67
- end
68
-
69
- def connstring(uri, skip_d_flag=false)
70
- database = uri.path[1..-1]
71
- user = uri.user ? "-U #{uri.user}" : ""
72
- %Q{#{user} -h #{uri.host} -p #{uri.port} #{skip_d_flag ? '' : '-d'} #{database} }
73
- end
74
-
75
- def fill_in_shorthand_uris!
76
- [@target, @source].each do |uri|
77
- uri.host ||= 'localhost'
78
- uri.port ||= Integer(ENV['PGPORT'] || 5432)
79
- end
80
- end
81
-
82
- def verify_extensions_match
83
- # It's pretty common for local DBs to not have extensions available that
84
- # are used by the remote bot, so take the final precaution of warning if
85
- # the extensions available in the local database don't match. We don't
86
- # report it if the difference is solely in the version of an extension
87
- # used, though.
88
- ext_sql = "SELECT extname FROM pg_extension ORDER BY extname;"
89
- target_exts = exec_sql_on_uri(ext_sql, @target)
90
- source_exts = exec_sql_on_uri(ext_sql, @source)
91
- if target_exts != source_exts
92
- command.error <<-EOM
93
- WARNING: Extensions in newly created target database differ from existing source database.
94
-
95
- Target extensions:
96
- #{target_exts}
97
- Source extensions:
98
- #{source_exts}
99
- HINT: You should review output to ensure that any errors
100
- ignored are acceptable - entire tables may have been missed, where a dependency
101
- could not be resolved. You may need to to install a postgresql-contrib package
102
- and retry.
103
- EOM
104
- end
105
- end
106
-
107
- def exec_sql_on_uri(sql, uri)
108
- command.send(:exec_sql_on_uri, sql, uri)
109
- end
110
-
111
- def run
112
- system dump_restore_cmd
113
- end
114
- end
115
-
@@ -1,213 +0,0 @@
1
- require "turbot/helpers"
2
-
3
- module Turbot::Helpers::TurbotPostgresql
4
-
5
- extend self
6
- extend Turbot::Helpers
7
-
8
- class Attachment
9
- attr_reader :bot, :name, :config_var, :resource_name, :url, :addon, :plan
10
- def initialize(raw)
11
- @raw = raw
12
- @bot = raw['bot']['name']
13
- @name = raw['name']
14
- @config_var = raw['config_var']
15
- @resource_name = raw['resource']['name']
16
- @url = raw['resource']['value']
17
- @addon, @plan = raw['resource']['type'].split(':')
18
- end
19
-
20
- def starter_plan?
21
- plan =~ /dev|basic/
22
- end
23
-
24
- def display_name
25
- config_var + (primary_attachment? ? " (DATABASE_URL)" : '')
26
- end
27
-
28
- def primary_attachment!
29
- @primary_attachment = true
30
- end
31
-
32
- def primary_attachment?
33
- @primary_attachment
34
- end
35
- end
36
-
37
- def hpg_resolve(identifier, default=nil)
38
- $stderr.puts " ! #hpg_resolve is deprecated. Please run `turbot plugins:update` to update your plugins."
39
- $stderr.puts " ! from: #{caller.first}"
40
- Resolver.new(bot, api).resolve(identifier , default)
41
- end
42
-
43
- class Resolver
44
- include Turbot::Helpers
45
- attr_reader :api, :bot_name
46
- def initialize(bot_name, api)
47
- @bot_name = bot_name
48
- @api = api
49
- end
50
-
51
- def resolve(identifier, default=nil)
52
- if identifier =~ /::/
53
- @bot_name, db_name = identifier.split('::')
54
- else
55
- db_name = identifier
56
- end
57
-
58
- hpg_resolve(db_name, default)
59
- end
60
-
61
- def all_databases
62
- hpg_databases
63
- end
64
-
65
- def database_name_from_url(url)
66
- vars = bot_config_vars.reject {|key,value| key == 'DATABASE_URL'}
67
- if var = vars.invert[url]
68
- var.gsub(/_URL$/, '')
69
- else
70
- uri = URI.parse(url)
71
- "Database on #{uri.host}:#{uri.port || 5432}#{uri.path}"
72
- end
73
- end
74
-
75
- def hpg_addon_name
76
- if ENV['SHOGUN']
77
- "shogun-#{ENV['SHOGUN']}"
78
- else
79
- ENV['TURBOT_POSTGRESQL_ADDON_NAME'] || 'turbot-postgresql'
80
- end
81
- end
82
-
83
- private
84
-
85
- def protect_missing_bot
86
- # in the case where --bot was left out, AND bot::db shorthand was not used, AND no bot autodetect
87
- unless bot_name
88
- error("No bot specified.\nRun this command from an bot folder or specify which bot to use with --bot APP.")
89
- end
90
- end
91
-
92
- def bot_config_vars
93
- protect_missing_bot
94
- @bot_config_vars ||= api.get_config_vars(bot_name).body
95
- end
96
-
97
- def bot_attachments
98
- protect_missing_bot
99
- @bot_attachments ||= api.get_attachments(bot_name).body.map { |raw| Attachment.new(raw) }
100
- end
101
-
102
- def hpg_databases
103
- return @hpg_databases if @hpg_databases
104
- pairs = bot_attachments.select {|att|
105
- att.addon == hpg_addon_name
106
- }.map { |att|
107
- [att.config_var, att]
108
- }
109
- @hpg_databases = Hash[ pairs ]
110
-
111
- if find_database_url_real_attachment
112
- @hpg_databases['DATABASE_URL'] = find_database_url_real_attachment
113
- end
114
-
115
- return @hpg_databases
116
- end
117
-
118
- def resource_url(resource)
119
- api.get_resource(resource).body['value']
120
- end
121
-
122
- def forget_config!
123
- @hpg_databases = nil
124
- @bot_config_vars = nil
125
- @bot_attachments = nil
126
- end
127
-
128
- def find_database_url_real_attachment
129
- raw_primary_db_url = bot_config_vars['DATABASE_URL']
130
- return unless raw_primary_db_url
131
-
132
- primary_db_url = raw_primary_db_url.split("?").first
133
- return unless primary_db_url && !primary_db_url.empty?
134
-
135
- real_config = bot_config_vars.detect {|k,v| k != 'DATABASE_URL' && v == primary_db_url }
136
- if real_config
137
- real = hpg_databases[real_config.first]
138
- real.primary_attachment! if real
139
- return real
140
- else
141
- return nil
142
- end
143
- end
144
-
145
- def match_attachments_by_name(name)
146
- return [] if name.empty?
147
- return [name] if hpg_databases[name]
148
- hpg_databases.keys.grep(%r{#{ name }}i)
149
- end
150
-
151
- def hpg_resolve(name, default=nil)
152
- name = '' if name.nil?
153
- name = 'DATABASE_URL' if name == 'DATABASE'
154
-
155
- if hpg_databases.empty?
156
- error("Your bot has no databases.")
157
- end
158
-
159
- found_attachment = nil
160
- candidates = match_attachments_by_name(name)
161
- if default && name.empty? && bot_config_vars[default]
162
- found_attachment = hpg_databases[default]
163
- elsif candidates.size == 1
164
- found_attachment = hpg_databases[candidates.first]
165
- end
166
-
167
- if found_attachment.nil?
168
- error("Unknown database#{': ' + name unless name.empty?}. Valid options are: #{hpg_databases.keys.sort.join(", ")}")
169
- end
170
-
171
- return found_attachment
172
- end
173
- end
174
-
175
- def hpg_translate_fork_and_follow(addon, config)
176
- $stderr.puts " ! #hpg_translate_fork_and_follow is deprecated. Update your plugins."
177
- hpg_translate_db_opts_to_urls(addon, config)
178
- end
179
-
180
- def hpg_translate_db_opts_to_urls(addon, config)
181
- bot_name = bot rescue nil
182
- resolver = Resolver.new(bot_name, api)
183
- if addon =~ /^#{resolver.hpg_addon_name}/
184
- %w[fork follow rollback].each do |opt|
185
- if val = config[opt]
186
- unless val.is_a?(String)
187
- error("--#{opt} requires a database argument.")
188
- end
189
-
190
- uri = URI.parse(val) rescue nil
191
- if uri && uri.scheme && uri.scheme == 'postgres'
192
- argument_url = uri.to_s
193
- else
194
- attachment = resolver.resolve(val)
195
- if attachment.starter_plan?
196
- error("#{opt.tr 'f', 'F'} is only available on production databases.")
197
- end
198
- argument_url = attachment.url
199
- end
200
-
201
- config[opt] = argument_url
202
- end
203
- end
204
- end
205
- end
206
-
207
- private
208
-
209
- def hpg_promote(url)
210
- api.put_config_vars(bot, "DATABASE_URL" => url)
211
- end
212
-
213
- end