xploy 0.1.0.beta

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