go_figure 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in go_figure.gemspec
4
+ gemspec
data/README.textile ADDED
@@ -0,0 +1,45 @@
1
+ h2. Go Figure Gem
2
+
3
+ This gem generates configuration for Go server - basically given a stage/pipeline
4
+ group this gem will configure for default pipeline and a simple test stage
5
+
6
+ h2. Installation
7
+
8
+ <pre>$ [sudo] gem install go_figure</pre>
9
+
10
+ h2. Usage
11
+
12
+ <pre>
13
+ require 'go_figure'
14
+ endpoint = GoFigure::GoConfigEndpoint.new(:host => 'example.com', :port => 8153)
15
+ config = endpoint.get_config
16
+ config.set_pipeline('http://github.com/user/repo.git', 'rails_working_dir')
17
+ endpoint.update_config(config)
18
+ </pre>
19
+
20
+ h2. License
21
+
22
+ Go Figure Gem is MIT Licensed
23
+
24
+ The MIT License
25
+
26
+ Copyright (c) 2012 ThoughtWorks, Inc. (http://thoughtworks.com)
27
+
28
+ Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ of this software and associated documentation files (the "Software"), to deal
30
+ in the Software without restriction, including without limitation the rights
31
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ copies of the Software, and to permit persons to whom the Software is
33
+ furnished to do so, subject to the following conditions:
34
+
35
+ The above copyright notice and this permission notice shall be included in
36
+ all copies or substantial portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
+ THE SOFTWARE.
45
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ task :test do
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/**/*test.rb']
8
+ t.verbose = true
9
+ end
10
+ end
11
+
12
+ task :default => :test
13
+
data/go_figure.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "go_figure/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "go_figure"
7
+ s.version = GoFigure::VERSION
8
+ s.authors = ["Ketan Padegaonkar"]
9
+ s.email = ["KetanPadegaonkar@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A Ruby DSL to write a configuration file for the a go server.}
12
+ s.description = %q{This provides a ruby DSL to create a configuration file for the go server (thoughtworks-studios.com/go)}
13
+
14
+ s.rubyforge_project = "go_figure"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+
22
+ # specify any dependencies here; for example:
23
+ # s.add_development_dependency "rspec"
24
+ s.add_runtime_dependency "nokogiri", "~> 1.5.0"
25
+ end
@@ -0,0 +1,32 @@
1
+ <pipelines group="defaultGroup">
2
+ <pipeline name="defaultPipeline">
3
+ <materials>
4
+ <git url="<%= @git_url %>" />
5
+ </materials>
6
+ <stage name="Units">
7
+ <jobs>
8
+ <job name="Test">
9
+ <tasks>
10
+ <exec command="bundle" workingdir="<%= @working_dir %>">
11
+ <arg>install</arg>
12
+ <arg>--local</arg>
13
+ <runif status="passed" />
14
+ </exec>
15
+ <exec command="bundle" workingdir="<%= @working_dir %>">
16
+ <arg>exec</arg>
17
+ <arg>rake</arg>
18
+ <arg>db:create</arg>
19
+ <arg>db:migrate</arg>
20
+ <runif status="passed" />
21
+ </exec>
22
+ <exec command="bundle" workingdir="<%= @working_dir %>">
23
+ <arg>exec</arg>
24
+ <arg>rake</arg>
25
+ <runif status="passed" />
26
+ </exec>
27
+ </tasks>
28
+ </job>
29
+ </jobs>
30
+ </stage>
31
+ </pipeline>
32
+ </pipelines>
@@ -0,0 +1,51 @@
1
+ require 'nokogiri'
2
+ require 'erb'
3
+
4
+ module GoFigure
5
+ class GoConfig
6
+ attr_accessor :original_md5
7
+ attr_reader :original_xml
8
+
9
+ def initialize(options = {})
10
+ @original_md5 = options[:md5]
11
+ @original_xml = options[:xml]
12
+ @doc = Nokogiri.XML(@original_xml, nil, 'utf-8')
13
+ end
14
+
15
+ def set_pipeline(git_url, working_dir)
16
+ @doc.root.xpath('pipelines').remove
17
+ agents = @doc.root.xpath('agents')
18
+
19
+ if agents.any?
20
+ agents.before(pipeline_template(git_url, working_dir))
21
+ else
22
+ @doc.root << pipeline_template(git_url, working_dir)
23
+ end
24
+
25
+ @doc = Nokogiri.XML(@doc.to_s) do |config|
26
+ config.default_xml.noblanks
27
+ end
28
+ end
29
+
30
+ def pipeline_template(git_url, working_dir)
31
+ template = ERB.new(File.read(File.expand_path('../../go-pipelines.xml.erb', __FILE__)))
32
+ template.result(PipelineConfig.new(git_url, working_dir).get_binding)
33
+ end
34
+
35
+ def xml_content
36
+ @doc.to_s
37
+ end
38
+
39
+ class PipelineConfig
40
+ def initialize(git_url, working_dir)
41
+ @git_url = git_url
42
+ @working_dir = working_dir
43
+ end
44
+
45
+ def get_binding
46
+ binding
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,43 @@
1
+ module GoFigure
2
+
3
+ class GoConfigEndpoint
4
+
5
+ DEFAULT_OPTIONS = {
6
+ :host => 'localhost',
7
+ :port => 8153
8
+ }
9
+
10
+ attr_accessor *DEFAULT_OPTIONS.keys
11
+ attr_accessor :http_fetcher
12
+
13
+ def initialize(options)
14
+ DEFAULT_OPTIONS.each do |k, v|
15
+ self.send("#{k}=", options[k] || v)
16
+ end
17
+ end
18
+
19
+ def get_config
20
+ response = http_fetcher.get(config_xml_url)
21
+ if response.status == 200
22
+ return GoConfig.new(:md5 => response['X-CRUISE-CONFIG-MD5'], :xml => response.body)
23
+ else
24
+ raise "Could not fetch the go config file"
25
+ end
26
+ end
27
+
28
+ def update_config(go_config)
29
+ http_fetcher.post(config_xml_url, :xmlFile => go_config.xml_content, :md5 => go_config.original_md5)
30
+ end
31
+
32
+ def http_fetcher
33
+ @http_fetcher || HttpFetcher.new
34
+ end
35
+
36
+ private
37
+ def config_xml_url
38
+ "http://#{host}:#{port}/go/api/admin/config.xml"
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,27 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+
4
+ module UserImport
5
+ class HttpFetcher
6
+
7
+ def fetch(url, user, pass)
8
+ url = URI.parse(url)
9
+
10
+ http = Net::HTTP.new(url.host, url.port)
11
+ http.use_ssl = url.scheme == 'https'
12
+
13
+ res = http.start do |http|
14
+ req = Net::HTTP::Get.new(url.path)
15
+ req.basic_auth user, pass
16
+ http.request(req)
17
+ end
18
+
19
+ case res
20
+ when Net::HTTPSuccess
21
+ return res.body
22
+ end
23
+ res.error!
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,3 @@
1
+ module GoFigure
2
+ VERSION = "0.0.1"
3
+ end
data/lib/go_figure.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "go_figure/version"
2
+ require "go_figure/go_config"
3
+ require "go_figure/http_fetcher"
4
+ require "go_figure/go_config_endpoint"
5
+
6
+ module GoFigure
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <cruise xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:say="com.thoughtworks.cruise.task.plugin.say" xsi:noNamespaceSchemaLocation="cruise-config.xsd" xsi:schemaLocation="com.thoughtworks.cruise.task.plugin.say bundle://1.0:1/say-config.xsd" schemaVersion="52">
3
+ <pipelines group="defaultGroup1">
4
+ <pipeline name="MyPipeline">
5
+ <materials>
6
+ <git url="git@go-saas.github.com:ThoughtWorksInc/go-saas.git" />
7
+ </materials>
8
+ <stage name="Units">
9
+ <jobs>
10
+ <job name="UnitTest">
11
+ <tasks>
12
+ <exec command="bundle" workingdir="rails">
13
+ <arg>install</arg>
14
+ <arg>--local</arg>
15
+ <runif status="passed" />
16
+ </exec>
17
+ <exec command="bundle" workingdir="rails">
18
+ <arg>exec</arg>
19
+ <arg>rake</arg>
20
+ <arg>db:create</arg>
21
+ <arg>db:migrate</arg>
22
+ <runif status="passed" />
23
+ </exec>
24
+ <rake workingdir="rails" />
25
+ </tasks>
26
+ </job>
27
+ </jobs>
28
+ </stage>
29
+ </pipeline>
30
+ </pipelines>
31
+ <agents>
32
+ <agent hostname="ika.corporate.thoughtworks.com" ipaddress="10.12.1.229" uuid="de494931-c26c-44ef-a94d-8835166a3e88" />
33
+ </agents>
34
+ </cruise>
35
+
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+
4
+ module GoFigure
5
+ class GoConfigEndpointTest < Test::Unit::TestCase
6
+
7
+ def test_should_fetch_xml_config_on_localhost
8
+ md5 = '7455edff001e2f262beb7c13f10ff7cb'
9
+ endpoint = GoConfigEndpoint.new(:host => 'example.com', :port => 1234)
10
+ endpoint.http_fetcher = fetcher_with_config_file('foo.xml', md5, config_endpoint)
11
+
12
+ config = endpoint.get_config
13
+ assert_equal config_file('foo.xml'), config.original_xml
14
+ assert_equal md5, config.original_md5
15
+ end
16
+
17
+ def test_should_post_back_new_config_xml_content_with_original_md5
18
+ md5 = '7455edff001e2f262beb7c13f10ff7cb'
19
+ endpoint = GoConfigEndpoint.new(:host => 'example.com', :port => 1234)
20
+ endpoint.http_fetcher = fetcher_with_config_file('foo.xml', md5, config_endpoint)
21
+
22
+ config = endpoint.get_config
23
+ config.set_pipeline("http://git.example.com/foo/bar.git", "my_rails_app")
24
+
25
+ endpoint.http_fetcher.register_content("OK", config_endpoint, :post, :md5 => config.original_md5, :xmlFile => config.xml_content)
26
+
27
+ endpoint.update_config(config)
28
+ assert endpoint.http_fetcher.invoked?(config_endpoint, :post, :md5 => config.original_md5, :xmlFile => config.xml_content)
29
+ end
30
+
31
+ def config_endpoint
32
+ "http://example.com:1234/go/api/admin/config.xml"
33
+ end
34
+
35
+ def fetcher_with_config_file(file_name, md5, url)
36
+ endpoint = StubHttpFetcher.new
37
+ endpoint.register_content(config_file(file_name), config_endpoint, :get, 'X-CRUISE-CONFIG-MD5' => md5)
38
+ endpoint
39
+ end
40
+
41
+ def config_file(file_name)
42
+ File.read("test/fixtures/#{file_name}")
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ module GoFigure
4
+ class GoConfigTest < Test::Unit::TestCase
5
+
6
+ def test_should_set_pipeline_in_a_config_file_with_no_pipelines_and_no_agents
7
+ assert_pipeline_template %Q{<?xml version="1.0" encoding="utf-8"?>
8
+ <cruise />
9
+ }
10
+ end
11
+
12
+ def test_should_set_pipeline_in_a_config_file_with_pipelines_and_no_agents
13
+
14
+ assert_pipeline_template %Q{<?xml version="1.0" encoding="utf-8"?>
15
+ <cruise>
16
+ <pipelines group="1">
17
+ </pipelines>
18
+
19
+ <pipelines group="2">
20
+ </pipelines>
21
+ </cruise>
22
+ }
23
+ end
24
+
25
+ def test_should_set_pipeline_in_a_config_file_with_no_pipelines_and_agents
26
+ assert_pipeline_template %Q{<?xml version="1.0" encoding="utf-8"?>
27
+ <cruise>
28
+ <agents />
29
+ </cruise>
30
+ }
31
+ end
32
+
33
+ def test_should_set_pipelines_in_a_config_file_with_pipelines_and_agents
34
+ assert_pipeline_template %Q{<?xml version="1.0" encoding="utf-8"?>
35
+ <cruise>
36
+ <pipelines group="1">
37
+ </pipelines>
38
+
39
+ <pipelines group="2">
40
+ </pipelines>
41
+ <agents />
42
+ </cruise>
43
+ }
44
+ end
45
+
46
+
47
+ def assert_pipeline_template(xml)
48
+ config = GoConfig.new(:xml => xml)
49
+ config.set_pipeline('http://git.example.com/my_project/atlas.git', 'atlas_rails')
50
+ assert config.xml_content =~ %r{<pipelines group="defaultGroup">}
51
+ assert config.xml_content =~ %r{<git url="http://git.example.com/my_project/atlas.git"/>}
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,88 @@
1
+ require 'ostruct'
2
+ class StubHttpFetcher
3
+ # Careful : this will respond to any call with nil
4
+ class HashStruct < OpenStruct
5
+ def [](key)
6
+ self.headers[key]
7
+ end
8
+ end
9
+
10
+ module Response
11
+ def invoked!
12
+ @invoked = true
13
+ end
14
+
15
+ def invoked?
16
+ !!@invoked
17
+ end
18
+ end
19
+
20
+ class StringResponse
21
+ include Response
22
+ def initialize(content, status = 200, headers = {})
23
+ @content = content
24
+ @status = 200
25
+ @headers = headers
26
+ end
27
+
28
+ def execute
29
+ HashStruct.new(:body => @content, :status => @status, :headers => @headers)
30
+ end
31
+
32
+ end
33
+
34
+ class ErrorResponse
35
+ include Response
36
+ def initialize(error)
37
+ @error = error
38
+ end
39
+
40
+ def execute
41
+ raise @error
42
+ end
43
+ end
44
+
45
+ def get(url)
46
+ if body = interweb[:get][url]
47
+ body.invoked!
48
+ return body.execute
49
+ else
50
+ raise "404 - Could not find #{url}. Available URLs are #{@interweb[:get].keys.inspect}"
51
+ end
52
+ end
53
+
54
+ def post(url, params = {})
55
+ if body = interweb[:post][url]
56
+ response = body.execute
57
+ if response.headers == params
58
+ body.invoked!
59
+ return response
60
+ end
61
+ end
62
+
63
+ raise "404 - Could not find a url listening to #{url.inspect} that responds to post params #{params.inspect}. Available URLs are #{@interweb[:post].keys.inspect}"
64
+ end
65
+
66
+ def invoked?(url, type = :get, params = {})
67
+ if body = interweb[type][url]
68
+ response = body.execute
69
+ if response.headers == params
70
+ body.invoked?
71
+ end
72
+ end
73
+ end
74
+
75
+ def register_content(content, url, type = :get, headers = {})
76
+ interweb[type][url] = StringResponse.new(content, 200, headers)
77
+ end
78
+
79
+ def register_error(url, type = :get, error)
80
+ interweb[type][url] = ErrorResponse.new(error)
81
+ end
82
+
83
+ def interweb
84
+ @interweb ||= {:get => {}, :post => {}}
85
+ end
86
+
87
+ end
88
+
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+ require 'stub_http_fetcher'
3
+
4
+ require 'go_figure'
5
+
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: go_figure
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ketan Padegaonkar
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-14 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: &70114218851080 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.5.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70114218851080
25
+ description: This provides a ruby DSL to create a configuration file for the go server
26
+ (thoughtworks-studios.com/go)
27
+ email:
28
+ - KetanPadegaonkar@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - .gitignore
34
+ - Gemfile
35
+ - README.textile
36
+ - Rakefile
37
+ - go_figure.gemspec
38
+ - lib/go-pipelines.xml.erb
39
+ - lib/go_figure.rb
40
+ - lib/go_figure/go_config.rb
41
+ - lib/go_figure/go_config_endpoint.rb
42
+ - lib/go_figure/http_fetcher.rb
43
+ - lib/go_figure/version.rb
44
+ - test/fixtures/foo.xml
45
+ - test/go_figure/go_config_endpoint_test.rb
46
+ - test/go_figure/go_config_test.rb
47
+ - test/stub_http_fetcher.rb
48
+ - test/test_helper.rb
49
+ homepage: ''
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project: go_figure
69
+ rubygems_version: 1.8.15
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A Ruby DSL to write a configuration file for the a go server.
73
+ test_files:
74
+ - test/fixtures/foo.xml
75
+ - test/go_figure/go_config_endpoint_test.rb
76
+ - test/go_figure/go_config_test.rb
77
+ - test/stub_http_fetcher.rb
78
+ - test/test_helper.rb