pushwagner 0.0.1
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/.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
|