sbci 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/Guardfile +19 -0
- data/LICENSE +22 -0
- data/README.md +28 -0
- data/Rakefile +2 -0
- data/bin/sbci +51 -0
- data/lib/config.xml +103 -0
- data/lib/sbci.rb +145 -0
- data/lib/sbci/version.rb +3 -0
- data/sbci.gemspec +29 -0
- data/spec/.DS_Store +0 -0
- data/spec/fixtures/vcr_cassettes/delete.yml +42 -0
- data/spec/fixtures/vcr_cassettes/dump.yml +78 -0
- data/spec/fixtures/vcr_cassettes/publish.yml +160 -0
- data/spec/fixtures/vcr_cassettes/republish.yml +232 -0
- data/spec/sbci_cli_spec.rb +21 -0
- data/spec/sbci_spec.rb +151 -0
- data/spec/spec_helper.rb +12 -0
- metadata +190 -0
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
.jenkins/
|
7
|
+
spec/fixtures/.jenkins
|
8
|
+
spec/fixtures/jenkins
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
21
|
+
/vendor/bundle
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
# Capybara request specs
|
17
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
18
|
+
end
|
19
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Egils Muzis
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# SBCI - Simply Business Continuous Integration
|
2
|
+
|
3
|
+
This command-line utility provides an easy way for Jenkins job configuration to be exported to disk.
|
4
|
+
Great for backup purposes and later restoring to the same or other Jenkins instances.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
### Through RVM global gemset (recommended)
|
9
|
+
|
10
|
+
rvm use gemset global
|
11
|
+
gem install sbci
|
12
|
+
|
13
|
+
### Or per project basis only - Gemfile
|
14
|
+
|
15
|
+
gem 'sbci'
|
16
|
+
|
17
|
+
## Example Usage
|
18
|
+
|
19
|
+
We recommend that you create a .jenkins directory checked into your project git repo to keep a backup of your Jenkins job configuration.
|
20
|
+
|
21
|
+
### Exporting / Backing up a job from your Jenkins server
|
22
|
+
sbci dump --host localhost --port 8080 --job-name development --path .jenkins
|
23
|
+
|
24
|
+
### Restoring / Updating a job from your backup
|
25
|
+
sbci publish --host localhost --port 8080 --job-name development --path .jenkins
|
26
|
+
|
27
|
+
### To view other commands
|
28
|
+
sbci --help
|
data/Rakefile
ADDED
data/bin/sbci
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
3
|
+
|
4
|
+
require 'trollop'
|
5
|
+
require 'sbci'
|
6
|
+
|
7
|
+
COMMANDS = %w(create dump publish delete)
|
8
|
+
|
9
|
+
opts = Trollop::options do
|
10
|
+
banner <<-EOS
|
11
|
+
Usage:
|
12
|
+
|
13
|
+
* Create a new configuration xml template file:
|
14
|
+
|
15
|
+
sbci create --job-name development --path .jenkins
|
16
|
+
|
17
|
+
* Dump a configuration xml from an existing project:
|
18
|
+
|
19
|
+
sbci dump --host localhost --port 8080 --job-name development --path .jenkins
|
20
|
+
|
21
|
+
* Publish a configuration xml to create a new Jenkins job:
|
22
|
+
|
23
|
+
sbci publish --host localhost --port 8080 --job-name development --path .jenkins
|
24
|
+
|
25
|
+
* Delete a Jenkins job:
|
26
|
+
|
27
|
+
sbci delete --host localhost --port 8080 --job-name development
|
28
|
+
|
29
|
+
* Force overwriting without getting prompt (e.g. create, publish, dump)
|
30
|
+
|
31
|
+
sbci dump --host localhost --port 8080 --job-name development --path .jenkins --force true
|
32
|
+
|
33
|
+
where [options] are:
|
34
|
+
|
35
|
+
EOS
|
36
|
+
opt :host, "Hostname", :type => String
|
37
|
+
opt :port, "Port number", :type => :int
|
38
|
+
opt :job_name, "Name of the Jenkins job", :type => String
|
39
|
+
opt :path, "Relative path", :type => String
|
40
|
+
opt :force, "Force overwriting"
|
41
|
+
end
|
42
|
+
|
43
|
+
cmd = ARGV.shift
|
44
|
+
|
45
|
+
if cmd == "debug"
|
46
|
+
puts YAML::dump(SBCI::Job.new(opts))
|
47
|
+
elsif COMMANDS.include?(cmd)
|
48
|
+
SBCI::Job.new(opts).send(cmd)
|
49
|
+
else
|
50
|
+
puts "Please enter a valid task name"
|
51
|
+
end
|
data/lib/config.xml
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
2
|
+
<project>
|
3
|
+
<actions/>
|
4
|
+
<description>_PROJECT_NAME_</description>
|
5
|
+
<logRotator>
|
6
|
+
<daysToKeep>1</daysToKeep>
|
7
|
+
<numToKeep>5</numToKeep>
|
8
|
+
<artifactDaysToKeep>-1</artifactDaysToKeep>
|
9
|
+
<artifactNumToKeep>-1</artifactNumToKeep>
|
10
|
+
</logRotator>
|
11
|
+
<keepDependencies>false</keepDependencies>
|
12
|
+
<properties>
|
13
|
+
<com.coravy.hudson.plugins.github.GithubProjectProperty>
|
14
|
+
<projectUrl>_PROJECT_URL_</projectUrl>
|
15
|
+
</com.coravy.hudson.plugins.github.GithubProjectProperty>
|
16
|
+
</properties>
|
17
|
+
<scm class="hudson.plugins.git.GitSCM">
|
18
|
+
<configVersion>2</configVersion>
|
19
|
+
<userRemoteConfigs>
|
20
|
+
<hudson.plugins.git.UserRemoteConfig>
|
21
|
+
<name></name>
|
22
|
+
<refspec></refspec>
|
23
|
+
<url>_GIT_REPO_</url>
|
24
|
+
</hudson.plugins.git.UserRemoteConfig>
|
25
|
+
</userRemoteConfigs>
|
26
|
+
<branches>
|
27
|
+
<hudson.plugins.git.BranchSpec>
|
28
|
+
<name>_BRANCH_NAME_</name>
|
29
|
+
</hudson.plugins.git.BranchSpec>
|
30
|
+
</branches>
|
31
|
+
<disableSubmodules>false</disableSubmodules>
|
32
|
+
<recursiveSubmodules>false</recursiveSubmodules>
|
33
|
+
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
|
34
|
+
<authorOrCommitter>false</authorOrCommitter>
|
35
|
+
<clean>false</clean>
|
36
|
+
<wipeOutWorkspace>false</wipeOutWorkspace>
|
37
|
+
<pruneBranches>false</pruneBranches>
|
38
|
+
<remotePoll>false</remotePoll>
|
39
|
+
<ignoreNotifyCommit>false</ignoreNotifyCommit>
|
40
|
+
<buildChooser class="hudson.plugins.git.util.DefaultBuildChooser"/>
|
41
|
+
<gitTool>Default</gitTool>
|
42
|
+
<submoduleCfg class="list"/>
|
43
|
+
<relativeTargetDir></relativeTargetDir>
|
44
|
+
<reference></reference>
|
45
|
+
<excludedRegions></excludedRegions>
|
46
|
+
<excludedUsers></excludedUsers>
|
47
|
+
<gitConfigName></gitConfigName>
|
48
|
+
<gitConfigEmail></gitConfigEmail>
|
49
|
+
<skipTag>false</skipTag>
|
50
|
+
<includedRegions></includedRegions>
|
51
|
+
<scmName></scmName>
|
52
|
+
</scm>
|
53
|
+
<canRoam>true</canRoam>
|
54
|
+
<disabled>false</disabled>
|
55
|
+
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
56
|
+
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
57
|
+
<triggers class="vector">
|
58
|
+
<com.cloudbees.jenkins.GitHubPushTrigger>
|
59
|
+
<spec></spec>
|
60
|
+
</com.cloudbees.jenkins.GitHubPushTrigger>
|
61
|
+
<hudson.triggers.SCMTrigger>
|
62
|
+
<spec>* * * * *</spec>
|
63
|
+
</hudson.triggers.SCMTrigger>
|
64
|
+
</triggers>
|
65
|
+
<concurrentBuild>false</concurrentBuild>
|
66
|
+
<builders>
|
67
|
+
<hudson.tasks.Shell>
|
68
|
+
<command>rvm --force gemset empty _PROJECT_NAME_ && bundle install</command>
|
69
|
+
</hudson.tasks.Shell>
|
70
|
+
<hudson.tasks.Shell>
|
71
|
+
<command>bundle exec rspec spec --format html -o doc/rspec.html</command>
|
72
|
+
</hudson.tasks.Shell>
|
73
|
+
</builders>
|
74
|
+
<publishers>
|
75
|
+
<hudson.tasks.ArtifactArchiver>
|
76
|
+
<artifacts>doc/*html</artifacts>
|
77
|
+
<latestOnly>false</latestOnly>
|
78
|
+
</hudson.tasks.ArtifactArchiver>
|
79
|
+
<htmlpublisher.HtmlPublisher>
|
80
|
+
<reportTargets>
|
81
|
+
<htmlpublisher.HtmlPublisherTarget>
|
82
|
+
<reportName>Rspec Report</reportName>
|
83
|
+
<reportDir>doc</reportDir>
|
84
|
+
<reportFiles>rspec.html</reportFiles>
|
85
|
+
<keepAll>true</keepAll>
|
86
|
+
<wrapperName>htmlpublisher-wrapper.html</wrapperName>
|
87
|
+
</htmlpublisher.HtmlPublisherTarget>
|
88
|
+
</reportTargets>
|
89
|
+
</htmlpublisher.HtmlPublisher>
|
90
|
+
<hudson.plugins.claim.ClaimPublisher/>
|
91
|
+
</publishers>
|
92
|
+
<buildWrappers>
|
93
|
+
<hudson.plugins.ansicolor.AnsiColorBuildWrapper/>
|
94
|
+
<ruby-proxy-object>
|
95
|
+
<ruby-object ruby-class="Jenkins::Plugin::Proxies::BuildWrapper" pluginid="rvm">
|
96
|
+
<object ruby-class="RvmWrapper" pluginid="rvm">
|
97
|
+
<impl pluginid="rvm" ruby-class="String">1.9.2-p290@_PROJECT_NAME_</impl>
|
98
|
+
</object>
|
99
|
+
<pluginid pluginid="rvm" ruby-class="String">rvm</pluginid>
|
100
|
+
</ruby-object>
|
101
|
+
</ruby-proxy-object>
|
102
|
+
</buildWrappers>
|
103
|
+
</project>
|
data/lib/sbci.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "rest_client"
|
3
|
+
require "grit"
|
4
|
+
require "uri"
|
5
|
+
require "rubygems"
|
6
|
+
require "sbci/version"
|
7
|
+
require "yaml"
|
8
|
+
|
9
|
+
module SBCI
|
10
|
+
|
11
|
+
INITIAL_CONFIG_PATH = "#{File.expand_path("../..",__FILE__)}/lib/config.xml"
|
12
|
+
MESSAGES = {
|
13
|
+
:config_dir_exists => "Config already exists for this project",
|
14
|
+
:config_already_exists => "Config file already exists and will be overwritten",
|
15
|
+
:config_already_published => "Config file is already published and will be overwritten"
|
16
|
+
}
|
17
|
+
|
18
|
+
def self.pwd
|
19
|
+
@pwd = Dir.pwd
|
20
|
+
end
|
21
|
+
|
22
|
+
class Job
|
23
|
+
|
24
|
+
def self.repo_name
|
25
|
+
conf = Grit::Config.new(get_repo)
|
26
|
+
conf["remote.origin.url"].gsub(/\.git$/,"").split("/").last
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.branch_name
|
30
|
+
Grit::Head.current(get_repo).name
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.get_repo
|
34
|
+
Grit::Repo.new(".")
|
35
|
+
end
|
36
|
+
|
37
|
+
ATTRIBUTES = [
|
38
|
+
:host, :port, :branch_name, :job_name, :path, :force
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
DEFAULTS = {
|
42
|
+
:host => "localhost",
|
43
|
+
:port => 8080,
|
44
|
+
:path => "",
|
45
|
+
:job_name => self.repo_name,
|
46
|
+
:force => false
|
47
|
+
}
|
48
|
+
|
49
|
+
ATTRIBUTES.each do |attr|
|
50
|
+
attr_accessor attr
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize(args = nil)
|
54
|
+
args.delete_if{ |k,v| v.nil? || v == ""} if args.is_a?(Hash)
|
55
|
+
args = args ? DEFAULTS.merge(args) : DEFAULTS
|
56
|
+
|
57
|
+
ATTRIBUTES.each do |attr|
|
58
|
+
if (args.key?(attr))
|
59
|
+
instance_variable_set("@#{attr}", args[attr])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create
|
65
|
+
prompt(SBCI::MESSAGES[:config_already_exists], config_exists?) do
|
66
|
+
FileUtils.cp(SBCI::INITIAL_CONFIG_PATH, config_file_path)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def publish
|
71
|
+
already_published = published?
|
72
|
+
url = if already_published
|
73
|
+
"#{host_with_port}/job/#{job_name}/config.xml"
|
74
|
+
else
|
75
|
+
"#{host_with_port}/createItem?name=#{job_name}"
|
76
|
+
end
|
77
|
+
prompt(SBCI::MESSAGES[:config_already_published], already_published) do
|
78
|
+
RestClient.post(URI.escape(url), File.read(config_file_path), :content_type => :xml)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def published?
|
83
|
+
begin
|
84
|
+
RestClient.get(URI.escape("#{host_with_port}/job/#{self.job_name}/config.xml"))
|
85
|
+
rescue
|
86
|
+
false
|
87
|
+
else
|
88
|
+
true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def dump
|
93
|
+
prompt(SBCI::MESSAGES[:config_already_exists], config_exists?) do
|
94
|
+
response = RestClient.get(URI.escape("#{host_with_port}/job/#{self.job_name}/config.xml"))
|
95
|
+
File.open(config_file_path, "w") {|f| f.write(response.body) }
|
96
|
+
response
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def delete
|
101
|
+
begin
|
102
|
+
RestClient.post(URI.escape("#{host_with_port}/job/#{self.job_name}/doDelete"), {})
|
103
|
+
rescue RestClient::Found
|
104
|
+
true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def config_file_path
|
109
|
+
File.join(config_file_dir, "#{self.job_name}.xml")
|
110
|
+
end
|
111
|
+
|
112
|
+
def config_file_dir
|
113
|
+
file_dir = File.join(SBCI.pwd, self.path)
|
114
|
+
FileUtils.mkdir_p(file_dir)
|
115
|
+
file_dir
|
116
|
+
end
|
117
|
+
|
118
|
+
def config_exists?
|
119
|
+
File.exists?(config_file_path)
|
120
|
+
end
|
121
|
+
|
122
|
+
def host_with_port
|
123
|
+
"#{host}:#{port}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def delete_config
|
127
|
+
FileUtils.rm(config_file_path) if File.exists?(config_file_path)
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def prompt(message, condition = true, &block)
|
133
|
+
if !self.force && condition
|
134
|
+
message << "\nDo you want to continue [Y/n] ? "
|
135
|
+
print(message)
|
136
|
+
answer = gets
|
137
|
+
yield if answer.strip.downcase == "y"
|
138
|
+
else
|
139
|
+
yield
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
data/lib/sbci/version.rb
ADDED
data/sbci.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sbci/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.authors = ["Egils Muzis"]
|
6
|
+
s.email = ["egils.muzis@xbridge.com"]
|
7
|
+
s.description = "Utility to easily export or import and Jenkins job configuration"
|
8
|
+
s.summary = "Manage your Jenkins jobs through this easy to use command-line interface"
|
9
|
+
s.homepage = "https://github.com/simplybusiness/sbci"
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split($\)
|
12
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
14
|
+
s.name = "sbci"
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.version = SBCI::VERSION
|
17
|
+
|
18
|
+
s.add_dependency "rest-client"
|
19
|
+
s.add_dependency "grit"
|
20
|
+
s.add_dependency "trollop"
|
21
|
+
|
22
|
+
s.add_development_dependency "bahia"
|
23
|
+
s.add_development_dependency "guard"
|
24
|
+
s.add_development_dependency "guard-rspec"
|
25
|
+
s.add_development_dependency "growl"
|
26
|
+
s.add_development_dependency "rspec"
|
27
|
+
s.add_development_dependency "vcr"
|
28
|
+
s.add_development_dependency "webmock"
|
29
|
+
end
|
data/spec/.DS_Store
ADDED
Binary file
|
@@ -0,0 +1,42 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: http://localhost:8080/job/test_job/doDelete
|
6
|
+
body:
|
7
|
+
encoding: ASCII-8BIT
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*; q=0.5, application/xml'
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip, deflate
|
14
|
+
Content-Length:
|
15
|
+
- '0'
|
16
|
+
Content-Type:
|
17
|
+
- application/x-www-form-urlencoded
|
18
|
+
User-Agent:
|
19
|
+
- Ruby
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 302
|
23
|
+
message: Found
|
24
|
+
headers:
|
25
|
+
Server:
|
26
|
+
- Winstone Servlet Engine v0.9.10
|
27
|
+
Location:
|
28
|
+
- http://localhost:8080/
|
29
|
+
Content-Length:
|
30
|
+
- '0'
|
31
|
+
Connection:
|
32
|
+
- Keep-Alive
|
33
|
+
Date:
|
34
|
+
- Mon, 02 Jul 2012 11:49:49 GMT
|
35
|
+
X-Powered-By:
|
36
|
+
- Servlet/2.5 (Winstone/0.9.10)
|
37
|
+
body:
|
38
|
+
encoding: US-ASCII
|
39
|
+
string: ''
|
40
|
+
http_version: !!null
|
41
|
+
recorded_at: Mon, 02 Jul 2012 11:49:49 GMT
|
42
|
+
recorded_with: VCR 2.2.1
|