octopusci 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
- num_jobs = Octopusci::JobStore.size
9
- jobs = Octopusci::JobStore.list(0, num_jobs)
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
- # delete the actual job record
13
- Octopusci::JobStore.redis.del("octopusci:jobs:#{j['id']}")
20
+ jobs.each do |j|
21
+ # delete the actual job record
22
+ Octopusci::JobStore.redis.del("octopusci:jobs:#{j['id']}")
14
23
 
15
- # delete the repo_name, branch_name job references
16
- Octopusci::JobStore.redis.del("octopusci:#{j['repo_name']}:#{j['branch_name']}:jobs")
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
- # delete the github payload for the repo_name, branch_name
19
- Octopusci::JobStore.redis.del("octopusci:github_payload:#{j['repo_name']}:#{j['branch_name']}")
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::JobStore.redis.del('octopusci:job_count')
24
- Octopusci::JobStore.redis.del('octopusci:jobs')
25
- Octopusci::JobStore.redis.del('octopusci:stagelocker')
26
- Octopusci::JobStore.redis.del('queue:octopusci:commit')
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
- FileUtils.mkdir_p(JOBS_PATH)
17
-
18
- if !File.exists?(CONFIG_PATH)
19
- File.open(CONFIG_PATH, 'w') do |f|
20
- f << "general:
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: SomeJobClass, repo_uri: 'git@github.com:cyphactor/octopusci.git', default_email: devs@example.com }
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
- - test_b
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
@@ -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
- # The StageLocker.load() method is called here not only to set things into
26
- # valid initial state. But, also in the case that octopusci-tentacles was
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
- case ARGV[0]
45
+ cmd = ARGV.shift # get the subcommand
46
+ case cmd
34
47
  when "start"
35
- Octopusci::WorkerLauncher.cleanup_existing_workers()
36
- Octopusci::WorkerLauncher.launch()
48
+ start_or_restart()
37
49
  when "restart"
38
- Octopusci::WorkerLauncher.cleanup_existing_workers()
39
- Octopusci::WorkerLauncher.launch()
50
+ start_or_restart()
40
51
  when "stop"
41
52
  Octopusci::WorkerLauncher.cleanup_existing_workers()
42
53
  when "help"
43
- display_help()
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
@@ -1,3 +1,6 @@
1
+ require 'resque'
2
+ require 'yaml'
3
+
1
4
  module Octopusci
2
5
  class JobStore
3
6
  def self.prepend(job)
@@ -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 <% if @page_logo %> - <%= @page_logo %><% end %>
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>
@@ -6,6 +6,14 @@ module Octopusci
6
6
  clear
7
7
  stages.each { |s| push(s) }
8
8
  end
9
+
10
+ def self.exists?
11
+ self.redis.exists('octopusci:stagelocker')
12
+ end
13
+
14
+ def self.empty?
15
+ !exists?
16
+ end
9
17
 
10
18
  def self.clear
11
19
  self.redis.del('octopusci:stagelocker')
@@ -1,3 +1,3 @@
1
1
  module Octopusci
2
- Version = VERSION = '0.3.6'
2
+ Version = VERSION = '0.3.7'
3
3
  end
@@ -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.6
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-11-12 00:00:00.000000000 Z
13
+ date: 2011-12-12 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sinatra
17
- requirement: &70209939639560 !ruby/object:Gem::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: *70209939639560
25
+ version_requirements: *70349244223700
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: json
28
- requirement: &70209939638360 !ruby/object:Gem::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: *70209939638360
36
+ version_requirements: *70349244223280
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: resque
39
- requirement: &70209939637360 !ruby/object:Gem::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: *70209939637360
47
+ version_requirements: *70349244222860
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: actionmailer
50
- requirement: &70209939636720 !ruby/object:Gem::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: *70209939636720
58
+ version_requirements: *70349244222440
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: multi_json
61
- requirement: &70209939635860 !ruby/object:Gem::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: *70209939635860
69
+ version_requirements: *70349244222020
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: time-ago-in-words
72
- requirement: &70209939635160 !ruby/object:Gem::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: *70209939635160
80
+ version_requirements: *70349244221600
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: ansi2html
83
- requirement: &70209939634180 !ruby/object:Gem::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: *70209939634180
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: &70209939632520 !ruby/object:Gem::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: *70209939632520
113
+ version_requirements: *70349244220340
103
114
  - !ruby/object:Gem::Dependency
104
115
  name: rspec
105
- requirement: &70209939632020 !ruby/object:Gem::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: *70209939632020
124
+ version_requirements: *70349244219920
114
125
  - !ruby/object:Gem::Dependency
115
126
  name: rack-test
116
- requirement: &70209939631460 !ruby/object:Gem::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: *70209939631460
135
+ version_requirements: *70349244219500
125
136
  - !ruby/object:Gem::Dependency
126
137
  name: guard
127
- requirement: &70209939630660 !ruby/object:Gem::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: *70209939630660
146
+ version_requirements: *70349244235460
136
147
  - !ruby/object:Gem::Dependency
137
148
  name: rb-fsevent
138
- requirement: &70209939628140 !ruby/object:Gem::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: *70209939628140
157
+ version_requirements: *70349244235040
147
158
  - !ruby/object:Gem::Dependency
148
159
  name: growl_notify
149
- requirement: &70209939626500 !ruby/object:Gem::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: *70209939626500
168
+ version_requirements: *70349244234620
158
169
  - !ruby/object:Gem::Dependency
159
170
  name: guard-rspec
160
- requirement: &70209939624700 !ruby/object:Gem::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: *70209939624700
169
- description: A multi-branch Continous Integration server that integrates with GitHub
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