xploy 0.1.0.beta

Sign up to get free protection for your applications and to get access to all the features.
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 2.0.0
3
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in xploy.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' 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
+ end
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jens Bissinger
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,67 @@
1
+ # xploy
2
+
3
+ [appway](http://github.com/threez/appway) client written in ruby
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/xploy.png)](https://rubygems.org/gems/xploy)
6
+ [![Travis-CI Build Status](https://secure.travis-ci.org/dpree/xploy.png)](https://travis-ci.org/dpree/xploy)
7
+ [![Coverage Status](https://coveralls.io/repos/dpree/xploy/badge.png)](https://coveralls.io/r/dpree/xploy)
8
+ [![Dependency Status](https://gemnasium.com/dpree/xploy.png)](https://gemnasium.com/dpree/xploy)
9
+ [![Code Climate](https://codeclimate.com/github/dpree/xploy.png)](https://codeclimate.com/github/dpree/xploy)
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'xploy'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install xploy
24
+
25
+ ## Usage
26
+
27
+ $ xploy
28
+
29
+ ### Recommended config settings
30
+
31
+ You can store default parameters like `app.name` and `app.manifest` in a file named `.xploy` located in your current working dir.
32
+
33
+ For an example just have a look at the `appway-example` folder.
34
+
35
+ $ cd appway-example
36
+
37
+ Here you can just redeploy the preconfigured app like so:
38
+
39
+ $ xploy redeploy
40
+
41
+ ## Development
42
+
43
+ To run the binary from the repository use the following command with ruby libray path:
44
+
45
+ RUBYLIB=lib bin/xploy
46
+
47
+ ### Coding guide
48
+
49
+ * Using global methods like `Xploy.parameter`
50
+ * is allowed for classes / modules defined on the same or a higher level to the `Xploy` namespace
51
+ * is allowed for classes / modules defined excactly one level below the `Xploy` namespace
52
+ * e.g. `Xploy::Api`
53
+ * is not allowed for classes / modules defined more than one level below the `Xploy` namespace
54
+ * e.g. `Xploy::Api::Request`
55
+ * these classes should use dependency injection instead
56
+
57
+ ### Contributing
58
+
59
+ 1. Fork it
60
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
61
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
62
+ 4. Push to the branch (`git push origin my-new-feature`)
63
+ 5. Create new Pull Request
64
+
65
+ # License
66
+
67
+ Copyright (c) 2013 Jens Bissinger. See [LICENSE.txt](LICENSE.txt)
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ app:
2
+ name: example
3
+ manifest: appway-example.json
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "example",
3
+ "repo": {
4
+ "url": "git://github.com/threez/appway-example.git",
5
+ "branch": "master"
6
+ },
7
+ "packages": {
8
+ },
9
+ "user": "www-data",
10
+ "group": "www-data",
11
+ "domain": [
12
+ "^example.*",
13
+ "^example.local$"
14
+ ],
15
+ "install": [
16
+ "npm install"
17
+ ],
18
+ "scale": {
19
+ "web": 2
20
+ }
21
+ }
data/bin/xploy ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'xploy'
4
+ Xploy::Cli.new.start
@@ -0,0 +1,76 @@
1
+ module Xploy
2
+ class Api
3
+ class Endpoints
4
+ def list options={}
5
+ Request.new 'get', '/applications'
6
+ end
7
+
8
+ def create options={}
9
+ Request.new 'post', '/applications', options
10
+ end
11
+
12
+ def find options={}
13
+ require_options options, :name
14
+ options[:name] ||= ':name'
15
+ Request.new 'get', "/applications/#{options[:name]}"
16
+ end
17
+
18
+ def update options={}
19
+ require_options options, :name
20
+ options[:name] ||= ':name'
21
+ Request.new 'put', "/applications/#{options[:name]}"
22
+ end
23
+
24
+ def delete options={}
25
+ require_options options, :name
26
+ options[:name] ||= ':name'
27
+ Request.new 'delete', "/applications/#{options[:name]}"
28
+ end
29
+
30
+ def log options={}
31
+ require_options options, :name
32
+ options[:name] ||= ':name'
33
+ Request.new 'get', "/applications/#{options[:name]}/log"
34
+ end
35
+
36
+ def start options={}
37
+ require_options options, :name
38
+ options[:name] ||= ':name'
39
+ Request.new 'post', "/applications/#{options[:name]}/start"
40
+ end
41
+
42
+ def stop options={}
43
+ require_options options, :name
44
+ options[:name] ||= ':name'
45
+ Request.new 'post', "/applications/#{options[:name]}/stop"
46
+ end
47
+
48
+ def restart options={}
49
+ require_options options, :name
50
+ options[:name] ||= ':name'
51
+ Request.new 'post', "/applications/#{options[:name]}/restart"
52
+ end
53
+
54
+ def redeploy options={}
55
+ require_options options, :name
56
+ options[:name] ||= ':name'
57
+ Request.new 'post', "/applications/#{options[:name]}/redeploy"
58
+ end
59
+
60
+ private
61
+
62
+ def require_options options, *keys
63
+ missing_keys = []
64
+ keys.each do |key|
65
+ if !options.is_a?(Hash) || options[key] == nil || options[key] == ''
66
+ missing_keys << key
67
+ end
68
+ end
69
+ unless missing_keys.empty?
70
+ raise MissingParameter, "Missing app parameter(s): "\
71
+ "#{missing_keys.map(&:to_s).join(', ')}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ require 'httparty'
2
+
3
+ module Xploy
4
+ class Api
5
+ class Http
6
+ def request server, request, debug=false
7
+ uri = File.join(server, request.path)
8
+ http_options = request.http_options.tap do |http_options|
9
+ http_options[:debug_output] = STDOUT if debug
10
+ end
11
+ HTTParty.send(request.method_name, uri, http_options)
12
+ rescue => e
13
+ raise ConnectionError, ["#{server} appears offline", e]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module Xploy
2
+ class Api
3
+ class Request
4
+ class Body
5
+ attr_reader :path
6
+
7
+ def initialize path
8
+ @path = path
9
+ end
10
+
11
+ def read
12
+ check_type do |extname|
13
+ if File.exists?(path)
14
+ File.read(path)
15
+ else
16
+ raise ManifestFileNotFound, "could not find file #{path}"
17
+ end
18
+ end
19
+ end
20
+
21
+ def mime_type
22
+ check_type do |extname|
23
+ 'application/json'
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def check_type
30
+ extname = File.extname(path)
31
+ if extname == '.json'
32
+ yield extname
33
+ else
34
+ raise ManifestFileTypeUnsupported, \
35
+ "unsupported extension #{extname} for #{path}"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ require 'xploy/api/request/body'
2
+
3
+ module Xploy
4
+ class Api
5
+ class Request
6
+ attr_reader :method_name, :path, :headers, :body
7
+
8
+ def initialize method_name, path, options={}
9
+ @method_name = method_name
10
+ @path = path
11
+ @options = options
12
+ @body = build_body
13
+ @headers = build_headers
14
+ end
15
+
16
+ def build_headers
17
+ {'X-App' => 'appway'}.tap do |headers|
18
+ headers['Content-Type'] = body.mime_type if body
19
+ end
20
+ end
21
+
22
+ def build_body
23
+ if path = @options[:manifest]
24
+ @body = Body.new path
25
+ else
26
+ @body = nil
27
+ end
28
+ end
29
+
30
+ def http_options
31
+ http_options = {headers: headers}.tap do |http_options|
32
+ http_options[:body] = body.read if body
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/xploy/api.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'xploy/api/request'
2
+ require 'xploy/api/endpoints'
3
+ require 'xploy/api/http'
4
+
5
+ module Xploy
6
+ class Api
7
+ def request method_name, *args, &block
8
+ http = Http.new
9
+ request = build_request method_name
10
+ parameter[:servers].map do |server|
11
+ http.request server, request, parameter[:debug]
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def parameter
18
+ Xploy.parameter
19
+ end
20
+
21
+ def build_request method_name
22
+ Endpoints.new.send(method_name, parameter[:app] || {})
23
+ end
24
+ end
25
+ end
data/lib/xploy/cli.rb ADDED
@@ -0,0 +1,21 @@
1
+ module Xploy
2
+ class Cli
3
+ def initialize api=Api.new, out=STDOUT
4
+ @api = api
5
+ @out = out
6
+ end
7
+
8
+ def start
9
+ commands = Xploy.parameter.rest
10
+ if Xploy.parameter[:version]
11
+ @out.puts "xploy #{VERSION}"
12
+ elsif commands.empty?
13
+ Xploy.parameter.print_help!
14
+ else
15
+ @out.puts @api.request(*commands)
16
+ end
17
+ rescue MissingParameter => e
18
+ @out.puts e.message
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module Xploy
2
+ # global error class
3
+ class Error < StandardError; end
4
+
5
+ class ManifestFileNotFound < Error; end
6
+ class ManifestFileTypeUnsupported < Error; end
7
+
8
+ class MissingParameter < Error; end
9
+
10
+ class ConnectionError < Error; end
11
+ end
@@ -0,0 +1,66 @@
1
+ require 'configliere'
2
+
3
+ module Xploy
4
+ class Parameter
5
+ def reload!
6
+ @param = Configliere::Param.new
7
+ @param.define :servers, type: Array,
8
+ flag: 's',
9
+ description: 'all appway servers',
10
+ default: ['http://localhost:8000']
11
+ @param.define 'app.name', flag: 'a',
12
+ description: 'name of your app'
13
+ @param.define 'app.manifest', flag: 'm',
14
+ description: 'path to your app.way file'
15
+ @param.define :debug, flag: 'd',
16
+ description: 'print debug info to stdout',
17
+ default: false
18
+ @param.define :version, flag: 'v',
19
+ description: 'print version info'
20
+ @param.read global_config if File.exists? global_config
21
+ @param.read local_config if File.exists? local_config
22
+ @param.use(:commandline)
23
+ @param.resolve!
24
+ self
25
+ end
26
+
27
+ def print_help!
28
+ reload!
29
+ @param[:help] = true
30
+ @param.resolve!
31
+ self
32
+ end
33
+
34
+ def [] key
35
+ if @param
36
+ @param[key]
37
+ else
38
+ nil
39
+ end
40
+ end
41
+
42
+ def rest
43
+ if @param
44
+ @param.rest
45
+ else
46
+ []
47
+ end
48
+ end
49
+
50
+ def to_hash
51
+ if @param
52
+ @param.to_hash
53
+ else
54
+ {}
55
+ end
56
+ end
57
+
58
+ def global_config
59
+ ENV['XPLOY_CONFIG'] || File.join(ENV['HOME'], '.xploy')
60
+ end
61
+
62
+ def local_config
63
+ File.join(Dir.pwd, '.xploy')
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module Xploy
2
+ VERSION = "0.1.0.beta"
3
+ end
data/lib/xploy.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'xploy/version'
2
+ require 'xploy/error'
3
+ require 'xploy/parameter'
4
+ require 'xploy/api'
5
+ require 'xploy/cli'
6
+
7
+ module Xploy
8
+ def self.parameter
9
+ @parameter ||= Parameter.new.reload!
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "example",
3
+ "repo": {
4
+ "url": "git://github.com/threez/appway-example.git",
5
+ "branch": "master"
6
+ },
7
+ "packages": {
8
+ },
9
+ "user": "www-data",
10
+ "group": "www-data",
11
+ "domain": [
12
+ "^example.*",
13
+ "^example.local$"
14
+ ],
15
+ "install": [
16
+ "npm install"
17
+ ],
18
+ "scale": {
19
+ "web": 2
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ foo: bar
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'open3'
3
+ require 'xploy/version'
4
+
5
+ class XployBinary
6
+ attr_reader :stdin, :stdout, :stderr
7
+ def run
8
+ exe = File.expand_path('../../../bin/xploy', File.dirname(__FILE__))
9
+ ENV['RUBYLIB'] = File.join(File.dirname(__FILE__), '../../../lib')
10
+ @stdin, @stdout, @stderr = Open3.popen3("#{exe} --version")
11
+ end
12
+ end
13
+
14
+ describe XployBinary do
15
+ before { subject.run }
16
+ its('stderr.readlines.to_s') { should_not include('xploy') }
17
+ its('stdout.readlines.to_s') { should include(Xploy::VERSION) }
18
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ require 'xploy'
3
+
4
+ describe Xploy::Cli do
5
+ it 'uses api and stdout per default' do
6
+ subject.instance_variable_get('@api').should be_instance_of(Xploy::Api)
7
+ subject.instance_variable_get('@out').should eq STDOUT
8
+ end
9
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+ require 'xploy/error'
3
+ require 'xploy/api/endpoints'
4
+ require 'xploy/api/request'
5
+
6
+ describe Xploy::Api::Endpoints do
7
+ subject('endpoints') { described_class.new }
8
+
9
+ specify 'list doesnt require_options' do
10
+ expect{ subject.list }.not_to raise_error(Xploy::MissingParameter)
11
+ end
12
+ specify 'create doesnt require_options' do
13
+ expect{ subject.create }.not_to raise_error(Xploy::MissingParameter)
14
+ end
15
+ specify 'find does require_options' do
16
+ expect{ subject.find }.to raise_error(Xploy::MissingParameter)
17
+ end
18
+ specify 'update does require_options' do
19
+ expect{ subject.update }.to raise_error(Xploy::MissingParameter)
20
+ end
21
+ specify 'delete does require_options' do
22
+ expect{ subject.delete }.to raise_error(Xploy::MissingParameter)
23
+ end
24
+ specify 'log does require_options' do
25
+ expect{ subject.log }.to raise_error(Xploy::MissingParameter)
26
+ end
27
+ specify 'start does require_options' do
28
+ expect{ subject.start }.to raise_error(Xploy::MissingParameter)
29
+ end
30
+ specify 'stop does require_options' do
31
+ expect{ subject.stop }.to raise_error(Xploy::MissingParameter)
32
+ end
33
+ specify 'restart does require_options' do
34
+ expect{ subject.restart }.to raise_error(Xploy::MissingParameter)
35
+ end
36
+ specify 'redeploy does require_options' do
37
+ expect{ subject.redeploy }.to raise_error(Xploy::MissingParameter)
38
+ end
39
+
40
+ context 'mock require_options' do
41
+ before { endpoints.stub('require_options') }
42
+
43
+ describe 'list' do
44
+ subject { endpoints.list({}) }
45
+ its('method_name') { should eq 'get' }
46
+ its('path') { should eq '/applications' }
47
+ its('headers') { should eq('X-App' => 'appway') }
48
+ its('body') { should eq(nil) }
49
+ end
50
+
51
+ describe 'create' do
52
+ let('manifest') { File.join(ASSETS_PATH, 'appway-example.json') }
53
+ subject { endpoints.create manifest: manifest }
54
+ its('method_name') { should eq 'post' }
55
+ its('path') { should eq '/applications' }
56
+ its('headers') { should eq('X-App' => 'appway',
57
+ 'Content-Type' => 'application/json') }
58
+ its('body') { should be_kind_of(Xploy::Api::Request::Body) }
59
+ end
60
+
61
+ describe 'find' do
62
+ subject { endpoints.find name: 'foo' }
63
+ its('method_name') { should eq 'get' }
64
+ its('path') { should eq '/applications/foo' }
65
+ its('headers') { should eq('X-App' => 'appway') }
66
+ its('body') { should eq(nil) }
67
+ end
68
+
69
+ describe 'update' do
70
+ subject { endpoints.update name: 'foo' }
71
+ its('method_name') { should eq 'put' }
72
+ its('path') { should eq '/applications/foo' }
73
+ its('headers') { should eq('X-App' => 'appway') }
74
+ its('body') { should eq(nil) }
75
+ end
76
+
77
+ describe 'delete' do
78
+ subject { endpoints.delete name: 'foo' }
79
+ its('method_name') { should eq 'delete' }
80
+ its('path') { should eq '/applications/foo' }
81
+ its('headers') { should eq('X-App' => 'appway') }
82
+ its('body') { should eq(nil) }
83
+ end
84
+
85
+ describe 'log' do
86
+ subject { endpoints.log name: 'foo' }
87
+ its('method_name') { should eq 'get' }
88
+ its('path') { should eq '/applications/foo/log' }
89
+ its('headers') { should eq('X-App' => 'appway') }
90
+ its('body') { should eq(nil) }
91
+ end
92
+
93
+ describe 'start' do
94
+ subject { endpoints.start name: 'foo' }
95
+ its('method_name') { should eq 'post' }
96
+ its('path') { should eq '/applications/foo/start' }
97
+ its('headers') { should eq('X-App' => 'appway') }
98
+ its('body') { should eq(nil) }
99
+ end
100
+
101
+ describe 'stop' do
102
+ subject { endpoints.stop name: 'foo' }
103
+ its('method_name') { should eq 'post' }
104
+ its('path') { should eq '/applications/foo/stop' }
105
+ its('headers') { should eq('X-App' => 'appway') }
106
+ its('body') { should eq(nil) }
107
+ end
108
+
109
+ describe 'restart' do
110
+ subject { endpoints.restart name: 'foo' }
111
+ its('method_name') { should eq 'post' }
112
+ its('path') { should eq '/applications/foo/restart' }
113
+ its('headers') { should eq('X-App' => 'appway') }
114
+ its('body') { should eq(nil) }
115
+ end
116
+
117
+ describe 'redeploy' do
118
+ subject { endpoints.redeploy name: 'foo' }
119
+ its('method_name') { should eq 'post' }
120
+ its('path') { should eq '/applications/foo/redeploy' }
121
+ its('headers') { should eq('X-App' => 'appway') }
122
+ its('body') { should eq(nil) }
123
+ end
124
+ end
125
+ end