octopusci 0.3.6 → 0.3.7
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/bin/octopusci-install +131 -0
- data/bin/octopusci-post-build-request +42 -0
- data/bin/octopusci-reset-redis +42 -15
- data/bin/octopusci-reset-stage-locker +49 -0
- data/bin/octopusci-skel +61 -15
- data/bin/octopusci-tentacles +43 -29
- data/lib/octopusci/job.rb +1 -1
- data/lib/octopusci/job_store.rb +3 -0
- data/lib/octopusci/server/views/layout.erb +6 -1
- data/lib/octopusci/stage_locker.rb +8 -0
- data/lib/octopusci/version.rb +1 -1
- data/spec/lib/octopusci/stage_locker_spec.rb +29 -0
- metadata +47 -33
- data/bin/octopusci +0 -56
- data/bin/pusci-stage +0 -67
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
APP_NAME = "octopusci-install"
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'octopusci/version'
|
9
|
+
require 'trollop'
|
10
|
+
|
11
|
+
module Octopusci
|
12
|
+
class Installer
|
13
|
+
def initialize(opts)
|
14
|
+
@opts = opts
|
15
|
+
end
|
16
|
+
|
17
|
+
def install
|
18
|
+
# Create user account for octopusci to use.
|
19
|
+
warn(account_exists?(@opts[:account]), "The \"#{@opts[:account]}\" user account already exists.") {
|
20
|
+
delete_account(@opts[:account])
|
21
|
+
}
|
22
|
+
create_account(@opts[:account], @opts[:shell], @opts[:uid], @opts[:gid])
|
23
|
+
puts "Created the \"#{@opts[:account]}\" account."
|
24
|
+
|
25
|
+
# Do the same stuff octopusci-skel currently does but also include the user and group that the octopusci-tentacles should run as
|
26
|
+
# in the config.yml so that when octopusci-tentacles launches as root at boot it can properly switch to the proper uid and guid
|
27
|
+
|
28
|
+
# Make sure that there exists a .ssh/config in the account home directory with the proper permissions and that config has the
|
29
|
+
# option that makes it so that when sshing to github it doesn't make you manually accept the server host key.
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def create_account(account_name, shell, uid, gid)
|
35
|
+
if on_mac?
|
36
|
+
# Create the user entry.
|
37
|
+
`dscl . -create /Users/#{account_name}`
|
38
|
+
|
39
|
+
# Set the users shell.
|
40
|
+
`dscl . -create /Users/#{account_name} UserShell ${shell}`
|
41
|
+
|
42
|
+
# Set the users full name.
|
43
|
+
`dscl . -create /Users/#{account_name} RealName "#{account_name}"`
|
44
|
+
|
45
|
+
# Associate the user with a unique id.
|
46
|
+
`dscl . -create /Users/#{account_name} UniqueID #{uid}`
|
47
|
+
|
48
|
+
# Associate the user with a primary gorup id.
|
49
|
+
`dscl . -create /Users/#{account_name} PrimaryGroupID #{gid}`
|
50
|
+
|
51
|
+
# Create the users home directory.
|
52
|
+
`dscl . -create /Users/#{account_name} NFSHomeDirectory /Users/#{account_name}`
|
53
|
+
|
54
|
+
# Create the home directory and set the ownership properly.
|
55
|
+
`mkdir -p /Users/#{account_name}`
|
56
|
+
`chown -R #{uid}:#{gid} /Users/#{account_name}`
|
57
|
+
|
58
|
+
# Set the users password.
|
59
|
+
puts "Please enter the password for the \"#{account_name}\" account."
|
60
|
+
`passwd ${account_name}`
|
61
|
+
else
|
62
|
+
not_implemented
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete_account(account_name)
|
67
|
+
if on_mac?
|
68
|
+
# Remove the directory services record
|
69
|
+
`dscl . -delete /Users/#{account_name}`
|
70
|
+
else
|
71
|
+
not_implemented
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns a boolean identifying if an account with the given name already exists or not
|
76
|
+
def account_exists?(account_name)
|
77
|
+
if on_mac?
|
78
|
+
cmd_out = `dscl . -search /Users name "#{account_name}"`
|
79
|
+
return cmd_out.empty? ? false : true
|
80
|
+
else
|
81
|
+
not_implenented
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get a boolean representing if this is running on a Mac or not.
|
86
|
+
def on_mac?
|
87
|
+
return RUBY_PLATFORM.downcase.include?("darwin") ? true : false
|
88
|
+
end
|
89
|
+
|
90
|
+
def warn(warn, msg)
|
91
|
+
if warn
|
92
|
+
if @opts[:force]
|
93
|
+
puts "Warning: (Bypassed by -f) #{msg}"
|
94
|
+
yield
|
95
|
+
else
|
96
|
+
puts "Warning: #{msg}"
|
97
|
+
exit 2
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def error(msg)
|
103
|
+
puts "Error: #{msg}"
|
104
|
+
exit 1
|
105
|
+
end
|
106
|
+
|
107
|
+
def not_implemented
|
108
|
+
error("Not currently implemented")
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
opts = Trollop::options do
|
115
|
+
version "Octopusci v#{Octopusci::Version} (c) Andrew De Ponte"
|
116
|
+
banner """Usage: #{APP_NAME} [-i|--install|-a|--account|-v|--version|-h|--help]"""
|
117
|
+
opt :install, "Actually install Octopusci.", :short => "-i", :default => false
|
118
|
+
opt :force, "Force the install to continue ignoring warnings", :short => "-f", :default => false
|
119
|
+
opt :account, "Account name to create for the Octopusci install", :short => "-a", :default => "octopusci"
|
120
|
+
opt :uid, "User id to assign to the user account that is going to be created", :short => "-u", :default => "498"
|
121
|
+
opt :gid, "Primary group id to assign to the user account that is going to be created", :short => "-g", :default => "1000"
|
122
|
+
opt :shell, "Shell that used by the account that is going to be created", :short => "-s", :default => "/bin/bash"
|
123
|
+
end
|
124
|
+
|
125
|
+
if Process.uid != 0
|
126
|
+
error("Must run as root.")
|
127
|
+
end
|
128
|
+
|
129
|
+
installer = Octopusci::Installer.new(opts)
|
130
|
+
|
131
|
+
installer.install
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'octopusci/version'
|
7
|
+
require 'trollop'
|
8
|
+
require "uri"
|
9
|
+
require "net/http"
|
10
|
+
|
11
|
+
opts = Trollop::options do
|
12
|
+
version "Octopusci v#{Octopusci::Version} (c) Andrew De Ponte"
|
13
|
+
banner """Usage: octopusci-post-build-request [-v|--version|-h|--help]"""
|
14
|
+
opt :hostname, "Hostname/IP address to send the POST request to", :short => "-n", :default => '127.0.0.1'
|
15
|
+
opt :port, "Port number to connect to", :short => "-p", :default => 80
|
16
|
+
opt :repo_name, "Repository name to send build request for", :short => "-r", :default => "octopusci"
|
17
|
+
opt :branch_name, "Branch name to send build request for", :short => "-b", :default => 'master'
|
18
|
+
opt :owner_email, "Repository owner's email address", :short => "-o", :default => 'cyphactor@gmail.com'
|
19
|
+
opt :owner_name, "Repository owner's name", :short => "-w", :default => 'cyphactor'
|
20
|
+
opt :pusher_name, "Pusher's name", :short => "-u", :default => 'cyphactor'
|
21
|
+
opt :pusher_email, "Pusher's email address", :short => "-s", :default => 'pusher@example.com'
|
22
|
+
end
|
23
|
+
|
24
|
+
http = Net::HTTP.new(opts[:hostname], opts[:port])
|
25
|
+
path = '/github-build'
|
26
|
+
|
27
|
+
# POST request -> logging in
|
28
|
+
params = { 'payload' => "{\"base_ref\":null,\"ref\":\"refs/heads/#{opts[:branch_name]}\",\"commits\":[{\"message\":\"shit son\",\"removed\":[],\"modified\":[\"test.txt\"],\"added\":[],\"author\":{\"username\":\"cyphactor\",\"email\":\"cyphactor@gmail.com\",\"name\":\"Andrew De Ponte\"},\"distinct\":true,\"timestamp\":\"2011-09-06T22:01:12-07:00\",\"id\":\"8573e06a3cb511babd9d19d33be637b661232011\",\"url\":\"https://github.com/cyphactor/octopusci/commit/8573e06a3cb511babd9d19d33be637b661232011\"},{\"message\":\"again broham\",\"removed\":[],\"modified\":[\"test.txt\"],\"added\":[],\"author\":{\"username\":\"cyphactor\",\"email\":\"cyphactor@gmail.com\",\"name\":\"Andrew De Ponte\"},\"distinct\":true,\"timestamp\":\"2011-09-06T23:01:07-07:00\",\"id\":\"771adb4b75694804f256e7e61704648a14d52afc\",\"url\":\"https://github.com/cyphactor/octopusci/commit/771adb4b75694804f256e7e61704648a14d52afc\"},{\"message\":\"again broham\",\"removed\":[],\"modified\":[\"test.txt\"],\"added\":[],\"author\":{\"username\":\"cyphactor\",\"email\":\"cyphactor@gmail.com\",\"name\":\"Andrew De Ponte\"},\"distinct\":true,\"timestamp\":\"2011-09-06T23:03:16-07:00\",\"id\":\"dadf8446b2037960cc6223d60a7d57c5d264fa48\",\"url\":\"https://github.com/cyphactor/octopusci/commit/dadf8446b2037960cc6223d60a7d57c5d264fa48\"}],\"created\":false,\"before\":\"e5a1385fd8654c46d2b52d90c1ba31c865493602\",\"repository\":{\"created_at\":\"2011/09/02 12:40:14 -0700\",\"open_issues\":0,\"forks\":1,\"description\":\"Temp repo for testing pusci as I dev it\",\"has_wiki\":true,\"fork\":false,\"watchers\":1,\"has_downloads\":true,\"homepage\":\"\",\"has_issues\":true,\"private\":false,\"size\":116,\"owner\":{\"email\":\"#{opts[:owner_email]}\",\"name\":\"#{opts[:owner_name]}\"},\"name\":\"#{opts[:repo_name]}\",\"pushed_at\":\"2011/09/06 23:03:21 -0700\",\"url\":\"https://github.com/cyphactor/octopusci\"},\"pusher\":{\"email\":\"#{opts[:pusher_email]}\",\"name\":\"#{opts[:pusher_name]}\"},\"forced\":false,\"after\":\"dd6e7913cc12937db88e469684e8698f8eee8c14\",\"deleted\":false,\"compare\":\"https://github.com/cyphactor/octopusci/compare/e5a1385...dd6e791\"}" }
|
29
|
+
|
30
|
+
data = URI.encode_www_form(params)
|
31
|
+
headers = {
|
32
|
+
'Accept' => '*/*',
|
33
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
34
|
+
'X-Github-Event' => 'push'
|
35
|
+
}
|
36
|
+
|
37
|
+
resp, data = http.post(path, data, headers)
|
38
|
+
|
39
|
+
puts 'Code = ' + resp.code
|
40
|
+
puts 'Message = ' + resp.message
|
41
|
+
resp.each {|key, val| puts key + ' = ' + val}
|
42
|
+
puts data
|
data/bin/octopusci-reset-redis
CHANGED
@@ -3,24 +3,51 @@
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'octopusci'
|
6
|
+
require 'octopusci/version'
|
7
|
+
require 'octopusci/job_store'
|
8
|
+
require 'trollop'
|
9
|
+
|
10
|
+
opts = Trollop::options do
|
11
|
+
version "Octopusci v#{Octopusci::Version} (c) Andrew De Ponte"
|
12
|
+
banner """Usage: octopusci-reset-redis [-r|-v|--version|-h|--help]"""
|
13
|
+
opt :reset, "Actually reset the redis datastore", :short => "-r", :default => false
|
14
|
+
end
|
7
15
|
|
8
|
-
|
9
|
-
|
16
|
+
if opts[:reset]
|
17
|
+
num_jobs = Octopusci::JobStore.size
|
18
|
+
jobs = Octopusci::JobStore.list(0, num_jobs)
|
10
19
|
|
11
|
-
jobs.each do |j|
|
12
|
-
|
13
|
-
|
20
|
+
jobs.each do |j|
|
21
|
+
# delete the actual job record
|
22
|
+
Octopusci::JobStore.redis.del("octopusci:jobs:#{j['id']}")
|
14
23
|
|
15
|
-
|
16
|
-
|
24
|
+
# delete the repo_name, branch_name job references
|
25
|
+
Octopusci::JobStore.redis.del("octopusci:#{j['repo_name']}:#{j['branch_name']}:jobs")
|
17
26
|
|
18
|
-
|
19
|
-
|
27
|
+
# delete the github payload for the repo_name, branch_name
|
28
|
+
Octopusci::JobStore.redis.del("octopusci:github_payload:#{j['repo_name']}:#{j['branch_name']}")
|
20
29
|
|
21
|
-
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Octopusci::JobStore.redis.del('octopusci:job_count')
|
33
|
+
Octopusci::JobStore.redis.del('octopusci:jobs')
|
34
|
+
Octopusci::JobStore.redis.del('octopusci:stagelocker')
|
35
|
+
Octopusci::JobStore.redis.del('queue:octopusci:commit')
|
36
|
+
else
|
37
|
+
puts %Q{THIS IS A WARNING. THIS IS A DESTRUCTIVE COMMAND!
|
38
|
+
|
39
|
+
This command is designed to allow you to reset/clear out the values in your redis
|
40
|
+
data store associated with Octopusci. If you run this command with the proper option
|
41
|
+
it will actually get rid of all of the data stored in the redis datae store for Octopusci.
|
42
|
+
It is intended to be used very rarely and only by people that understand exactly what it
|
43
|
+
is going to do (primarily Octopusci Developers).
|
22
44
|
|
23
|
-
Octopusci
|
24
|
-
|
25
|
-
|
26
|
-
|
45
|
+
To go forward and actually reset the redis data store with respect to Octopusci run it using
|
46
|
+
the following example.
|
47
|
+
|
48
|
+
Example:
|
49
|
+
octopusci-reset-redis -r
|
50
|
+
|
51
|
+
}
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'octopusci/version'
|
7
|
+
require 'trollop'
|
8
|
+
|
9
|
+
opts = Trollop::options do
|
10
|
+
version "Octopusci v#{Octopusci::Version} (c) Andrew De Ponte"
|
11
|
+
banner """Usage: octopusci-reset-stage-locker [-r|-v|--version|-h|--help]"""
|
12
|
+
opt :reset, "Actually reset the stage locker", :short => "-r", :default => false
|
13
|
+
end
|
14
|
+
|
15
|
+
if opts[:reset]
|
16
|
+
puts "Reseting the Octopusci StageLocker, please wait..."
|
17
|
+
require 'octopusci'
|
18
|
+
Octopusci::StageLocker.load(Octopusci::Config['stages'])
|
19
|
+
puts "Succesfully Reset the Octopusci StageLocker"
|
20
|
+
else
|
21
|
+
puts %Q{THIS IS A WARNING. THIS IS A DESTRUCTIVE COMMAND!
|
22
|
+
|
23
|
+
This command is designed to allow you to reset/clear out the Octopusci StageLocker
|
24
|
+
and repopulate it with the stages defined in the config. If you run this command
|
25
|
+
with the proper option it will actually get rid of the Octopusci StageLocker and
|
26
|
+
recreate it with the stage values from the Octopusci config. It is intended to be
|
27
|
+
used very rarely.
|
28
|
+
|
29
|
+
The primary use case for it is that you have added a stage to your Octopusci setup
|
30
|
+
after already doing the initial setup. Running this command is necessary to make
|
31
|
+
Octopusci aware of the new stages you have added to the config since the initial
|
32
|
+
setup.
|
33
|
+
|
34
|
+
WARNING: You should not run this command until all job processes have completed.
|
35
|
+
Running 'octopusci-tentacles stop' only requests that the tentacles stop running
|
36
|
+
future jobs and that they kill themselves off once they are done with any current
|
37
|
+
jobs they are running. So, be sure you wait for the currently running jobs to
|
38
|
+
exit before you run this command or you could end up with multiple jobs running
|
39
|
+
on a single stage.
|
40
|
+
|
41
|
+
To go forward and actually reset the Octopusci StageLocker simply run the command
|
42
|
+
using the following example.
|
43
|
+
|
44
|
+
Example:
|
45
|
+
octopusci-reset-stage-locker -r
|
46
|
+
|
47
|
+
}
|
48
|
+
|
49
|
+
end
|
data/bin/octopusci-skel
CHANGED
@@ -2,25 +2,34 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
4
|
|
5
|
+
APP_NAME = "octopusci-skel"
|
6
|
+
|
5
7
|
require 'rubygems'
|
8
|
+
require 'octopusci/version'
|
6
9
|
require 'fileutils'
|
10
|
+
require 'trollop'
|
7
11
|
|
8
12
|
if Process.uid != 0
|
9
13
|
puts "Must run as root"
|
10
14
|
exit 1
|
11
15
|
end
|
12
16
|
|
17
|
+
opts = Trollop::options do
|
18
|
+
version "Octopusci v#{Octopusci::Version} (c) Andrew De Ponte"
|
19
|
+
banner """Usage: #{APP_NAME} [-c|-v|--version|-h|--help]"""
|
20
|
+
opt :create, "Actually create any missing pieces of the Octopusci Skeleton.", :short => "-c", :default => false
|
21
|
+
end
|
22
|
+
|
13
23
|
JOBS_PATH = '/etc/octopusci/jobs'
|
14
24
|
CONFIG_PATH = '/etc/octopusci/config.yml'
|
25
|
+
OCTOPUSCI_BUILD_PATH = '/etc/octopusci/jobs/octopusci_rspec_build_local.rb'
|
26
|
+
WORKSPACE_BASE_PATH = '/var/octopusci'
|
15
27
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
jobs_path: \"/etc/octopusci/jobs\"
|
22
|
-
base_url: \"http://localhost:9998\"
|
23
|
-
workspace_base_path: \"/Users/octopusci/.octopusci\"
|
28
|
+
config_default_content = %Q{
|
29
|
+
general:
|
30
|
+
jobs_path: "/etc/octopusci/jobs"
|
31
|
+
workspace_base_path: "#{WORKSPACE_BASE_PATH}"
|
32
|
+
base_url: "http://localhost:9998"
|
24
33
|
|
25
34
|
http_basic:
|
26
35
|
username: admin
|
@@ -37,15 +46,52 @@ smtp:
|
|
37
46
|
raise_delivery_errors: true
|
38
47
|
|
39
48
|
projects:
|
40
|
-
- { name: octopusci, owner: cyphactor, job_klass:
|
49
|
+
- { name: octopusci, owner: cyphactor, job_klass: OctopusciRSpecBuildLocal, repo_uri: 'git@github.com:cyphactor/octopusci.git', default_email: devs@example.com }
|
41
50
|
|
42
51
|
stages:
|
43
|
-
-
|
44
|
-
|
52
|
+
- test_a
|
53
|
+
}
|
54
|
+
|
55
|
+
octopusci_build_default_content = %Q{
|
56
|
+
class OctopusciRSpecBuildLocal < Octopusci::Job
|
57
|
+
def self.run(job_rec)
|
58
|
+
context "RSpec Tests (commit)" do
|
59
|
+
run_shell_cmd!("bundle install", true)
|
60
|
+
run_shell_cmd!("STAGE=\#{job_rec['stage']} bundle exec rspec spec 2>&1")
|
61
|
+
end
|
45
62
|
end
|
46
|
-
puts "Created example #{CONFIG_PATH}, please modify appropriately"
|
47
|
-
else
|
48
|
-
puts "#{CONFIG_PATH} already exists, exiting to avoid modification."
|
49
|
-
puts "If you would like to generated the example config again please rename the existing #{CONFIG_PATH}."
|
50
63
|
end
|
64
|
+
}
|
51
65
|
|
66
|
+
if opts[:create]
|
67
|
+
FileUtils.mkdir_p(JOBS_PATH)
|
68
|
+
puts "1. Ran mkdir -p #{JOBS_PATH}"
|
69
|
+
FileUtils.mkdir_p(WORKSPACE_BASE_PATH)
|
70
|
+
puts "2. Ran mkdir -p #{WORKSPACE_BASE_PATH}"
|
71
|
+
|
72
|
+
if !File.exists?(CONFIG_PATH)
|
73
|
+
File.open(CONFIG_PATH, 'w') do |f|
|
74
|
+
f << config_default_content
|
75
|
+
end
|
76
|
+
puts "3. Created example #{CONFIG_PATH}. Please modify appropriately"
|
77
|
+
else
|
78
|
+
puts "3. #{CONFIG_PATH} already exists. It has NOT been modified."
|
79
|
+
puts " If you would like to generate the example config again please rename the existing #{CONFIG_PATH} and rerun #{APP_NAME}."
|
80
|
+
end
|
81
|
+
|
82
|
+
if !File.exists?(OCTOPUSCI_BUILD_PATH)
|
83
|
+
File.open(OCTOPUSCI_BUILD_PATH, 'w') do |f|
|
84
|
+
f << octopusci_build_default_content
|
85
|
+
end
|
86
|
+
puts "4. Created example job definition (#{OCTOPUSCI_BUILD_PATH}). Please use as a starting point for your own jobs."
|
87
|
+
else
|
88
|
+
puts "4. #{OCTOPUSCI_BUILD_PATH} already exists. It has NOT been modified."
|
89
|
+
puts " If you would like to generate the example job definition again please rename the existing #{OCTOPUSCI_BUILD_PATH} and rerun #{APP_NAME}"
|
90
|
+
end
|
91
|
+
else
|
92
|
+
puts "This is a Dry Run\n No actions have been taken this is simply a description of what would take place if you ran this command with the create option (-c).\n\n"
|
93
|
+
puts " 1. mkdir -p #{JOBS_PATH}"
|
94
|
+
puts " 2. mkdir -p #{WORKSPACE_BASE_PATH}"
|
95
|
+
puts " 3. Create example config (#{CONFIG_PATH}) if one doesn't exist"
|
96
|
+
puts " 4. Create example job definition (#{OCTOPUSCI_BUILD_PATH}) if it doesn't exist"
|
97
|
+
end
|
data/bin/octopusci-tentacles
CHANGED
@@ -1,44 +1,58 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
def display_help
|
4
|
-
puts "Usage: octopusci-tentacles <command>"
|
5
|
-
puts " Acceptable Commands:"
|
6
|
-
puts " start - Cleanup existing workers and start new worker processes in the background"
|
7
|
-
puts " stop - Signals workers to exit when current job is finished"
|
8
|
-
puts " restart - Synonym for the 'start' command, just here for convenience"
|
9
|
-
puts " help - Display this help"
|
10
|
-
puts ""
|
11
|
-
puts " Example: octopusci-tentacles start"
|
12
|
-
puts ""
|
13
|
-
end
|
14
|
-
|
15
|
-
if !["start", "stop", "restart", "help"].include?(ARGV[0])
|
16
|
-
display_help()
|
17
|
-
exit 1
|
18
|
-
end
|
19
|
-
|
20
3
|
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
21
4
|
|
22
5
|
require 'rubygems'
|
23
6
|
require 'octopusci'
|
7
|
+
require 'trollop'
|
8
|
+
|
9
|
+
SUB_COMMANDS = %w(start, restart, stop, help)
|
10
|
+
|
11
|
+
p = Trollop::Parser.new do
|
12
|
+
version "Octopusci v#{Octopusci::Version} (c) Andrew De Ponte"
|
13
|
+
banner """Usage: octopusci-tentacles [-v|--version|-h|--help] <subcommand>
|
14
|
+
Acceptable SubCommands:
|
15
|
+
start - Cleanup existing workers and start new worker processes in the background
|
16
|
+
stop - Signals workers to exit when current job is finished
|
17
|
+
restart - Synonym for the 'start' command, just here for convenience
|
18
|
+
help - Display this help
|
19
|
+
|
20
|
+
Available Options:
|
21
|
+
"""
|
22
|
+
stop_on SUB_COMMANDS
|
23
|
+
end
|
24
|
+
|
25
|
+
opts = Trollop::with_standard_exception_handling(p) do
|
26
|
+
o = p.parse ARGV
|
27
|
+
raise Trollop::HelpNeeded if ARGV.empty? # show help screen
|
28
|
+
o
|
29
|
+
end
|
30
|
+
|
31
|
+
def start_or_restart
|
32
|
+
# The StageLocker.load() method is called here not only to set things into
|
33
|
+
# valid initial state. But, also in the case that octopusci-tentacles was
|
34
|
+
# killed it nukes the potentially screwed up state the redis data is in and
|
35
|
+
# initializes it the proper state based on the config.
|
36
|
+
if Octopusci::Config.has_key?('stages') && Octopusci::StageLocker.empty?
|
37
|
+
puts "Reseting stage locker and loading stages in from config."
|
38
|
+
Octopusci::StageLocker.load(Octopusci::Config['stages'])
|
39
|
+
end
|
24
40
|
|
25
|
-
|
26
|
-
|
27
|
-
# killed it nukes the potentially screwed up state the redis data is in and
|
28
|
-
# initializes it the proper state based on the config.
|
29
|
-
if Octopusci::Config.has_key?('stages')
|
30
|
-
Octopusci::StageLocker.load(Octopusci::Config['stages'])
|
41
|
+
Octopusci::WorkerLauncher.cleanup_existing_workers()
|
42
|
+
Octopusci::WorkerLauncher.launch()
|
31
43
|
end
|
32
44
|
|
33
|
-
|
45
|
+
cmd = ARGV.shift # get the subcommand
|
46
|
+
case cmd
|
34
47
|
when "start"
|
35
|
-
|
36
|
-
Octopusci::WorkerLauncher.launch()
|
48
|
+
start_or_restart()
|
37
49
|
when "restart"
|
38
|
-
|
39
|
-
Octopusci::WorkerLauncher.launch()
|
50
|
+
start_or_restart()
|
40
51
|
when "stop"
|
41
52
|
Octopusci::WorkerLauncher.cleanup_existing_workers()
|
42
53
|
when "help"
|
43
|
-
|
54
|
+
p.educate
|
55
|
+
else
|
56
|
+
p.die "unknown subcommand #{cmd.inspect}", nil
|
44
57
|
end
|
58
|
+
|
data/lib/octopusci/job.rb
CHANGED
@@ -118,7 +118,7 @@ module Octopusci
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def self.checkout_branch(job_conf)
|
121
|
-
return run_shell_cmd("cd #{repository_path} 2>&1 && git fetch --all -p 2>&1 && git checkout #{@job['branch_name']} 2>&1 && git pull -f origin #{@job['branch_name']}:#{@job['branch_name']} 2>&1", true, false)
|
121
|
+
return run_shell_cmd("cd #{repository_path} 2>&1 && git fetch --all -p 2>&1 && git reset --hard && git checkout #{@job['branch_name']} 2>&1 && git pull -f origin #{@job['branch_name']}:#{@job['branch_name']} 2>&1", true, false)
|
122
122
|
end
|
123
123
|
|
124
124
|
def self.get_recip_email
|
data/lib/octopusci/job_store.rb
CHANGED
@@ -22,6 +22,11 @@
|
|
22
22
|
color: white;
|
23
23
|
background-color: #333;
|
24
24
|
}
|
25
|
+
|
26
|
+
.version {
|
27
|
+
font-size: 11px;
|
28
|
+
margin-right: 10px;
|
29
|
+
}
|
25
30
|
|
26
31
|
#main_content_area {
|
27
32
|
width: 960px;
|
@@ -161,7 +166,7 @@
|
|
161
166
|
<body>
|
162
167
|
<div id="header">
|
163
168
|
<div id="logo">
|
164
|
-
Octopusci
|
169
|
+
Octopusci <span class="version">v<%= Octopusci::Version %></span><% if @page_logo %>( <%= @page_logo %> )<% end %>
|
165
170
|
</div>
|
166
171
|
<div id="main_nav">
|
167
172
|
<a href="/">Dashboard</a>
|
data/lib/octopusci/version.rb
CHANGED
@@ -17,6 +17,35 @@ describe "Octopusci::StageLocker" do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
describe "#exists?" do
|
21
|
+
it "should check if the redis key exists for the stage locker" do
|
22
|
+
@mock_redis.should_receive(:exists).with('octopusci:stagelocker')
|
23
|
+
Octopusci::StageLocker.exists?
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return fales if the stage locker key does not exists in redis" do
|
27
|
+
@mock_redis.stub(:exists).and_return(false)
|
28
|
+
Octopusci::StageLocker.exists?.should == false
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return true if the stage locker key exists in redis" do
|
32
|
+
@mock_redis.stub(:exists).and_return(true)
|
33
|
+
Octopusci::StageLocker.exists?.should == true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#empty?" do
|
38
|
+
it "should return true if exists? returns false" do
|
39
|
+
Octopusci::StageLocker.stub(:exists?).and_return(false)
|
40
|
+
Octopusci::StageLocker.empty?.should == true
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return false if exists? returns true" do
|
44
|
+
Octopusci::StageLocker.stub(:exists?).and_return(true)
|
45
|
+
Octopusci::StageLocker.empty?.should == false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
20
49
|
describe "#clear" do
|
21
50
|
it "should clear all of the stages out of the stage locker" do
|
22
51
|
r = mock('redis')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: octopusci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-12-12 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: sinatra
|
17
|
-
requirement: &
|
17
|
+
requirement: &70349244223700 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70349244223700
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: json
|
28
|
-
requirement: &
|
28
|
+
requirement: &70349244223280 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70349244223280
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: resque
|
39
|
-
requirement: &
|
39
|
+
requirement: &70349244222860 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70349244222860
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: actionmailer
|
50
|
-
requirement: &
|
50
|
+
requirement: &70349244222440 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70349244222440
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: multi_json
|
61
|
-
requirement: &
|
61
|
+
requirement: &70349244222020 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :runtime
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70349244222020
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: time-ago-in-words
|
72
|
-
requirement: &
|
72
|
+
requirement: &70349244221600 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,10 +77,10 @@ dependencies:
|
|
77
77
|
version: '0'
|
78
78
|
type: :runtime
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *70349244221600
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: ansi2html
|
83
|
-
requirement: &
|
83
|
+
requirement: &70349244221180 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
85
85
|
requirements:
|
86
86
|
- - ! '>='
|
@@ -88,10 +88,21 @@ dependencies:
|
|
88
88
|
version: '0'
|
89
89
|
type: :runtime
|
90
90
|
prerelease: false
|
91
|
-
version_requirements: *
|
91
|
+
version_requirements: *70349244221180
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: trollop
|
94
|
+
requirement: &70349244220760 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
type: :runtime
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: *70349244220760
|
92
103
|
- !ruby/object:Gem::Dependency
|
93
104
|
name: rake
|
94
|
-
requirement: &
|
105
|
+
requirement: &70349244220340 !ruby/object:Gem::Requirement
|
95
106
|
none: false
|
96
107
|
requirements:
|
97
108
|
- - ! '>='
|
@@ -99,10 +110,10 @@ dependencies:
|
|
99
110
|
version: '0'
|
100
111
|
type: :development
|
101
112
|
prerelease: false
|
102
|
-
version_requirements: *
|
113
|
+
version_requirements: *70349244220340
|
103
114
|
- !ruby/object:Gem::Dependency
|
104
115
|
name: rspec
|
105
|
-
requirement: &
|
116
|
+
requirement: &70349244219920 !ruby/object:Gem::Requirement
|
106
117
|
none: false
|
107
118
|
requirements:
|
108
119
|
- - ! '>='
|
@@ -110,10 +121,10 @@ dependencies:
|
|
110
121
|
version: '0'
|
111
122
|
type: :development
|
112
123
|
prerelease: false
|
113
|
-
version_requirements: *
|
124
|
+
version_requirements: *70349244219920
|
114
125
|
- !ruby/object:Gem::Dependency
|
115
126
|
name: rack-test
|
116
|
-
requirement: &
|
127
|
+
requirement: &70349244219500 !ruby/object:Gem::Requirement
|
117
128
|
none: false
|
118
129
|
requirements:
|
119
130
|
- - ! '>='
|
@@ -121,10 +132,10 @@ dependencies:
|
|
121
132
|
version: '0'
|
122
133
|
type: :development
|
123
134
|
prerelease: false
|
124
|
-
version_requirements: *
|
135
|
+
version_requirements: *70349244219500
|
125
136
|
- !ruby/object:Gem::Dependency
|
126
137
|
name: guard
|
127
|
-
requirement: &
|
138
|
+
requirement: &70349244235460 !ruby/object:Gem::Requirement
|
128
139
|
none: false
|
129
140
|
requirements:
|
130
141
|
- - ! '>='
|
@@ -132,10 +143,10 @@ dependencies:
|
|
132
143
|
version: '0'
|
133
144
|
type: :development
|
134
145
|
prerelease: false
|
135
|
-
version_requirements: *
|
146
|
+
version_requirements: *70349244235460
|
136
147
|
- !ruby/object:Gem::Dependency
|
137
148
|
name: rb-fsevent
|
138
|
-
requirement: &
|
149
|
+
requirement: &70349244235040 !ruby/object:Gem::Requirement
|
139
150
|
none: false
|
140
151
|
requirements:
|
141
152
|
- - ! '>='
|
@@ -143,10 +154,10 @@ dependencies:
|
|
143
154
|
version: '0'
|
144
155
|
type: :development
|
145
156
|
prerelease: false
|
146
|
-
version_requirements: *
|
157
|
+
version_requirements: *70349244235040
|
147
158
|
- !ruby/object:Gem::Dependency
|
148
159
|
name: growl_notify
|
149
|
-
requirement: &
|
160
|
+
requirement: &70349244234620 !ruby/object:Gem::Requirement
|
150
161
|
none: false
|
151
162
|
requirements:
|
152
163
|
- - ! '>='
|
@@ -154,10 +165,10 @@ dependencies:
|
|
154
165
|
version: '0'
|
155
166
|
type: :development
|
156
167
|
prerelease: false
|
157
|
-
version_requirements: *
|
168
|
+
version_requirements: *70349244234620
|
158
169
|
- !ruby/object:Gem::Dependency
|
159
170
|
name: guard-rspec
|
160
|
-
requirement: &
|
171
|
+
requirement: &70349244234200 !ruby/object:Gem::Requirement
|
161
172
|
none: false
|
162
173
|
requirements:
|
163
174
|
- - ! '>='
|
@@ -165,8 +176,8 @@ dependencies:
|
|
165
176
|
version: '0'
|
166
177
|
type: :development
|
167
178
|
prerelease: false
|
168
|
-
version_requirements: *
|
169
|
-
description: A multi-branch
|
179
|
+
version_requirements: *70349244234200
|
180
|
+
description: A multi-branch Continuous Integration server that integrates with GitHub
|
170
181
|
email:
|
171
182
|
- cyphactor@gmail.com
|
172
183
|
- sarmiena@gmail.com
|
@@ -174,6 +185,8 @@ executables:
|
|
174
185
|
- octopusci-tentacles
|
175
186
|
- octopusci-skel
|
176
187
|
- octopusci-reset-redis
|
188
|
+
- octopusci-reset-stage-locker
|
189
|
+
- octopusci-post-build-request
|
177
190
|
extensions: []
|
178
191
|
extra_rdoc_files: []
|
179
192
|
files:
|
@@ -204,11 +217,12 @@ files:
|
|
204
217
|
- lib/octopusci/version.rb
|
205
218
|
- lib/octopusci/worker_launcher.rb
|
206
219
|
- lib/octopusci.rb
|
207
|
-
- bin/octopusci
|
220
|
+
- bin/octopusci-install
|
221
|
+
- bin/octopusci-post-build-request
|
208
222
|
- bin/octopusci-reset-redis
|
223
|
+
- bin/octopusci-reset-stage-locker
|
209
224
|
- bin/octopusci-skel
|
210
225
|
- bin/octopusci-tentacles
|
211
|
-
- bin/pusci-stage
|
212
226
|
- spec/lib/octopusci/config_spec.rb
|
213
227
|
- spec/lib/octopusci/io_spec.rb
|
214
228
|
- spec/lib/octopusci/job_spec.rb
|
data/bin/octopusci
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
-
|
5
|
-
require 'rubygems'
|
6
|
-
require 'optparse'
|
7
|
-
|
8
|
-
# This hash will hold all of the options
|
9
|
-
# parsed from the command-line by
|
10
|
-
# OptionParser.
|
11
|
-
options = {}
|
12
|
-
|
13
|
-
optparse = OptionParser.new do|opts|
|
14
|
-
# Set a banner, displayed at the top
|
15
|
-
# of the help screen.
|
16
|
-
opts.banner = "Usage: optparse1.rb [options] file1 file2 ..."
|
17
|
-
|
18
|
-
# Define the options, and what they do
|
19
|
-
options[:verbose] = false
|
20
|
-
opts.on( '-v', '--verbose', 'Output more information' ) do
|
21
|
-
options[:verbose] = true
|
22
|
-
end
|
23
|
-
|
24
|
-
options[:quick] = false
|
25
|
-
opts.on( '-q', '--quick', 'Perform the task quickly' ) do
|
26
|
-
options[:quick] = true
|
27
|
-
end
|
28
|
-
|
29
|
-
options[:logfile] = nil
|
30
|
-
opts.on( '-l', '--logfile FILE', 'Write log to FILE' ) do |file|
|
31
|
-
options[:logfile] = file
|
32
|
-
end
|
33
|
-
|
34
|
-
# This displays the help screen, all programs are
|
35
|
-
# assumed to have this option.
|
36
|
-
opts.on( '-h', '--help', 'Display this screen' ) do
|
37
|
-
puts opts
|
38
|
-
exit
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Parse the command-line. Remember there are two forms
|
43
|
-
# of the parse method. The 'parse' method simply parses
|
44
|
-
# ARGV, while the 'parse!' method parses ARGV and removes
|
45
|
-
# any options found there, as well as any parameters for
|
46
|
-
# the options. What's left is the list of files to resize.
|
47
|
-
optparse.parse!
|
48
|
-
|
49
|
-
puts "Being verbose" if options[:verbose]
|
50
|
-
puts "Being quick" if options[:quick]
|
51
|
-
puts "Logging to file #{options[:logfile]}" if options[:logfile]
|
52
|
-
|
53
|
-
ARGV.each do|f|
|
54
|
-
puts "Resizing image #{f}..."
|
55
|
-
sleep 0.5
|
56
|
-
end
|
data/bin/pusci-stage
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
-
|
5
|
-
require 'rubygems'
|
6
|
-
require 'optparse'
|
7
|
-
require 'octopusci'
|
8
|
-
|
9
|
-
# This hash will hold all of the options
|
10
|
-
# parsed from the command-line by
|
11
|
-
# OptionParser.
|
12
|
-
options = {}
|
13
|
-
|
14
|
-
optparse = OptionParser.new do|opts|
|
15
|
-
# Set a banner, displayed at the top
|
16
|
-
# of the help screen.
|
17
|
-
opts.banner = "Usage: pusci-stage [options] stage_name"
|
18
|
-
|
19
|
-
# Define the options, and what they do
|
20
|
-
options[:add] = false
|
21
|
-
opts.on('-a', '--add', 'Add a stage back into the pool') do
|
22
|
-
options[:add] = true
|
23
|
-
end
|
24
|
-
|
25
|
-
options[:rem] = false
|
26
|
-
opts.on( '-r', '--rem', 'Rem a stage from the pool' ) do
|
27
|
-
options[:rem] = true
|
28
|
-
end
|
29
|
-
|
30
|
-
options[:list] = false
|
31
|
-
opts.on( '-l', '--list', 'List all stages' ) do
|
32
|
-
options[:list] = true
|
33
|
-
end
|
34
|
-
|
35
|
-
options[:pool] = false
|
36
|
-
opts.on( '-p', '--pool', 'List all stages currently in the pool' ) do
|
37
|
-
options[:pool] = true
|
38
|
-
end
|
39
|
-
|
40
|
-
# This displays the help screen, all programs are
|
41
|
-
# assumed to have this option.
|
42
|
-
opts.on( '-h', '--help', 'Display the help screen' ) do
|
43
|
-
puts opts
|
44
|
-
exit
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Parse the command-line. Remember there are two forms
|
49
|
-
# of the parse method. The 'parse' method simply parses
|
50
|
-
# ARGV, while the 'parse!' method parses ARGV and removes
|
51
|
-
# any options found there, as well as any parameters for
|
52
|
-
# the options. What's left is the list of files to resize.
|
53
|
-
optparse.parse!
|
54
|
-
|
55
|
-
if options[:list] == true
|
56
|
-
Octopusci::StageLocker.stages.each do |s|
|
57
|
-
puts s
|
58
|
-
end
|
59
|
-
elsif options[:pool] == true
|
60
|
-
puts Octopusci::StageLocker.pool
|
61
|
-
elsif options[:add] == true
|
62
|
-
Octopusci::StageLocker.push(ARGV[0])
|
63
|
-
elsif options[:rem] == true
|
64
|
-
Octopusci::StageLocker.rem(ARGV[0])
|
65
|
-
end
|
66
|
-
|
67
|
-
exit
|