hudson 0.2.4 → 0.2.5.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+ require 'socket'
2
+
3
+ Before do
4
+ @hudson_cleanup = []
5
+ end
6
+
7
+ After do
8
+ for port in @hudson_cleanup do
9
+ begin
10
+ TCPSocket.open("localhost", port) do |sock|
11
+ sock.write("0")
12
+ end
13
+ rescue
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module Matchers
3
+ def contain(expected)
4
+ Spec::Matchers::SimpleMatcher.new("contain #{expected.inspect}") do |given, matcher|
5
+ matcher.failure_message = "expected #{given.inspect} to contain #{expected.inspect}"
6
+ matcher.negative_failure_message = "expected #{given.inspect} not to contain #{expected.inspect}"
7
+ given.index expected
8
+ end
9
+ end
10
+ end
11
+
12
+ World(Matchers)
data/hudson.gemspec ADDED
@@ -0,0 +1,57 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{hudson}
5
+ s.version = "0.2.5.pre2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Charles Lowell", "Dr Nic Williams"]
9
+ s.date = %q{2010-06-22}
10
+ s.default_executable = %q{hudson}
11
+ s.description = %q{A suite of utilities for bringing continous integration to your projects (not the other way around) with hudson CI}
12
+ s.email = ["cowboyd@thefrontside.net", "drnicwilliams@gmail.com"]
13
+ s.executables = ["hudson"]
14
+ s.files = ["bin", "bin/hudson", "features", "features/create_jobs.feature", "features/development.feature", "features/fixtures", "features/fixtures/projects", "features/fixtures/projects/ruby", "features/fixtures/projects/ruby/Rakefile", "features/managing_remote_servers.feature", "features/server.feature", "features/step_definitions", "features/step_definitions/common_steps.rb", "features/step_definitions/fixture_project_steps.rb", "features/step_definitions/hudson_steps.rb", "features/step_definitions/scm_steps.rb", "features/support", "features/support/common.rb", "features/support/env.rb", "features/support/hooks.rb", "features/support/matchers.rb", "hudson.gemspec", "lib", "lib/hudson", "lib/hudson/api.rb", "lib/hudson/cli", "lib/hudson/cli/formatting.rb", "lib/hudson/cli.rb", "lib/hudson/hudson.war", "lib/hudson/job_config_builder.rb", "lib/hudson/plugins", "lib/hudson/plugins/git.hpi", "lib/hudson/plugins/github.hpi", "lib/hudson/plugins/greenballs.hpi", "lib/hudson/plugins/rake.hpi", "lib/hudson/plugins/ruby.hpi", "lib/hudson/project_scm.rb", "lib/hudson.rb", "Rakefile", "README.md", "spec", "spec/fixtures", "spec/fixtures/ec2_global.config.xml", "spec/fixtures/rails.multi.config.xml", "spec/fixtures/rails.single.config.xml", "spec/fixtures/rubygem.config.xml", "spec/fixtures/therubyracer.config.xml", "spec/job_config_builder_spec.rb", "spec/spec_helper.rb"]
15
+ s.homepage = %q{http://github.com/cowboyd/hudson.rb}
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{hudson}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{Painless Continuous Integration with Hudson Server}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<term-ansicolor>, [">= 1.0.4"])
27
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0.7.6"])
28
+ s.add_runtime_dependency(%q<httparty>, ["~> 0.5.2"])
29
+ s.add_runtime_dependency(%q<builder>, ["~> 2.1.2"])
30
+ s.add_runtime_dependency(%q<thor>, ["~> 0.13.6"])
31
+ s.add_runtime_dependency(%q<hpricot>, [">= 0"])
32
+ s.add_development_dependency(%q<cucumber>, ["~> 0.7.3"])
33
+ s.add_development_dependency(%q<rspec>, ["~> 1.3.0"])
34
+ s.add_development_dependency(%q<json>, ["~> 1.4.0"])
35
+ else
36
+ s.add_dependency(%q<term-ansicolor>, [">= 1.0.4"])
37
+ s.add_dependency(%q<yajl-ruby>, [">= 0.7.6"])
38
+ s.add_dependency(%q<httparty>, ["~> 0.5.2"])
39
+ s.add_dependency(%q<builder>, ["~> 2.1.2"])
40
+ s.add_dependency(%q<thor>, ["~> 0.13.6"])
41
+ s.add_dependency(%q<hpricot>, [">= 0"])
42
+ s.add_dependency(%q<cucumber>, ["~> 0.7.3"])
43
+ s.add_dependency(%q<rspec>, ["~> 1.3.0"])
44
+ s.add_dependency(%q<json>, ["~> 1.4.0"])
45
+ end
46
+ else
47
+ s.add_dependency(%q<term-ansicolor>, [">= 1.0.4"])
48
+ s.add_dependency(%q<yajl-ruby>, [">= 0.7.6"])
49
+ s.add_dependency(%q<httparty>, ["~> 0.5.2"])
50
+ s.add_dependency(%q<builder>, ["~> 2.1.2"])
51
+ s.add_dependency(%q<thor>, ["~> 0.13.6"])
52
+ s.add_dependency(%q<hpricot>, [">= 0"])
53
+ s.add_dependency(%q<cucumber>, ["~> 0.7.3"])
54
+ s.add_dependency(%q<rspec>, ["~> 1.3.0"])
55
+ s.add_dependency(%q<json>, ["~> 1.4.0"])
56
+ end
57
+ end
data/lib/hudson/api.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'httparty'
2
+ require 'cgi'
3
+
4
+ module Hudson
5
+ class Api
6
+ include HTTParty
7
+
8
+ headers 'content-type' => 'application/json'
9
+ format :json
10
+ # http_proxy 'localhost', '8888'
11
+
12
+ def self.setup_base_url(options)
13
+ server_name, host, port = options[:server], options[:host], options[:port]
14
+ return false unless host || server_name
15
+ p "http://#{host}:#{port}"
16
+ base_uri "http://#{host}:#{port}"
17
+ end
18
+
19
+ # returns true if successfully create a new job on Hudson
20
+ def self.create_job(name, job_config)
21
+ res = post "/createItem/api/xml?name=#{CGI.escape(name)}", {
22
+ :body => job_config.to_xml, :format => :xml, :headers => { 'content-type' => 'application/xml' }
23
+ }
24
+ if res.code == 200
25
+ true
26
+ else
27
+ require "hpricot"
28
+ puts "Server error:"
29
+ puts Hpricot(res.body).search("//body").text
30
+ false
31
+ end
32
+ end
33
+
34
+ def self.summary
35
+ get "/api/json"
36
+ end
37
+
38
+ # Return hash of job sta
39
+ def self.job(name)
40
+ get "/job/#{name}/api/json"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ require 'term/ansicolor'
2
+
3
+ module Hudson
4
+ class CLI < Thor
5
+ module Formatting
6
+ module ClassMethods
7
+ def task_help(shell, task_name)
8
+ meth = normalize_task_name(task_name)
9
+ task = all_tasks[meth]
10
+ handle_no_task_error(meth) unless task
11
+
12
+ shell.say "usage: #{banner(task)}"
13
+ shell.say
14
+ class_options_help(shell, nil => task.options.map { |_, o| o })
15
+ # shell.say task.description
16
+ # shell.say
17
+ end
18
+
19
+
20
+ def print_options(shell, options, grp = nil)
21
+ return if options.empty?
22
+ table = options.map do |option|
23
+ prototype = if option.default
24
+ " [#{option.default}]"
25
+ elsif option.boolean
26
+ ""
27
+ elsif option.required?
28
+ " #{option.banner}"
29
+ else
30
+ " [#{option.banner}]"
31
+ end
32
+ aliases = option.aliases.empty? ? "" : option.aliases.join(" ") + ","
33
+ [aliases, "--#{option.name}#{prototype}", "\t",option.description]
34
+ end
35
+ shell.print_table(table, :ident => 2)
36
+ shell.say
37
+ end
38
+ end
39
+
40
+ module InstanceMethods
41
+ def c
42
+ Term::ANSIColor
43
+ end
44
+ end
45
+
46
+ def self.included(receiver)
47
+ receiver.extend ClassMethods
48
+ receiver.send :include, InstanceMethods
49
+ end
50
+ end
51
+ end
52
+ end
53
+
data/lib/hudson/cli.rb ADDED
@@ -0,0 +1,141 @@
1
+ require 'thor'
2
+ require 'hudson/cli/formatting'
3
+
4
+ module Hudson
5
+ class CLI < Thor
6
+ include CLI::Formatting
7
+
8
+ map "-v" => :version, "--version" => :version, "-h" => :help, "--help" => :help
9
+
10
+ def self.common_options
11
+ method_option :host, :desc => 'connect to hudson server on this host'
12
+ method_option :port, :desc => 'connect to hudson server on this port'
13
+ method_option :server, :desc => 'connect to remote hudson server by search'
14
+ end
15
+
16
+ desc "server [options]", "run a hudson server"
17
+ method_option :home, :type => :string, :default => File.join(ENV['HOME'], ".hudson", "server"), :banner => "PATH", :desc => "use this directory to store server data"
18
+ method_option :port, :type => :numeric, :default => 3001, :desc => "run hudson server on this port", :aliases => "-p"
19
+ method_option :control, :type => :numeric, :default => 3002, :desc => "set the shutdown/control port", :aliases => "-c"
20
+ method_option :daemon, :type => :boolean, :default => false, :desc => "fork into background and run as a daemon"
21
+ method_option :kill, :type => :boolean, :desc => "send shutdown signal to control port", :aliases => "-k"
22
+ method_option :logfile, :type => :string, :banner => "PATH", :desc => "redirect log messages to this file"
23
+ def server
24
+ if options[:kill]
25
+ require 'socket'
26
+ TCPSocket.open("localhost", options[:control]) do |sock|
27
+ sock.write("0")
28
+ end
29
+ exit
30
+ end
31
+
32
+ serverhome = File.join(options[:home])
33
+ javatmp = File.join(serverhome, "javatmp")
34
+ FileUtils.mkdir_p serverhome
35
+ FileUtils.mkdir_p javatmp
36
+ FileUtils.cp_r Hudson::PLUGINS, serverhome
37
+ ENV['HUDSON_HOME'] = serverhome
38
+ cmd = ["java", "-Djava.io.tmpdir=#{javatmp}", "-jar", Hudson::WAR]
39
+ cmd << "--daemon" if options[:daemon]
40
+ cmd << "--logfile=#{File.expand_path(options[:logfile])}" if options[:logfile]
41
+ cmd << "--httpPort=#{options[:port]}"
42
+ cmd << "--controlPort=#{options[:control]}"
43
+ puts cmd.join(" ")
44
+ exec(*cmd)
45
+ end
46
+
47
+ desc "create [project_path] [options]", "create a continuous build for your project"
48
+ common_options
49
+ method_option :name, :banner => "dir_name", :desc => "name of the build"
50
+ def create(project_path = ".")
51
+ select_hudson_server(options)
52
+ FileUtils.chdir(project_path) do
53
+ unless scm = Hudson::ProjectScm.discover
54
+ error "Cannot determine project SCM. Currently supported: #{Hudson::ProjectScm.supported}"
55
+ end
56
+ job_config = Hudson::JobConfigBuilder.new(:rubygem) do |c|
57
+ c.scm = scm.url
58
+ end
59
+ name = options[:name] || File.basename(FileUtils.pwd)
60
+ if Hudson::Api.create_job(name, job_config)
61
+ build_url = "http://#{options[:host]}:#{options[:port]}/job/#{name.gsub(/\s/,'%20')}/build"
62
+ puts "Added project '#{name}' to Hudson."
63
+ puts "Trigger builds via: #{build_url}"
64
+ else
65
+ error "Failed to create project '#{name}'"
66
+ end
67
+ end
68
+ end
69
+
70
+ desc "list [project_path] [options]", "list builds on a hudson server"
71
+ common_options
72
+ def list(project_path = ".")
73
+ select_hudson_server(options)
74
+ FileUtils.chdir(project_path) do
75
+ if summary = Hudson::Api.summary
76
+ if summary["jobs"]
77
+ summary["jobs"].each do |job|
78
+ color = job['color']
79
+ color = 'green' if color == 'blue'
80
+ shell.say job['name'], color.to_sym, false
81
+ shell.say " - #{job['url']}"
82
+ end
83
+ else
84
+ display "No jobs found on #{options[:host]}:#{options[:port]}"
85
+ end
86
+ else
87
+ error "Failed connection to #{options[:host]}:#{options[:port]}"
88
+ end
89
+ end
90
+ end
91
+
92
+ desc "remote command [options]", "manage integration with hudson servers"
93
+ def remote(command)
94
+ puts command
95
+ end
96
+
97
+
98
+ desc "help [command]", "show help for hudson or for a specific command"
99
+ def help(*args)
100
+ super(*args)
101
+ end
102
+
103
+ desc "version", "show version information"
104
+ def version
105
+ shell.say "#{Hudson::VERSION} (Hudson Server #{Hudson::HUDSON_VERSION})"
106
+ end
107
+
108
+ def self.help(shell)
109
+ list = printable_tasks
110
+ shell.say <<-USEAGE
111
+ Hudson.rb is a smart set of utilities for making
112
+ continuous integration as simple as possible
113
+
114
+ Usage: hudson command [arguments] [options]
115
+
116
+ USEAGE
117
+
118
+ shell.say "Commands:"
119
+ shell.print_table(list, :ident => 2, :truncate => true)
120
+ shell.say
121
+ class_options_help(shell)
122
+ end
123
+
124
+ private
125
+
126
+ def select_hudson_server(options)
127
+ unless Hudson::Api.setup_base_url(options)
128
+ error "Either use --host or add remote servers."
129
+ end
130
+ end
131
+ def display(text)
132
+ shell.say text
133
+ exit
134
+ end
135
+
136
+ def error(text)
137
+ shell.say "ERROR: #{text}"
138
+ exit
139
+ end
140
+ end
141
+ end
Binary file
@@ -0,0 +1,161 @@
1
+ require "builder"
2
+
3
+ module Hudson
4
+ class JobConfigBuilder
5
+ attr_accessor :scm, :git_branches
6
+ attr_accessor :job_type, :matrix_project
7
+
8
+ def initialize(options = nil, &block)
9
+ if options.is_a?(Symbol)
10
+ @job_type = options.to_s
11
+ elsif options.is_a?(Hash)
12
+ @job_type = options[:job_type].to_s
13
+ end
14
+ @matrix_project = %w[rubygem].include? job_type
15
+ yield self
16
+ @git_branches ||= ["**"]
17
+ end
18
+
19
+ def builder
20
+ b = Builder::XmlMarkup.new :indent => 2
21
+ b.instruct!
22
+ b.tag!(matrix_project ? "matrix-project" : "project") do
23
+ b.actions
24
+ b.description
25
+ b.keepDependencies false
26
+ b.properties
27
+ build_scm b
28
+ b.canRoam true
29
+ b.disabled false
30
+ b.blockBuildWhenUpstreamBuilding false
31
+ build_triggers b
32
+ b.concurrentBuild false
33
+ build_axes b if matrix_project
34
+ build_steps b
35
+ b.publishers
36
+ b.buildWrappers
37
+ b.runSequentially false if matrix_project
38
+ end
39
+ end
40
+
41
+ def to_xml
42
+ builder.to_s
43
+ end
44
+
45
+ protected
46
+
47
+ # <scm class="hudson.plugins.git.GitSCM"> ... </scm>
48
+ def build_scm(b)
49
+ if scm && scm =~ /git/
50
+ b.scm :class => "hudson.plugins.git.GitSCM" do
51
+ b.configVersion 1
52
+ b.remoteRepositories do
53
+ b.tag! "org.spearce.jgit.transport.RemoteConfig" do
54
+ b.string "origin"
55
+ b.int 5
56
+ b.string "fetch"
57
+ b.string "+refs/heads/*:refs/remotes/origin/*"
58
+ b.string "receivepack"
59
+ b.string "git-upload-pack"
60
+ b.string "uploadpack"
61
+ b.string "git-upload-pack"
62
+ b.string "url"
63
+ b.string scm
64
+ b.string "tagopt"
65
+ b.string
66
+ end
67
+ end
68
+
69
+ if git_branches
70
+ b.branches do
71
+ git_branches.each do |branch|
72
+ b.tag! "hudson.plugins.git.BranchSpec" do
73
+ b.name branch
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ b.mergeOptions
80
+ b.doGenerateSubmoduleConfigurations false
81
+ b.clean false
82
+ b.choosingStrategy "Default"
83
+ b.submoduleCfg :class => "list"
84
+ end
85
+ end
86
+ end
87
+
88
+ # <triggers class="vector">
89
+ # <hudson.triggers.SCMTrigger>
90
+ # <spec># every minute
91
+ # * * * * *</spec>
92
+ # </hudson.triggers.SCMTrigger>
93
+ # </triggers>
94
+ def build_triggers(b)
95
+ b.triggers :class => "vector" do
96
+ b.tag! "hudson.triggers.SCMTrigger" do
97
+ b.spec "# every minute\n* * * * *"
98
+ end
99
+ end
100
+ end
101
+
102
+ def build_axes(b)
103
+ b.axes
104
+ end
105
+
106
+ def build_steps(b)
107
+ b.builders do
108
+ if job_type == "rails"
109
+ build_ruby_step b, <<-RUBY.gsub(/^ /, '')
110
+ unless File.exist?("config/database.yml")
111
+ require 'fileutils'
112
+ example = Dir["config/database*"].first
113
+ puts "Using \#{example} for config/database.yml"
114
+ FileUtils.cp example, "config/database.yml"
115
+ end
116
+ RUBY
117
+ build_rake_step b, "db:schema:load"
118
+ build_rake_step b, "features"
119
+ build_rake_step b, "spec"
120
+ elsif job_type == "rubygem"
121
+ build_rake_step b, "features"
122
+ end
123
+ end
124
+ end
125
+
126
+ # <hudson.plugins.ruby.Ruby>
127
+ # <command>unless File.exist?(&quot;config/database.yml&quot;)
128
+ # require &apos;fileutils&apos;
129
+ # example = Dir[&quot;config/database*&quot;].first
130
+ # puts &quot;Using #{example} for config/database.yml&quot;
131
+ # FileUtils.cp example, &quot;config/database.yml&quot;
132
+ # end</command>
133
+ # </hudson.plugins.ruby.Ruby>
134
+ def build_ruby_step(b, command)
135
+ b.tag! "hudson.plugins.ruby.Ruby" do
136
+ b.command command
137
+ end
138
+ end
139
+
140
+ # Usage: build_ruby_step b, "db:schema:load"
141
+ #
142
+ # <hudson.plugins.rake.Rake>
143
+ # <rakeInstallation>(Default)</rakeInstallation>
144
+ # <rakeFile></rakeFile>
145
+ # <rakeLibDir></rakeLibDir>
146
+ # <rakeWorkingDir></rakeWorkingDir>
147
+ # <tasks>db:schema:load</tasks>
148
+ # <silent>false</silent>
149
+ # </hudson.plugins.rake.Rake>
150
+ def build_rake_step(b, tasks)
151
+ b.tag! "hudson.plugins.rake.Rake" do
152
+ b.rakeInstallation "(Default)"
153
+ b.rakeFile
154
+ b.rakeLibDir
155
+ b.rakeWorkingDir
156
+ b.tasks tasks
157
+ b.silent false
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,22 @@
1
+ module Hudson
2
+ class ProjectScm
3
+
4
+ def self.discover
5
+ ProjectScmGit.new if File.exist?(".git") && File.directory?(".git")
6
+ end
7
+
8
+ def self.supported
9
+ %w[git]
10
+ end
11
+ end
12
+
13
+ class ProjectScmGit < ProjectScm
14
+ def initialize(url = nil)
15
+ @url = nil
16
+ end
17
+
18
+ def url
19
+ @url ||= `git config remote.origin.url`.strip
20
+ end
21
+ end
22
+ end
data/lib/hudson.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  module Hudson
2
- VERSION = "0.2.4"
3
- HUDSON_VERSION = "1.359"
4
- WAR = File.expand_path(File.dirname(__FILE__) + "/hudson/hudson.war")
5
- PLUGINS = File.expand_path(File.dirname(__FILE__) + "/hudson/plugins")
6
- end
2
+ VERSION = "0.2.5.pre2"
3
+ HUDSON_VERSION = "1.363"
4
+ WAR = File.expand_path(File.dirname(__FILE__) + "/hudson/hudson.war")
5
+ PLUGINS = File.expand_path(File.dirname(__FILE__) + "/hudson/plugins")
6
+ end
7
+
8
+ require 'hudson/api'
9
+ require 'hudson/job_config_builder'
10
+ require 'hudson/project_scm'
@@ -0,0 +1,103 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <hudson>
3
+ <version>1.359</version>
4
+ <numExecutors>2</numExecutors>
5
+ <mode>NORMAL</mode>
6
+ <authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
7
+ <securityRealm class="hudson.security.SecurityRealm$None"/>
8
+ <jdks/>
9
+ <clouds>
10
+ <hudson.plugins.ec2.EC2Cloud>
11
+ <name>ec2-US_EAST_1</name>
12
+ <accessId>0MVEQ5Q0BNYEGJX898G2</accessId>
13
+ <secretKey>[REMOVED]</secretKey>
14
+ <privateKey>
15
+ <privateKey>[REMOVED]</privateKey>
16
+ </privateKey>
17
+ <instanceCap>2147483647</instanceCap>
18
+ <templates>
19
+ <hudson.plugins.ec2.SlaveTemplate>
20
+ <ami>ami-79d43d10</ami>
21
+ <description>Ubuntu Lucid 10.04 64bit Server</description>
22
+ <remoteFS>/mnt/hudson</remoteFS>
23
+ <type>LARGE</type>
24
+ <labels>Ubuntu-Lucid-10.04-server-amd64 GCC_44</labels>
25
+ <initScript></initScript>
26
+ <userData></userData>
27
+ <numExecutors>4</numExecutors>
28
+ <remoteAdmin>ubuntu</remoteAdmin>
29
+ <rootCommandPrefix>sudo</rootCommandPrefix>
30
+ </hudson.plugins.ec2.SlaveTemplate>
31
+ <hudson.plugins.ec2.SlaveTemplate>
32
+ <ami>ami-e7d53c8e</ami>
33
+ <description>Ubuntu Karmic 9.10 64bit Server</description>
34
+ <remoteFS>/mnt/hudson</remoteFS>
35
+ <type>LARGE</type>
36
+ <labels>Ubuntu-Karmic-9.10-server-amd64 GCC_43</labels>
37
+ <initScript></initScript>
38
+ <userData></userData>
39
+ <numExecutors>4</numExecutors>
40
+ <remoteAdmin>ubuntu</remoteAdmin>
41
+ <rootCommandPrefix>sudo</rootCommandPrefix>
42
+ </hudson.plugins.ec2.SlaveTemplate>
43
+ </templates>
44
+ <region>US_EAST_1</region>
45
+ </hudson.plugins.ec2.EC2Cloud>
46
+ </clouds>
47
+ <slaves>
48
+ <slave>
49
+ <name>Legolas</name>
50
+ <description>Legolas Mac Pro</description>
51
+ <remoteFS>/Users/hudon/work</remoteFS>
52
+ <numExecutors>2</numExecutors>
53
+ <mode>NORMAL</mode>
54
+ <retentionStrategy class="hudson.slaves.RetentionStrategy$Always"/>
55
+ <launcher class="hudson.plugins.sshslaves.SSHLauncher">
56
+ <host>legolas.thefrontside.net</host>
57
+ <port>22</port>
58
+ <username>cowboyd</username>
59
+ <password>[REMOVED]</password>
60
+ <privatekey></privatekey>
61
+ <jvmOptions></jvmOptions>
62
+ </launcher>
63
+ <label>OSX-Snow-Leopard-10.6.3</label>
64
+ <nodeProperties/>
65
+ </slave>
66
+ <slave>
67
+ <name>Gimli</name>
68
+ <description>The Mac Mini Sitting on the bookshelf at the frontside office</description>
69
+ <remoteFS>/Users/hudson/work</remoteFS>
70
+ <numExecutors>2</numExecutors>
71
+ <mode>NORMAL</mode>
72
+ <retentionStrategy class="hudson.slaves.RetentionStrategy$Always"/>
73
+ <launcher class="hudson.plugins.sshslaves.SSHLauncher">
74
+ <host>gimli.thefrontside.net</host>
75
+ <port>22</port>
76
+ <username>hudson</username>
77
+ <password>[REMOVED]</password>
78
+ <privatekey></privatekey>
79
+ <jvmOptions></jvmOptions>
80
+ </launcher>
81
+ <label>OSX-Leopard-10.5</label>
82
+ <nodeProperties/>
83
+ </slave>
84
+ </slaves>
85
+ <quietPeriod>5</quietPeriod>
86
+ <scmCheckoutRetryCount>0</scmCheckoutRetryCount>
87
+ <views>
88
+ <hudson.model.AllView>
89
+ <owner class="hudson" reference="../../.."/>
90
+ <name>All</name>
91
+ <filterExecutors>false</filterExecutors>
92
+ <filterQueue>false</filterQueue>
93
+ </hudson.model.AllView>
94
+ </views>
95
+ <primaryView>All</primaryView>
96
+ <slaveAgentPort>0</slaveAgentPort>
97
+ <label></label>
98
+ <nodeProperties/>
99
+ <globalNodeProperties/>
100
+ <disabledAdministrativeMonitors>
101
+ <string>OldData</string>
102
+ </disabledAdministrativeMonitors>
103
+ </hudson>