pandemonium 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Pandemonium
2
+
3
+ ![](http://upload.wikimedia.org/wikipedia/commons/thumb/0/08/John_Martin_Le_Pandemonium_Louvre.JPG/640px-John_Martin_Le_Pandemonium_Louvre.JPG)
4
+
5
+ Everything started with this tweet:
6
+ https://twitter.com/poteland/status/339436974261805059
7
+
8
+ And then I tried to think the quickest (and probably dirtiest) way to do a
9
+ deploy app (aka Big Red Button)
10
+
11
+ ## Commands
12
+
13
+ ```bash
14
+ pandemonium add [repository] [deploy command]
15
+ pandemonium list
16
+ pandemonium run
17
+ ```
data/bin/pandemonium ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ $: << "lib"
3
+
4
+ require "clap"
5
+ require "pandemonium/cli"
6
+
7
+ Clap.run ARGV,
8
+ "run" => Pandemonium::CLI.method(:run),
9
+ "list" => Pandemonium::CLI.method(:list),
10
+ "add" => Pandemonium::CLI.method(:add)
11
+
12
+ # vim: ft=ruby
data/bin/worker.sh ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+
3
+ name="$1"
4
+ repo="$2"
5
+ deploy_script="$3"
6
+ branch=$4 || "master"
7
+ destination_folder="/tmp/$name"
8
+
9
+
10
+ if [ -d $destination_folder ]; then
11
+ cd $destination_folder
12
+ git pull
13
+ else
14
+ git clone $repo $destination_folder
15
+ fi
16
+
17
+ cd $destination_folder
18
+ $deploy_script
@@ -0,0 +1,11 @@
1
+ require "toml"
2
+ require "pandemonium/boss"
3
+ require "pandemonium/loader"
4
+
5
+ EM.kqueue = true
6
+ EventMachine.watch_file(Pandemonium::Loader::REPO_FILE, Pandemonium::Loader, config)
7
+ Pandemonium::ConfigLoader.new(config).load_repos
8
+
9
+ config["jobs"] = Hash.new do |h, k|
10
+ h[k] = Pandemonium::Boss.new(EM::Channel.new)
11
+ end
@@ -0,0 +1,52 @@
1
+ require "goliath/api"
2
+
3
+ EM.kqueue = true
4
+
5
+ module Pandemonium
6
+ class API < Goliath::API
7
+ use Goliath::Rack::Params
8
+ use Goliath::Rack::Render, ["json"]
9
+
10
+ def response(env)
11
+ case env["PATH_INFO"]
12
+ when "/"
13
+ puts env.repos
14
+ [200, {}, "Pandemonium"]
15
+ when "/attach"
16
+ project_name = env.params["project_name"]
17
+ boss = env.jobs[project_name]
18
+ channel = boss.channel
19
+
20
+ env.stream_close if !boss || !boss.running?
21
+
22
+ env["subscription"] = channel.subscribe do |message|
23
+ case message.type
24
+ when :data
25
+ env.stream_send(message.content)
26
+ when :exit_status
27
+ env.stream_send("Exit status: #{message.content}")
28
+ when :action
29
+ if message.content == :finish
30
+ channel.unsubscribe(env["subscription"])
31
+ env.stream_close
32
+ end
33
+ end
34
+ end
35
+
36
+ streaming_response(202, {"X-Stream" => "Pandemonium"})
37
+ when "/deploy"
38
+ project_name = env.params["project_name"]
39
+ project = env.repos[project_name]
40
+
41
+ boss = env.jobs[project_name]
42
+
43
+ if boss.running?
44
+ [200, {}, "Already deploying"]
45
+ else
46
+ boss.run_command project
47
+ [201, {}, "Deploying"]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,16 @@
1
+ require "pandemonium/job"
2
+
3
+ module Pandemonium
4
+ Boss = Struct.new(:channel) do
5
+ def run_command(repo)
6
+ puts "Starting Job"
7
+
8
+ @working_on = Pandemonium::Job.new(repo, channel)
9
+ @working_on.run
10
+ end
11
+
12
+ def running?
13
+ !!@working_on && @working_on.running?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ require "goliath/runner"
2
+ require "toml"
3
+ require "uri"
4
+ require "pandemonium/api"
5
+ require "pandemonium/loader"
6
+
7
+ module Pandemonium
8
+ module CLI
9
+ class << self
10
+ def run
11
+ # There must be a prettier way to pass options to the runner
12
+ argv = ["-sv"]
13
+ argv << "-c"
14
+ argv << File.join(File.expand_path("../../..", __FILE__), "config/pandemonium.rb")
15
+
16
+ runner = Goliath::Runner.new(argv, nil)
17
+ api = Pandemonium::API
18
+
19
+ runner.api = api.new
20
+ runner.app = Goliath::Rack::Builder.build(api, runner.api)
21
+ runner.run
22
+ end
23
+
24
+ def help
25
+ end
26
+
27
+ def list
28
+ get_projects.each do |name, items|
29
+ if !items["last_status"].to_s.empty?
30
+ message = "#{name}: [#{items["last_run"]}] #{items["deploy_script"]}"
31
+ puts colorize(message, items["last_status"] == 0 ? 32 : 31)
32
+ else
33
+ puts "#{name}: #{items["deploy_script"]}"
34
+ end
35
+ end
36
+ end
37
+
38
+ def colorize(text, color_code)
39
+ "\e[#{color_code}m#{text}\e[0m"
40
+ end
41
+
42
+ def add(repo, script)
43
+ config = get_projects
44
+ project_name = File.basename(repo, ".git")
45
+ repo_name = escape_key(project_name)
46
+
47
+ config[repo_name] = {
48
+ repository: repo,
49
+ deploy_script: script,
50
+ last_run: "",
51
+ last_status: ""
52
+ }
53
+
54
+ File.open(Pandemonium::Loader::REPO_FILE, "w") << TOML.dump(config)
55
+ end
56
+
57
+ def get_projects
58
+ TOML.load_file(Pandemonium::Loader::REPO_FILE)
59
+ end
60
+
61
+ def escape_key(key)
62
+ key.tr("-", "_")
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,22 @@
1
+ require "pandemonium/usain_bolt"
2
+
3
+ module Pandemonium
4
+ Job = Struct.new(:repo, :output) do
5
+ def run
6
+ worker = File.join(File.expand_path("../../..", __FILE__), "bin/worker.sh")
7
+ command = "#{worker} '#{repo.name}' '#{repo.repository}' '#{repo.deploy_script}'"
8
+ puts "Unix, do your thing. Running #{command}"
9
+
10
+ @shell_command = EM.popen(command, Pandemonium::UsainBolt, self)
11
+ end
12
+
13
+ def running?
14
+ @shell_command.running?
15
+ end
16
+
17
+ def finish(exit_status)
18
+ repo.last_status = exit_status
19
+ repo.save
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require "pandemonium/repos"
2
+
3
+ module Pandemonium
4
+ module Loader
5
+ REPO_FILE = File.expand_path("~/.pandemonium").freeze
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def load_repos
12
+ puts "reloading repos"
13
+ repos = TOML.load_file(REPO_FILE)
14
+
15
+ @config["repos"] = Pandemonium::Repos.new
16
+ @config["repos"].load(repos)
17
+ end
18
+
19
+ alias file_modified load_repos
20
+ end
21
+
22
+ class ConfigLoader
23
+ include Loader
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Pandemonium
2
+ Message = Struct.new(:type, :content)
3
+ end
@@ -0,0 +1,15 @@
1
+ module Pandemonium
2
+ Repo = Struct.new(:name, :repository, :deploy_script, :last_run, :last_status) do
3
+ def save
4
+ config = TOML.load_file(Pandemonium::Loader::REPO_FILE)
5
+ config[name].merge!({
6
+ "last_run" => Time.now,
7
+ "last_status" => last_status
8
+ })
9
+
10
+ toml_file = TOML.dump(config)
11
+
12
+ File.write(Pandemonium::Loader::REPO_FILE, toml_file)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ require "pandemonium/repo"
2
+
3
+ module Pandemonium
4
+ class Repos
5
+ def initialize
6
+ @repos = []
7
+ end
8
+
9
+ def [](name)
10
+ @repos.select { |item| item.name == name }.first
11
+ end
12
+
13
+ def <<(repo)
14
+ @repos << repo
15
+ end
16
+
17
+ def load(array)
18
+ Array(array).each do |name, repo|
19
+ @repos << Repo.new(name, repo["repository"], repo["deploy_script"])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ require "pandemonium/message"
2
+
3
+ module Pandemonium
4
+ class UsainBolt < EM::Connection
5
+ def initialize(job)
6
+ @job = job
7
+ @output = job.output
8
+ @buffer = StringIO.new
9
+ end
10
+
11
+ def post_init
12
+ @running = true
13
+ puts "Running!"
14
+ end
15
+
16
+ def receive_data(data)
17
+ @output << Pandemonium::Message.new(:data, data)
18
+ @buffer << data
19
+
20
+ puts "Command output: #{data}"
21
+ end
22
+
23
+ def unbind
24
+ @running = false
25
+ @buffer = nil
26
+
27
+ @job.finish(get_status.exitstatus)
28
+
29
+ @output << Pandemonium::Message.new(:exit_status, get_status.exitstatus)
30
+ @output << Pandemonium::Message.new(:action, :finish)
31
+ end
32
+
33
+ def running?; @running; end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "pandemonium"
3
+ s.executables = ["pandemonium"]
4
+ s.version = "0.0.1"
5
+ s.summary = "Pandemonium the deployer"
6
+ s.description = "Pandemonium is an app to run deployment instructions"
7
+ s.authors = ["elcuervo"]
8
+ s.email = ["yo@brunoaguirre.com"]
9
+ s.homepage = "http://github.com/elcuervo/pandemonium"
10
+ s.files = `git ls-files`.split("\n")
11
+ s.test_files = `git ls-files test`.split("\n")
12
+
13
+ s.add_dependency("goliath", "~> 1.0.2")
14
+ s.add_dependency("clap", "~> 1.0.0")
15
+ s.add_dependency("toml-rb", "~> 0.1.3")
16
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pandemonium
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - elcuervo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: goliath
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: clap
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: toml-rb
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.3
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.3
62
+ description: Pandemonium is an app to run deployment instructions
63
+ email:
64
+ - yo@brunoaguirre.com
65
+ executables:
66
+ - pandemonium
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - README.md
71
+ - bin/pandemonium
72
+ - bin/worker.sh
73
+ - config/pandemonium.rb
74
+ - lib/pandemonium/api.rb
75
+ - lib/pandemonium/boss.rb
76
+ - lib/pandemonium/cli.rb
77
+ - lib/pandemonium/job.rb
78
+ - lib/pandemonium/loader.rb
79
+ - lib/pandemonium/message.rb
80
+ - lib/pandemonium/repo.rb
81
+ - lib/pandemonium/repos.rb
82
+ - lib/pandemonium/usain_bolt.rb
83
+ - pandemonium.gemspec
84
+ homepage: http://github.com/elcuervo/pandemonium
85
+ licenses: []
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 1.8.23
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Pandemonium the deployer
108
+ test_files: []