slotbox 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|