pushwagner 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +42 -0
- data/Rakefile +8 -0
- data/bin/pw +26 -0
- data/lib/pushwagner/environment.rb +56 -0
- data/lib/pushwagner/ext.rb +59 -0
- data/lib/pushwagner/main.rb +25 -0
- data/lib/pushwagner/maven.rb +142 -0
- data/lib/pushwagner/static.rb +33 -0
- data/lib/pushwagner/supervisord.rb +14 -0
- data/lib/pushwagner/version.rb +3 -0
- data/lib/pushwagner.rb +6 -0
- data/pushwagner.gemspec +32 -0
- data/spec/configs/empty.yml +1 -0
- data/spec/configs/full.yml +26 -0
- data/spec/configs/maven-metadata.xml +24 -0
- data/spec/configs/maven.yml +19 -0
- data/spec/configs/settings.xml +14 -0
- data/spec/configs/static.yml +11 -0
- data/spec/environment_spec.rb +74 -0
- data/spec/maven_spec.rb +104 -0
- data/spec/spec_helper.rb +19 -0
- metadata +175 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.idea
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3@pw --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pushwagner (0.0.1)
|
5
|
+
net-scp
|
6
|
+
net-ssh
|
7
|
+
nokogiri (~> 1.5)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
coderay (1.0.8)
|
13
|
+
diff-lcs (1.1.3)
|
14
|
+
method_source (0.8.1)
|
15
|
+
net-scp (1.0.4)
|
16
|
+
net-ssh (>= 1.99.1)
|
17
|
+
net-ssh (2.6.1)
|
18
|
+
nokogiri (1.5.5)
|
19
|
+
pry (0.9.10)
|
20
|
+
coderay (~> 1.0.5)
|
21
|
+
method_source (~> 0.8)
|
22
|
+
slop (~> 3.3.1)
|
23
|
+
rake (0.9.5)
|
24
|
+
rspec (2.12.0)
|
25
|
+
rspec-core (~> 2.12.0)
|
26
|
+
rspec-expectations (~> 2.12.0)
|
27
|
+
rspec-mocks (~> 2.12.0)
|
28
|
+
rspec-core (2.12.0)
|
29
|
+
rspec-expectations (2.12.0)
|
30
|
+
diff-lcs (~> 1.1.3)
|
31
|
+
rspec-mocks (2.12.0)
|
32
|
+
slop (3.3.3)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
bundler (~> 1.0)
|
39
|
+
pry
|
40
|
+
pushwagner!
|
41
|
+
rake (~> 0.9)
|
42
|
+
rspec (~> 2.11)
|
data/Rakefile
ADDED
data/bin/pw
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pushwagner'
|
4
|
+
|
5
|
+
def get_version
|
6
|
+
puts "You must specify which version you wish to deploy: "
|
7
|
+
STDIN.gets.strip
|
8
|
+
end
|
9
|
+
|
10
|
+
# TODO: detect version requirement from config
|
11
|
+
version = 1 # ENV["VERSION"] || get_version
|
12
|
+
|
13
|
+
main = Pushwagner::Main.new(:config_file => 'config/deploy.yml', :version => version, :environment => 'staging')
|
14
|
+
|
15
|
+
# TODO: detect cli from config
|
16
|
+
case ARGV[0]
|
17
|
+
when "deploy"
|
18
|
+
main.deploy
|
19
|
+
main.restart
|
20
|
+
|
21
|
+
when "restart"
|
22
|
+
main.restart
|
23
|
+
|
24
|
+
else
|
25
|
+
puts "Usage: pw <deploy|restart>"
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'pushwagner/ext'
|
2
|
+
require 'pushwagner/maven'
|
3
|
+
|
4
|
+
module Pushwagner
|
5
|
+
|
6
|
+
class Environment
|
7
|
+
attr_reader :config
|
8
|
+
attr_accessor :current, :version
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
opts = HashWithIndifferentAccess.new(opts)
|
12
|
+
|
13
|
+
config_file = opts[:config_file] || File.join(File.dirname(__FILE__), '/config/deploy.yml')
|
14
|
+
@version = opts[:version]
|
15
|
+
@current = opts[:environment] || 'development'
|
16
|
+
|
17
|
+
@config = HashWithIndifferentAccess.new(YAML::load_file(config_file) || {})
|
18
|
+
end
|
19
|
+
|
20
|
+
def path_prefix
|
21
|
+
config['path_prefix'] || '/srv/www'
|
22
|
+
end
|
23
|
+
|
24
|
+
def maven
|
25
|
+
@maven = config['maven'] ? Maven.new(config['maven'], version) : {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def maven?
|
29
|
+
maven.any?
|
30
|
+
end
|
31
|
+
|
32
|
+
def static
|
33
|
+
config['static'] || {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def static?
|
37
|
+
static.any?
|
38
|
+
end
|
39
|
+
|
40
|
+
def environments
|
41
|
+
config['environments'] || {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def environment
|
45
|
+
environments[current] || {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def hosts
|
49
|
+
environment['hosts'] || []
|
50
|
+
end
|
51
|
+
|
52
|
+
def user
|
53
|
+
environment['user'] || "nobody"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Pushwagner
|
2
|
+
class HashWithIndifferentAccess < ::Hash
|
3
|
+
def initialize(hash={})
|
4
|
+
super()
|
5
|
+
hash.each do |key, value|
|
6
|
+
self[convert_key(key)] = value
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
super(convert_key(key))
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(key, value)
|
15
|
+
super(convert_key(key), value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(key)
|
19
|
+
super(convert_key(key))
|
20
|
+
end
|
21
|
+
|
22
|
+
def values_at(*indices)
|
23
|
+
indices.collect { |key| self[convert_key(key)] }
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge(other)
|
27
|
+
dup.merge!(other)
|
28
|
+
end
|
29
|
+
|
30
|
+
def merge!(other)
|
31
|
+
other.each do |key, value|
|
32
|
+
self[convert_key(key)] = value
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_hash
|
38
|
+
Hash.new(default).merge!(self)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def convert_key(key)
|
43
|
+
key.is_a?(Symbol) ? key.to_s : key
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(method, *args, &block)
|
47
|
+
method = method.to_s
|
48
|
+
if method =~ /^(\w+)\?$/
|
49
|
+
if args.empty?
|
50
|
+
!!self[$1]
|
51
|
+
else
|
52
|
+
self[$1] == args.first
|
53
|
+
end
|
54
|
+
else
|
55
|
+
self[method]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pushwagner
|
2
|
+
|
3
|
+
class Main
|
4
|
+
def initialize(opts = {})
|
5
|
+
@environment = Pushwagner::Environment.new(opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
def set_environment(env)
|
9
|
+
@environment.current = env.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_version(version)
|
13
|
+
@environment.version = version
|
14
|
+
end
|
15
|
+
|
16
|
+
def deploy(opts = {})
|
17
|
+
Maven::Deployer.new(@environment, opts).deploy
|
18
|
+
Static::Deployer.new(@environment, opts).deploy
|
19
|
+
end
|
20
|
+
|
21
|
+
def restart(opts = {})
|
22
|
+
Supervisord::Restarter.new(@environment, opts).restart
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'net/scp'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'nokogiri'
|
6
|
+
|
7
|
+
module Pushwagner
|
8
|
+
class Maven
|
9
|
+
|
10
|
+
attr_reader :repository, :artifacts
|
11
|
+
def initialize(maven, version)
|
12
|
+
return if !maven or maven.empty?
|
13
|
+
|
14
|
+
@version = version || required("Deployment version for artifacts is required")
|
15
|
+
@repository = Repository.new(maven['repositories'])
|
16
|
+
@artifacts = Hash[(maven['artifacts'] || {}).map { |k,h| [k, Artifact.new(h['artifact_id'], h['group_id'], h['version'] || version)] }]
|
17
|
+
end
|
18
|
+
|
19
|
+
def required(msg)
|
20
|
+
raise StandardError.new(msg)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Maven::Artifact
|
25
|
+
attr_reader :artifact_id, :group_id, :version
|
26
|
+
|
27
|
+
def initialize(artifact_id, group_id, version)
|
28
|
+
@artifact_id = artifact_id
|
29
|
+
@group_id = group_id
|
30
|
+
@version = version
|
31
|
+
end
|
32
|
+
|
33
|
+
def base_path
|
34
|
+
"#{group_id.gsub('.', '/')}/#{artifact_id.gsub('.', '/')}/#{version}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def jar_name
|
38
|
+
"#{artifact_id}-#{version}.jar"
|
39
|
+
end
|
40
|
+
|
41
|
+
def jar_path
|
42
|
+
"#{base_path}/#{jar_name}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def snapshot?
|
46
|
+
version.downcase =~ /snapshot/
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class Maven::Repository
|
52
|
+
attr_reader :snapshots_url
|
53
|
+
attr_reader :releases_url
|
54
|
+
|
55
|
+
def initialize(repositories)
|
56
|
+
required(repositories, "repositories configuration required")
|
57
|
+
required(repositories['snapshots'], "snapshots repository required")
|
58
|
+
required(repositories['releases'], "releases repository required")
|
59
|
+
|
60
|
+
@snapshots_url = repositories['snapshots']
|
61
|
+
@releases_url = repositories['releases']
|
62
|
+
end
|
63
|
+
|
64
|
+
def absolute_url(artifact)
|
65
|
+
if artifact.snapshot?
|
66
|
+
doc = Nokogiri::XML(open(URI.parse("#{snapshots_url}/#{artifact.base_path}/maven-metadata.xml"), :http_basic_authentication => authentication(false)))
|
67
|
+
snapshot_version = doc.xpath("//metadata/versioning/snapshotVersions/snapshotVersion/value/text()").first.content
|
68
|
+
return "#{snapshots_url}/#{artifact.base_path}/#{artifact.artifact_id}-#{snapshot_version}.jar"
|
69
|
+
end
|
70
|
+
|
71
|
+
"#{releases_url}/#{artifact.jar_path}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def authentication(snapshots = false)
|
75
|
+
@settings_file ||= ENV['M2_HOME'] ? "#{ENV['M2_HOME']}/conf/settings.xml" : "#{ENV['HOME']}/.m2/settings.xml"
|
76
|
+
|
77
|
+
if File.exists?(@settings_file)
|
78
|
+
Nokogiri::XML(open(@settings_file)).css("settings servers server").each do |n|
|
79
|
+
return "#{n.css("username").text}:#{n.css("password").text}" if n.css("id").text == (snapshots ? 'snapshots' : 'releases')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
""
|
83
|
+
end
|
84
|
+
|
85
|
+
def required(exp, message)
|
86
|
+
raise StandardError.new(message) unless exp
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Deployer strategy for maven repos (wip).
|
93
|
+
#
|
94
|
+
class Maven::Deployer
|
95
|
+
|
96
|
+
attr_reader :environment, :artifacts, :repository
|
97
|
+
|
98
|
+
def initialize(env, opts = {})
|
99
|
+
@environment = env
|
100
|
+
# TODO: nil-object instead?
|
101
|
+
@artifacts = env.maven? ? env.maven.artifacts : {}
|
102
|
+
@repository = env.maven? ? env.maven.repository : nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def deploy
|
106
|
+
artifacts.each do |name, artifact|
|
107
|
+
environment.hosts.each do |host|
|
108
|
+
mark_previous(name, host)
|
109
|
+
pull_artifact(name, artifact, host)
|
110
|
+
mark_new(name, artifact, host)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
true # false if failed
|
114
|
+
end
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
def pull_artifact(name, artifact, host)
|
119
|
+
Net::SSH.start(host, environment.user) do |ssh|
|
120
|
+
puts "Pulling #{repository.absolute_url(artifact)} to #{host}:#{environment.path_prefix}/#{artifact.jar_name}..."
|
121
|
+
ssh.exec("curl --user '#{repository.authentication(artifact.snapshot?)}' #{repository.absolute_url(artifact)} > #{environment.path_prefix}/#{artifact.jar_name}")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def mark_previous(name, host)
|
126
|
+
Net::SSH.start(host, user) do |ssh|
|
127
|
+
puts "Marking previous release on #{host}..."
|
128
|
+
ssh.exec("cp -P #{environment.path_prefix}/#{name}.jar #{environment.path_prefix}/#{name}.previous.jar")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def mark_new(name, artifact, host)
|
133
|
+
Net::SSH.start(host, user) do |ssh|
|
134
|
+
cwd = deploy_path(app_name)
|
135
|
+
puts "Marking #{artifact.jar_name} as current on #{host}..."
|
136
|
+
ssh.exec("ln -sf #{environment.path_prefix}/#{artifact.jar_name} #{environment.path_prefix}/#{name}.jar")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
##
|
142
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'net/scp'
|
3
|
+
|
4
|
+
module Pushwagner
|
5
|
+
module Static
|
6
|
+
class Deployer
|
7
|
+
attr_reader :environment
|
8
|
+
|
9
|
+
def initialize(environment, opts = {})
|
10
|
+
@environment = environment
|
11
|
+
end
|
12
|
+
|
13
|
+
def deploy
|
14
|
+
environment.static.each do |name, files|
|
15
|
+
environment.hosts.each do |host|
|
16
|
+
Net::SCP.start(host, environment.user) do |scp|
|
17
|
+
puts "Uploading files to #{host}:#{environment.path_prefix}/#{name}/"
|
18
|
+
files.each do |f|
|
19
|
+
if File.exists?(f)
|
20
|
+
scp.upload!(f, "#{environment.path_prefix}/#{name}/", :recursive => File.directory?(f))
|
21
|
+
else
|
22
|
+
puts "Warning: File #{f} does not exist"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# EOC
|
30
|
+
end
|
31
|
+
# EOM
|
32
|
+
end
|
33
|
+
end
|
data/lib/pushwagner.rb
ADDED
data/pushwagner.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
2
|
+
require 'pushwagner/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'pushwagner'
|
6
|
+
s.version = Pushwagner::VERSION
|
7
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
8
|
+
|
9
|
+
s.description = "Simple remote automation wrapper."
|
10
|
+
s.summary = "Simple remote automation wrapper (wip)."
|
11
|
+
|
12
|
+
s.authors = ["Ole Christian Rynning"]
|
13
|
+
s.email = 'oc@rynning.no'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files spec`.split("\n")
|
17
|
+
s.licenses = ['MIT']
|
18
|
+
s.homepage = 'http://rubygems.org/gems/pushwagner'
|
19
|
+
s.executables = ['pw']
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
|
22
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
|
23
|
+
|
24
|
+
s.add_runtime_dependency 'net-ssh'
|
25
|
+
s.add_runtime_dependency 'net-scp'
|
26
|
+
s.add_runtime_dependency 'nokogiri', '~> 1.5'
|
27
|
+
|
28
|
+
s.add_development_dependency 'bundler', '~> 1.0'
|
29
|
+
s.add_development_dependency 'rake', '~> 0.9'
|
30
|
+
s.add_development_dependency 'rspec', '~> 2.11'
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# empty.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
path_prefix: /full/path
|
2
|
+
|
3
|
+
maven:
|
4
|
+
repositories:
|
5
|
+
releases: http://foo.mu/nexus/content/repositories/releases
|
6
|
+
snapshots: http://foo.mu/nexus/content/repositories/snapshots
|
7
|
+
artifacts:
|
8
|
+
bubble-api:
|
9
|
+
group_id: double
|
10
|
+
artifact_id: trouble-api
|
11
|
+
bubble-notifier:
|
12
|
+
group_id: double
|
13
|
+
artifact_id: trouble-notifier
|
14
|
+
|
15
|
+
static:
|
16
|
+
diakonhjemmet.uppercase.no:
|
17
|
+
- index.htm
|
18
|
+
- static
|
19
|
+
|
20
|
+
environments:
|
21
|
+
staging:
|
22
|
+
hosts: [staging.uppercase.no]
|
23
|
+
user: www-data
|
24
|
+
production:
|
25
|
+
hosts: [prod1.uppercase.no]
|
26
|
+
user: www-data
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<metadata modelVersion="1.1.0">
|
2
|
+
<groupId>bar</groupId>
|
3
|
+
<artifactId>foo</artifactId>
|
4
|
+
<version>1.0-SNAPSHOT</version>
|
5
|
+
<versioning>
|
6
|
+
<snapshot>
|
7
|
+
<timestamp>20121114.152717</timestamp>
|
8
|
+
<buildNumber>3</buildNumber>
|
9
|
+
</snapshot>
|
10
|
+
<lastUpdated>20121114152717</lastUpdated>
|
11
|
+
<snapshotVersions>
|
12
|
+
<snapshotVersion>
|
13
|
+
<extension>jar</extension>
|
14
|
+
<value>1.0-20121114.152717-3</value>
|
15
|
+
<updated>20121114152717</updated>
|
16
|
+
</snapshotVersion>
|
17
|
+
<snapshotVersion>
|
18
|
+
<extension>pom</extension>
|
19
|
+
<value>1.0-20121114.152717-3</value>
|
20
|
+
<updated>20121114152717</updated>
|
21
|
+
</snapshotVersion>
|
22
|
+
</snapshotVersions>
|
23
|
+
</versioning>
|
24
|
+
</metadata>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
path_prefix: /var/www
|
2
|
+
|
3
|
+
maven:
|
4
|
+
repositories:
|
5
|
+
releases: http://w00t.uppercase.no/nexus/content/repositories/releases
|
6
|
+
snapshots: http://w00t.uppercase.no/nexus/content/repositories/snapshots
|
7
|
+
artifacts:
|
8
|
+
some-api:
|
9
|
+
group_id: uppercase
|
10
|
+
artifact_id: uc-api
|
11
|
+
some-notifier:
|
12
|
+
group_id: uppercase
|
13
|
+
artifact_id: uc-notifier
|
14
|
+
version: 1.0final
|
15
|
+
|
16
|
+
environments:
|
17
|
+
simple:
|
18
|
+
hosts: [simple.uppercase.no]
|
19
|
+
user: www-data
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'pushwagner/environment'
|
3
|
+
|
4
|
+
describe Pushwagner::Environment do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "requires config_file" do
|
7
|
+
expect { Pushwagner::Environment.new('config_file' => File.join(config_root, 'nonexisting.yml'))}.to raise_error
|
8
|
+
end
|
9
|
+
|
10
|
+
it "supports config_file" do
|
11
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'full.yml'))
|
12
|
+
expect(env.path_prefix).to eq("/full/path")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "supports :config_file" do
|
16
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'static.yml'))
|
17
|
+
expect(env.path_prefix).to eq("/static/path")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "supports :version" do
|
21
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'full.yml'), :version => "1.3.3.7")
|
22
|
+
expect(env.version).to eq("1.3.3.7")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
describe "#maven" do
|
26
|
+
it "requires a version" do
|
27
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'maven.yml'))
|
28
|
+
expect { env.maven }.to raise_error(StandardError, "Deployment version for artifacts is required")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns empty hash when not configured" do
|
32
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'static.yml'), :version => "1foo" )
|
33
|
+
expect(env.maven?).to be_false
|
34
|
+
expect(env.maven).to eq({})
|
35
|
+
end
|
36
|
+
end
|
37
|
+
describe "#static" do
|
38
|
+
it "returns empty hash when not configured" do
|
39
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'maven.yml'), :version => "1foo" )
|
40
|
+
expect(env.static?).to be_false
|
41
|
+
expect(env.static).to eq({})
|
42
|
+
end
|
43
|
+
it "is a hash with files" do
|
44
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'static.yml'))
|
45
|
+
expect(env.static).to eq({'diakonhjemmet.uppercase.no' => ['index.htm', 'static']})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
describe "#environments" do
|
49
|
+
it "returns all environments" do
|
50
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'full.yml'), :version => "1foo" )
|
51
|
+
expect(env.environments.size).to eq(2)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
describe "#environment" do
|
55
|
+
it "returns empty environment if it doesn't exist" do
|
56
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'full.yml'), :version => "1foo" )
|
57
|
+
expect(env.environment).to eq({})
|
58
|
+
end
|
59
|
+
it "returns environment if it exists" do
|
60
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'full.yml'), :version => "1foo", :environment => "staging")
|
61
|
+
expect(env.environment).to eq({'hosts' => ["staging.uppercase.no"], 'user' => "www-data"})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe "#hosts" do
|
65
|
+
it "returns empty list if it doesn't exist" do
|
66
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'empty.yml'), :version => "1foo" )
|
67
|
+
expect(env.hosts).to eq([])
|
68
|
+
end
|
69
|
+
it "returns environment if it exists" do
|
70
|
+
env = Pushwagner::Environment.new(:config_file => File.join(config_root, 'full.yml'), :version => "1foo", :environment => "staging")
|
71
|
+
expect(env.environment).to eq({'hosts' => ["staging.uppercase.no"], 'user' => "www-data"})
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/maven_spec.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'pushwagner/environment'
|
3
|
+
|
4
|
+
describe Pushwagner::Maven do
|
5
|
+
let(:cfg) {YAML::load_file(File.join(config_root, 'maven.yml'))['maven']}
|
6
|
+
|
7
|
+
describe "#initialize" do
|
8
|
+
it "requires a version" do
|
9
|
+
expect { Pushwagner::Maven.new(cfg, nil) }.to raise_error(StandardError, "Deployment version for artifacts is required")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "trickles the version down to artifacts" do
|
13
|
+
m = Pushwagner::Maven.new(cfg, "1foo")
|
14
|
+
expect(m.artifacts["some-api"].version).to eq("1foo")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "allows stable versions on artifacts" do
|
18
|
+
m = Pushwagner::Maven.new(cfg, "1bar")
|
19
|
+
expect(m.artifacts["some-notifier"].version).to eq("1.0final")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns nil-object maven when not configured" do
|
23
|
+
m = Pushwagner::Maven.new({}, "1baz")
|
24
|
+
expect(m.artifacts).to be_nil
|
25
|
+
expect(m).to_not be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "initialization of artifacts" do
|
29
|
+
it "handles no artifacts" do
|
30
|
+
cfg.delete('artifacts')
|
31
|
+
m = Pushwagner::Maven.new(cfg, "1bar")
|
32
|
+
expect(m.artifacts.size).to eq(0)
|
33
|
+
end
|
34
|
+
it "parses two artifacts" do
|
35
|
+
m = Pushwagner::Maven.new(cfg, "1bar")
|
36
|
+
expect(m.artifacts.size).to eq(2)
|
37
|
+
expect(m.artifacts.keys.first).to eq("some-api")
|
38
|
+
expect(m.artifacts.keys.last).to eq("some-notifier")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "initialization of repositories" do
|
43
|
+
it "requires snapshots repository" do
|
44
|
+
cfg.delete('repositories')
|
45
|
+
expect {Pushwagner::Maven.new(cfg, "1")}.to raise_error(StandardError)
|
46
|
+
end
|
47
|
+
it "requires snapshots repository" do
|
48
|
+
cfg['repositories'].delete('snapshots')
|
49
|
+
expect {Pushwagner::Maven.new(cfg, "1")}.to raise_error(StandardError)
|
50
|
+
end
|
51
|
+
it "requires releases repository" do
|
52
|
+
cfg['repositories'].delete('releases')
|
53
|
+
expect {Pushwagner::Maven.new(cfg, "1")}.to raise_error(StandardError)
|
54
|
+
end
|
55
|
+
it "parses repository" do
|
56
|
+
m = Pushwagner::Maven.new(cfg, "1")
|
57
|
+
expect(m.repository.snapshots_url).to eq("http://w00t.uppercase.no/nexus/content/repositories/snapshots")
|
58
|
+
expect(m.repository.releases_url).to eq("http://w00t.uppercase.no/nexus/content/repositories/releases")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "repositories" do
|
64
|
+
let(:settings) {IO.read(File.join(config_root, 'settings.xml'))}
|
65
|
+
|
66
|
+
it "reads releases authentication from maven settings.xml" do
|
67
|
+
m = Pushwagner::Maven.new(cfg, "1")
|
68
|
+
m.repository.should_receive(:open).
|
69
|
+
with(/.*settings.xml$/).
|
70
|
+
and_return(settings)
|
71
|
+
|
72
|
+
expect(m.repository.authentication).to eq("foo:bar")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "reads snapshots authentication from maven settings.xml" do
|
76
|
+
m = Pushwagner::Maven.new(cfg, "1")
|
77
|
+
m.repository.should_receive(:open).
|
78
|
+
with(/.*settings.xml$/).
|
79
|
+
and_return(settings)
|
80
|
+
|
81
|
+
expect(m.repository.authentication(true)).to eq("bar:baz")
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:metadata) {IO.read(File.join(config_root, 'maven-metadata.xml'))}
|
85
|
+
|
86
|
+
it "builds maven2-repo-style urls and retrieves metadata" do
|
87
|
+
m = Pushwagner::Maven.new(cfg, "1")
|
88
|
+
|
89
|
+
m.repository.should_receive(:authentication).and_return("")
|
90
|
+
m.repository.should_receive(:open).and_return(metadata)
|
91
|
+
|
92
|
+
snapshot = Pushwagner::Maven::Artifact.new("foo", "bar", "1.0-SNAPSHOT")
|
93
|
+
expect(m.repository.absolute_url(snapshot)).to eq("http://w00t.uppercase.no/nexus/content/repositories/snapshots/bar/foo/1.0-SNAPSHOT/foo-1.0-20121114.152717-3.jar")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "builds maven2-repo-style urls for release artifacts" do
|
97
|
+
m = Pushwagner::Maven.new(cfg, "1")
|
98
|
+
release = Pushwagner::Maven::Artifact.new("foo", "bar", "1.0")
|
99
|
+
expect(m.repository.absolute_url(release)).to eq("http://w00t.uppercase.no/nexus/content/repositories/releases/bar/foo/1.0/foo-1.0.jar")
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
require 'pushwagner'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
require 'rspec'
|
6
|
+
require 'diff/lcs'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.before do
|
10
|
+
ARGV.replace []
|
11
|
+
end
|
12
|
+
|
13
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
14
|
+
|
15
|
+
def config_root
|
16
|
+
File.join(File.dirname(__FILE__), 'configs')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pushwagner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ole Christian Rynning
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: net-ssh
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: net-scp
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.5'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bundler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0.9'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.9'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '2.11'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.11'
|
110
|
+
description: Simple remote automation wrapper.
|
111
|
+
email: oc@rynning.no
|
112
|
+
executables:
|
113
|
+
- pw
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- .rvmrc
|
119
|
+
- Gemfile
|
120
|
+
- Gemfile.lock
|
121
|
+
- Rakefile
|
122
|
+
- bin/pw
|
123
|
+
- lib/pushwagner.rb
|
124
|
+
- lib/pushwagner/environment.rb
|
125
|
+
- lib/pushwagner/ext.rb
|
126
|
+
- lib/pushwagner/main.rb
|
127
|
+
- lib/pushwagner/maven.rb
|
128
|
+
- lib/pushwagner/static.rb
|
129
|
+
- lib/pushwagner/supervisord.rb
|
130
|
+
- lib/pushwagner/version.rb
|
131
|
+
- pushwagner.gemspec
|
132
|
+
- spec/configs/empty.yml
|
133
|
+
- spec/configs/full.yml
|
134
|
+
- spec/configs/maven-metadata.xml
|
135
|
+
- spec/configs/maven.yml
|
136
|
+
- spec/configs/settings.xml
|
137
|
+
- spec/configs/static.yml
|
138
|
+
- spec/environment_spec.rb
|
139
|
+
- spec/maven_spec.rb
|
140
|
+
- spec/spec_helper.rb
|
141
|
+
homepage: http://rubygems.org/gems/pushwagner
|
142
|
+
licenses:
|
143
|
+
- MIT
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 1.3.6
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 1.8.24
|
163
|
+
signing_key:
|
164
|
+
specification_version: 3
|
165
|
+
summary: Simple remote automation wrapper (wip).
|
166
|
+
test_files:
|
167
|
+
- spec/configs/empty.yml
|
168
|
+
- spec/configs/full.yml
|
169
|
+
- spec/configs/maven-metadata.xml
|
170
|
+
- spec/configs/maven.yml
|
171
|
+
- spec/configs/settings.xml
|
172
|
+
- spec/configs/static.yml
|
173
|
+
- spec/environment_spec.rb
|
174
|
+
- spec/maven_spec.rb
|
175
|
+
- spec/spec_helper.rb
|