slotbox 0.0.2
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.
- data/README.md +28 -0
- data/bin/slotbox +66 -0
- data/lib/rubygems_plugin.rb +12 -0
- data/lib/slotbox.rb +4 -0
- data/plugin/init.rb +9 -0
- data/plugin/lib/slotbox/api/deploying.rb +15 -0
- data/plugin/lib/slotbox/command/apps.rb +62 -0
- data/plugin/lib/slotbox/command/base.rb +79 -0
- data/plugin/lib/slotbox/command/deploy.rb +58 -0
- data/plugin/lib/slotbox/command/help.rb +12 -0
- data/plugin/lib/slotbox/ruby/puts.rb +8 -0
- metadata +57 -0
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Slotbox CLI
|
2
|
+
===========
|
3
|
+
|
4
|
+
Command line tool for interacting with Slotbox.
|
5
|
+
|
6
|
+
# Installation
|
7
|
+
`gem install slotbox`
|
8
|
+
|
9
|
+
# Usage
|
10
|
+
|
11
|
+
It has exactly the same usage as the [Heroku CLi client](https://devcenter.heroku.com/categories/command-line), except for one extra command and a few unsupported commands.
|
12
|
+
|
13
|
+
## Extra commands
|
14
|
+
|
15
|
+
`slotbox deploy`
|
16
|
+
|
17
|
+
Slotbox enforces the use of public Github repos to ensure that funders can always scrutinise the code in which they are investing. Therefore deployment
|
18
|
+
is done by the Slotbox API rather a `git push`.
|
19
|
+
|
20
|
+
## Unsupported commands
|
21
|
+
|
22
|
+
`addons, certs, db, drains, keys, labs, pg, pgbackups, ssl, stack`
|
23
|
+
|
24
|
+
# Caveats
|
25
|
+
|
26
|
+
The Slotbox gem piggybacks off the Heroku gem using Heroku's plugin architecture. As such it overrides IO#puts in order
|
27
|
+
to replace all occurrences of 'heroku' with 'slotbox'! But until the Slotbox client is a bonafide fork of the Heroku client
|
28
|
+
this will have to do.
|
data/bin/slotbox
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'slotbox'
|
4
|
+
|
5
|
+
# Cross-platform way of finding an executable in the $PATH.
|
6
|
+
#
|
7
|
+
# which('ruby') #=> /usr/bin/ruby
|
8
|
+
def which(cmd)
|
9
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
10
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
11
|
+
exts.each { |ext|
|
12
|
+
exe = "#{path}/#{cmd}#{ext}"
|
13
|
+
return exe if File.executable? exe
|
14
|
+
}
|
15
|
+
end
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Install the Heroku Toolbelt
|
20
|
+
if ! which "heroku"
|
21
|
+
puts "The Heroku Toolbelt isn't installed on your system."
|
22
|
+
if RUBY_PLATFORM =~ /linux/
|
23
|
+
puts "Would you like to install it now? (y/n)"
|
24
|
+
begin
|
25
|
+
system("stty raw -echo")
|
26
|
+
answer = STDIN.getc
|
27
|
+
ensure
|
28
|
+
system("stty -raw echo")
|
29
|
+
end
|
30
|
+
if ['y', 'yes'].include? answer
|
31
|
+
system "wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
puts "Please visit https://toolbelt.heroku.com/ to install"
|
35
|
+
end
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
# Make sure the Heroku-Slotbox plugin is installed
|
40
|
+
if !File.exists? Slotbox::PLUGIN_DIR + "/init.rb"
|
41
|
+
puts "Installing Slotbox-Heroku plugin..."
|
42
|
+
require 'rubygems'
|
43
|
+
spec = Gem::Specification.find_by_name("slotbox")
|
44
|
+
system "mkdir -p #{Slotbox::PLUGIN_DIR}"
|
45
|
+
system "cp -rf #{spec.gem_dir}/plugin/* #{Slotbox::PLUGIN_DIR}"
|
46
|
+
puts "Slotbox-Heroku plugin installed. It will automatically be removed when you uninstall this gem."
|
47
|
+
end
|
48
|
+
|
49
|
+
if ARGV.length > 0
|
50
|
+
if Slotbox::UNSUPPORTED_COMMANDS.select{ |c| ARGV.first.start_with? c }.length > 0
|
51
|
+
$stderr.puts " ! Slotbox does not currently support this command."
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
slotbox_host = ENV["SLOTBOX_HOST"] || "slotbox.es"
|
57
|
+
|
58
|
+
system <<-EOF
|
59
|
+
|
60
|
+
export HEROKU_HOST=${HEROKU_HOST:-http://#{slotbox_host}:5000/}
|
61
|
+
export HEROKU_STATUS_HOST=${HEROKU_STATUS_HOST:-"#{slotbox_host}"}
|
62
|
+
export HEROKU_SSL_VERIFY=${HEROKU_SSL_VERIFY:-"disable"}
|
63
|
+
|
64
|
+
exec heroku #{ARGV.join(" ")}
|
65
|
+
|
66
|
+
EOF
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'slotbox'
|
3
|
+
|
4
|
+
# I can't believe this runs *every* time *any* (yes, any) gem is unisntalled
|
5
|
+
# And that it isn't documented!
|
6
|
+
Gem.post_uninstall do |uninstaller|
|
7
|
+
if uninstaller.spec.name == 'slotbox'
|
8
|
+
puts "Uninstalling Slotbox-Heroku plugin..."
|
9
|
+
system "rm -rf #{Slotbox::PLUGIN_DIR}"
|
10
|
+
puts "Slotbox-Heroku plugin uninstalled."
|
11
|
+
end
|
12
|
+
end
|
data/lib/slotbox.rb
ADDED
data/plugin/init.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# PUT /apps/:app/deploy
|
5
|
+
def put_app_deploy(app, github_url)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :put,
|
9
|
+
:path => "/apps/#{app}/deploy",
|
10
|
+
:query => app_params({"github_url" => github_url})
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Here we disbale the ability to manually name apps
|
2
|
+
# And remove other functionality not present in Slotbox
|
3
|
+
|
4
|
+
class Heroku::Command::Apps
|
5
|
+
|
6
|
+
# apps:create
|
7
|
+
#
|
8
|
+
# create a new app
|
9
|
+
#
|
10
|
+
# --addons ADDONS # a comma-delimited list of addons to install
|
11
|
+
# -b, --buildpack BUILDPACK # a buildpack url to use for this app
|
12
|
+
# -r, --remote REMOTE # the git remote to create, first github.com is default
|
13
|
+
#
|
14
|
+
#Examples:
|
15
|
+
#
|
16
|
+
# $ heroku apps:create
|
17
|
+
# Creating slotbox-nodejs-hello-world... done, stack is cedar
|
18
|
+
# http://slotbox-nodejs-hello-world.slotbox.es/
|
19
|
+
#
|
20
|
+
def create
|
21
|
+
name = app
|
22
|
+
validate_arguments!
|
23
|
+
|
24
|
+
info = api.post_app({
|
25
|
+
"name" => name,
|
26
|
+
"region" => options[:region]
|
27
|
+
}).body
|
28
|
+
begin
|
29
|
+
action("Creating #{info['name']}") do
|
30
|
+
if info['create_status'] == 'creating'
|
31
|
+
Timeout::timeout(options[:timeout].to_i) do
|
32
|
+
loop do
|
33
|
+
break if api.get_app(info['name']).body['create_status'] == 'complete'
|
34
|
+
sleep 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
status("stack is #{info['stack']}")
|
39
|
+
end
|
40
|
+
|
41
|
+
(options[:addons] || "").split(",").each do |addon|
|
42
|
+
addon.strip!
|
43
|
+
action("Adding #{addon} to #{info["name"]}") do
|
44
|
+
api.post_addon(info["name"], addon)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if buildpack = options[:buildpack]
|
49
|
+
api.put_config_vars(info["name"], "BUILDPACK_URL" => buildpack)
|
50
|
+
display("BUILDPACK_URL=#{buildpack}")
|
51
|
+
end
|
52
|
+
|
53
|
+
hputs(info["web_url"])
|
54
|
+
rescue Timeout::Error
|
55
|
+
hputs("Timed Out! Run `heroku status` to check for known platform issues.")
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
alias_command "create", "apps:create"
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Here we formalise the naming of Slotbox apps.
|
2
|
+
#
|
3
|
+
# Names consist of the Github user and the repo name, so;
|
4
|
+
# git@github.com:slotbox/nodejs-hello-world.git becomes
|
5
|
+
# => slotbox-nodejs-hello-world
|
6
|
+
# Errors are thrown if there is not a github.com remote on the local repo.
|
7
|
+
|
8
|
+
require "addressable/uri"
|
9
|
+
|
10
|
+
class Heroku::Command::Base
|
11
|
+
|
12
|
+
def app
|
13
|
+
@app ||= if options[:confirm].is_a?(String)
|
14
|
+
if options[:app] && (options[:app] != options[:confirm])
|
15
|
+
error("Mismatch between --app and --confirm")
|
16
|
+
end
|
17
|
+
options[:confirm]
|
18
|
+
elsif options[:app].is_a?(String)
|
19
|
+
options[:app]
|
20
|
+
elsif ENV.has_key?('SLOTBOX_APP')
|
21
|
+
ENV['SLOTBOX_APP']
|
22
|
+
elsif app_from_dir = extract_app_in_dir(Dir.pwd)
|
23
|
+
app_from_dir
|
24
|
+
else
|
25
|
+
# raise instead of using error command to enable rescuing when app is optional
|
26
|
+
raise Heroku::Command::CommandFailed.new("No app specified.\nRun this command from an app folder or specify which app to use with --app APP.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
def extract_app_in_dir(dir)
|
32
|
+
return unless remotes = git_remotes(dir)
|
33
|
+
|
34
|
+
if remote = options[:remote]
|
35
|
+
extract_app_name_from_remote remotes[remote]
|
36
|
+
elsif remote = extract_app_from_git_config
|
37
|
+
extract_app_name_from_remote remotes[remote]
|
38
|
+
else
|
39
|
+
apps = remotes.values.uniq
|
40
|
+
if apps.size == 1
|
41
|
+
extract_app_name_from_remote apps.first
|
42
|
+
else
|
43
|
+
raise(Heroku::Command::CommandFailed, "Multiple apps in folder and no app specified.\nSpecify app with --app APP.")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_app_from_git_config
|
49
|
+
remote = git("config slotbox.remote")
|
50
|
+
remote == "" ? nil : remote
|
51
|
+
end
|
52
|
+
|
53
|
+
def extract_app_name_from_remote remote
|
54
|
+
path = Addressable::URI.parse(remote).path.gsub(/\.git$/, '').split('/')
|
55
|
+
"#{path[-2]}-#{path[-1]}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def git_remotes(base_dir=Dir.pwd)
|
59
|
+
remotes = {}
|
60
|
+
original_dir = Dir.pwd
|
61
|
+
Dir.chdir(base_dir)
|
62
|
+
|
63
|
+
return unless File.exists?(".git")
|
64
|
+
git("remote -v").split("\n").each do |remote|
|
65
|
+
name, url = remote.split(/\s/)
|
66
|
+
if url =~ /github\.com/
|
67
|
+
remotes[name] = url
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Dir.chdir(original_dir)
|
72
|
+
if remotes.empty?
|
73
|
+
raise(Heroku::Command::CommandFailed, "You must have a git remote hosted on github.com")
|
74
|
+
else
|
75
|
+
remotes
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "addressable/uri"
|
2
|
+
|
3
|
+
module Heroku::Command
|
4
|
+
|
5
|
+
# deploy the app from its Github repo
|
6
|
+
class Deploy < BaseWithApp
|
7
|
+
|
8
|
+
def index
|
9
|
+
# Pick the first
|
10
|
+
remote = git "config --get remote.origin.url"
|
11
|
+
if remote.nil? || !remote.include?("github.com")
|
12
|
+
raise(CommandFailed, "A Github repo must be in a remote called 'origin'")
|
13
|
+
end
|
14
|
+
# Ensure that we have a non-SSH version of the repo, so we don't have to
|
15
|
+
# 'ensure the authenticity of the host' when pulling.
|
16
|
+
# Note that only Addressable::URI seems to be able to handle ssh-style URIs
|
17
|
+
path = Addressable::URI.parse(remote).path.split('/')
|
18
|
+
remote = "https://github.com/#{path[-2]}/#{path[-1]}"
|
19
|
+
|
20
|
+
app = git "config --get slotbox.app"
|
21
|
+
if app.nil?
|
22
|
+
raise(CommandFailed, "Cannot find Slotbox app name from git config")
|
23
|
+
end
|
24
|
+
|
25
|
+
process_data = action("Starting deploy", :success => "connected") do
|
26
|
+
process_data = api.put_app_deploy(app, remote).body
|
27
|
+
status(process_data["process"])
|
28
|
+
process_data
|
29
|
+
end
|
30
|
+
rendezvous_session(process_data["rendezvous_url"])
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
def rendezvous_session(rendezvous_url, &on_connect)
|
35
|
+
begin
|
36
|
+
set_buffer(false)
|
37
|
+
rendezvous = Heroku::Client::Rendezvous.new(
|
38
|
+
:rendezvous_url => rendezvous_url,
|
39
|
+
:connect_timeout => (ENV["HEROKU_CONNECT_TIMEOUT"] || 120).to_i,
|
40
|
+
:activity_timeout => nil,
|
41
|
+
:input => nil,
|
42
|
+
:output => $stdout)
|
43
|
+
rendezvous.on_connect(&on_connect)
|
44
|
+
rendezvous.start
|
45
|
+
rescue Timeout::Error
|
46
|
+
error "\nTimeout awaiting process"
|
47
|
+
rescue OpenSSL::SSL::SSLError
|
48
|
+
error "Authentication error"
|
49
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
50
|
+
error "\nError connecting to process"
|
51
|
+
rescue Interrupt
|
52
|
+
ensure
|
53
|
+
set_buffer(true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Oh god this is profound hack.
|
2
|
+
# It would be slightly more acceptable to just override Heroku's display(), error(), ets functions.
|
3
|
+
# But until the Heroku client is forked to Slotbox this will have to do :(
|
4
|
+
class IO
|
5
|
+
def puts(output="")
|
6
|
+
super(output.gsub("heroku", "slotbox").gsub("Heroku", "Slotbox"))
|
7
|
+
end
|
8
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: slotbox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tom BUckley-Houston
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Command-line tool to deploy and manage apps on Slotbox.
|
15
|
+
email: tom@tombh.co.uk
|
16
|
+
executables:
|
17
|
+
- slotbox
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- README.md
|
22
|
+
- bin/slotbox
|
23
|
+
- lib/rubygems_plugin.rb
|
24
|
+
- lib/slotbox.rb
|
25
|
+
- plugin/init.rb
|
26
|
+
- plugin/lib/slotbox/api/deploying.rb
|
27
|
+
- plugin/lib/slotbox/command/apps.rb
|
28
|
+
- plugin/lib/slotbox/command/base.rb
|
29
|
+
- plugin/lib/slotbox/command/deploy.rb
|
30
|
+
- plugin/lib/slotbox/command/help.rb
|
31
|
+
- plugin/lib/slotbox/ruby/puts.rb
|
32
|
+
homepage: http://slotbox.es
|
33
|
+
licenses:
|
34
|
+
- MIT
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 1.8.24
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: CLI to deploy and manage apps on Slotbox.
|
57
|
+
test_files: []
|