kanaveral 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e3d1bf221748c5b0ab3b62e41458e9ecc428248c
4
+ data.tar.gz: e5d33590b267ee7f9e3ee0e0b2013dda9b091435
5
+ SHA512:
6
+ metadata.gz: 13f4f2122e85887ff3893a8862c5b7539dc25996cccc96a463f0fa40a656c57a0e7c7ed228e45261495b2d10152053386ca3f4e7d77fd971d911dac27be47ac9
7
+ data.tar.gz: c640ae85fbc14043fa16f5bd8c89e4e1a7201634a750d48deb6f7e90874c82b56e84ca7de510c58823000dc9cb9495eee900788f0ee851bafe8eda6eedcb1aff
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kanaveral.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Philippe Cantin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,167 @@
1
+ # Kanaveral
2
+
3
+ Kanaveral is a flexible deployment/automation tool.
4
+ Its purpose is for app deployment and/or server installation.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'kanaveral'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install kanaveral
21
+
22
+ ## Usage
23
+
24
+ You can see an example under /sample, commands.rb contains the commands you use and kanaveral.rb is
25
+ the deployment script itself which use commands.rb.
26
+
27
+ The main file must be named kanaveral.rb.
28
+ The DSL define 3 main instructions :
29
+
30
+ - **commands** : indicate the path to load your commands.rb
31
+
32
+ - **server** : define your servers (user, host, app root ...). Set password to true if you don't use ssh keys.
33
+
34
+ - **deploy** contain the main instructions block to deploy your application, with **local** blocks for commands to
35
+ run locally and **remote** blocks for commands to run on remote server. You can save outputs of commands to be
36
+ used later via the keyword to:. The output result string will be available via context variable passed to
37
+ your lambda in commands.rb
38
+
39
+
40
+ ### Commands
41
+
42
+ Simply define a command like that :
43
+
44
+ ```ruby
45
+ command(<symbol>) do
46
+ command ->(context) { "my shell command where i get access to context" }
47
+ notice -> { "What i do"}
48
+ end
49
+ ```
50
+ if *notice* lambda is not present a default message is displayed. If you don't need
51
+ context just skip lambda parameter.
52
+
53
+ **Example**
54
+
55
+ ```ruby
56
+ command(:bundler) do
57
+ command ->(context) { "cd #{context.server.root} && bundle" }
58
+ notice -> { "Run bundle" }
59
+ end
60
+ ```
61
+
62
+
63
+ With *context.server* you get your server configuration, *context.server.user*, *context.server.host* etc...
64
+
65
+ You can also get variables you define in your deployment script via keyword to: (see after 'Deploy script')
66
+
67
+ **Example**
68
+
69
+ ```ruby
70
+ command(:newrelic) do
71
+ command ->(context) { "echo '#{context.commits}' | newrelic deployments -c" }
72
+ end
73
+ ```
74
+
75
+ *context.commits* contains the output of the command *run :changelog, to: :commits* (see after 'Deploy script')
76
+
77
+ ### Deploy script
78
+ ```ruby
79
+ Kanaveral::Base.deployer do
80
+
81
+ #set the file where commands to be loaded
82
+ commands(File.join(File.dirname(__FILE__), 'commands.rb'))
83
+
84
+ #define server 1
85
+ server 'server-1' do |s|
86
+ s.user = 'user'
87
+ s.host = 'myhost or ip'
88
+ s.root = '/home/www/application'
89
+ s.password = true
90
+ end
91
+
92
+ #define server 1
93
+ server 'server-2' do |s|
94
+ s.user = 'user'
95
+ s.host = 'myhost'
96
+ s.root = '/home/www/application'
97
+ s.password = true
98
+ end
99
+
100
+ #deploy commands for production servers
101
+ deploy(:production) do
102
+
103
+ #run commands locally
104
+ local do
105
+ run :changelog, to: :commits
106
+ #save output to commits which will be available in you commands via context.commits
107
+ run :git_push
108
+ end
109
+
110
+ #run commands on server-1 and then server-2
111
+ remotes('server-1', 'server-2') do
112
+ run :git_pull
113
+ run :bundler
114
+ run :assets_precompile
115
+ run :unicorn_upgrade
116
+ end
117
+
118
+ #then run commands on server-2 only
119
+ remote('server-2') do
120
+ run :delayed_job_restart
121
+ end
122
+
123
+ #at least run a command which use context.commits (this push a deployment
124
+ notification to newrelic with changelog made from commits)
125
+ local do
126
+ run :newrelic
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ ```
133
+
134
+ Then in order to run just run at the same path where your kanaveral.rb is:
135
+
136
+ $ kanaveral -e production
137
+ or
138
+
139
+ $ bundle exec kanaveral -e production
140
+
141
+
142
+ **NOTES**
143
+
144
+ - **kanaveral command look for a file named kanaveral.rb at the path it is launched**
145
+
146
+ - *context* and *server* are ruby OpenStruct so, you are free to define what you need. But user, host, root and
147
+ password are reserved.
148
+
149
+ ## Todo
150
+
151
+ - Some generic and often used commands included in gem which can be used for ie rails application deployment(bundler, git commands ...)
152
+
153
+ ## Development
154
+
155
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
156
+
157
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
158
+
159
+ ## Contributing
160
+
161
+ Bug reports and pull requests are welcome on GitHub at https://github.com/anoiaque/kanaveral. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
162
+
163
+
164
+ ## License
165
+
166
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
167
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kanaveral"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ options = {}
5
+
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: kanaveral [options]"
8
+
9
+ opts.on("-e environment", "Environment for deploy ie production") do |v|
10
+ options[:env] = v
11
+ end
12
+
13
+ opts.on('-h', "Help") { puts opts; exit }
14
+ opts.parse!
15
+ end
16
+
17
+ ENV['KANAVERAL_ENV'] = options[:env]
18
+ require "#{Dir.pwd}/kanaveral.rb"
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kanaveral/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kanaveral"
8
+ spec.version = Kanaveral::VERSION
9
+ spec.authors = ["Philippe Cantin"]
10
+ spec.email = ["anoiaque@me.com"]
11
+
12
+ spec.summary = %q{Simple application deployer}
13
+ spec.description = %q{Simple application deployer}
14
+ spec.homepage = "http://www.artizencoder.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'net-ssh'
23
+ spec.add_dependency 'rainbow'
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest"
27
+ end
@@ -0,0 +1,144 @@
1
+ require "kanaveral/version"
2
+ require 'ostruct'
3
+ require 'net/ssh'
4
+ require 'rainbow'
5
+ require 'io/console'
6
+ require 'kanaveral/extensions'
7
+ require 'kanaveral/output'
8
+
9
+ module Kanaveral
10
+ using Kanaveral::Extensions
11
+
12
+ class MissingCommand < Exception
13
+ def initialize(command)
14
+ @command = command
15
+ end
16
+
17
+ def message
18
+ "Missing command : #{@command}"
19
+ end
20
+ end
21
+
22
+ class Command < OpenStruct
23
+ @@commands = {}
24
+
25
+ def self.load path
26
+ class_eval(File.read(path))
27
+ @@commands
28
+ end
29
+
30
+ def self.command tag, &block
31
+ cmd = new
32
+ cmd.instance_eval(&block)
33
+ cmd.tag = tag
34
+ cmd.msg ||= -> { "Run #{cmd.tag}" }
35
+
36
+ @@commands[tag] = cmd
37
+ end
38
+
39
+ def command cmd
40
+ self.cmd = cmd
41
+ end
42
+
43
+ def notice msg
44
+ self.msg = msg
45
+ end
46
+
47
+ end
48
+
49
+ class Server < OpenStruct;end
50
+
51
+ class Deploy
52
+ attr_accessor :local_commands, :remote_commands
53
+
54
+ def initialize context
55
+ @context = context
56
+ @commands = @context.commands
57
+ end
58
+
59
+ def local &block
60
+ instance_eval(&block)
61
+ end
62
+
63
+ def remotes *names, &block
64
+ names.each do |name|
65
+ remote(name, &block)
66
+ end
67
+ end
68
+
69
+ def remote name, &block
70
+ Kanaveral::Output.deploy(name)
71
+
72
+ @server = @context.servers[name]
73
+ password = Kanaveral::Output.password(@server.name) if @server.password
74
+ args = [@server.host, @server.user]
75
+ args << { password: password } if password
76
+
77
+ Net::SSH.start(*args) do |ssh|
78
+ @ssh = ssh
79
+ instance_eval(&block)
80
+ end
81
+
82
+ @ssh = nil
83
+ @server = nil
84
+ end
85
+
86
+ def run command, args={}
87
+ cmd = @commands[command]
88
+ raise MissingCommand.new(command) unless cmd
89
+
90
+ cmd.context = @context
91
+ cmd.context.server = @server
92
+
93
+
94
+ Kanaveral::Output.command(kall(cmd.msg))
95
+
96
+ output = @ssh ? @ssh.exec!(kall(cmd.cmd)) : `#{kall(cmd.cmd)}`
97
+
98
+ @context.send("#{args[:to]}=", output) if args[:to]
99
+
100
+ Kanaveral::Output.cmd_output(output) unless @context.nooutput
101
+ output
102
+ end
103
+
104
+ private
105
+
106
+ def kall callee
107
+ callee.arity == 0 ? callee.call : callee.call(@context)
108
+ end
109
+
110
+ end
111
+
112
+ class Context < OpenStruct;end
113
+
114
+ class Base
115
+ ENV_KEY = 'KANAVERAL_ENV'
116
+
117
+ def server name
118
+ @servers ||= {}
119
+ server = Server.new
120
+ server.name = name
121
+ yield server
122
+ @servers[name] = server
123
+ end
124
+
125
+ def deploy env=:development, &block
126
+ Kanaveral::Output.warn("Environment : #{ENV[ENV_KEY] || 'Not set via KANAVERAL_ENV'}")
127
+
128
+ return unless ENV[ENV_KEY] == env.to_s
129
+
130
+ @context = Context.new(servers: @servers, commands: @commands)
131
+ @deployer = Deploy.new(@context)
132
+ @deployer.instance_eval(&block)
133
+ end
134
+
135
+ def commands path
136
+ @commands = Command.load(path)
137
+ end
138
+
139
+ def self.deployer &block
140
+ self.new.instance_eval(&block)
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,9 @@
1
+ module Kanaveral
2
+ module Extensions
3
+ refine String do
4
+ def camelize
5
+ split('_'.freeze).map(&:capitalize).join
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ module Kanaveral
2
+ module Output
3
+
4
+ def self.password remote
5
+ ask "Password for #{remote} : "
6
+ password = STDIN.noecho(&:gets).chop
7
+ cr
8
+ password
9
+ end
10
+
11
+ def self.cmd_output text
12
+ text ||= ''
13
+ cr
14
+ print Rainbow(text).cyan
15
+ cr
16
+ end
17
+
18
+ def self.ask text
19
+ cr
20
+ print Rainbow(text).green
21
+ end
22
+
23
+ def self.command text
24
+ cr
25
+ text = '-> ' + text
26
+ notice(text)
27
+ end
28
+
29
+ def self.deploy name
30
+ cr
31
+ title = " Deploy to #{name} "
32
+ banner '-'*(title.length + 1)
33
+ banner title
34
+ banner '-'*(title.length + 1)
35
+ end
36
+
37
+ def self.banner text
38
+ puts Rainbow(text).cyan
39
+ end
40
+
41
+ def self.notice text
42
+ puts Rainbow(text).white
43
+ end
44
+
45
+ def self.warn text
46
+ puts Rainbow(text).yellow.bright.underline
47
+ end
48
+
49
+ def self.cr
50
+ puts "\n"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module Kanaveral
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,35 @@
1
+ command(:changelog) do
2
+ command -> { "git log origin/master..master --format=short" }
3
+ notice -> { "Create changelog from commits" }
4
+ end
5
+
6
+ command(:git_push) do
7
+ command -> { "git push origin master" }
8
+ notice -> { "Push to origin/master" }
9
+ end
10
+
11
+ command(:git_pull) do
12
+ command -> { "git pull origin master" }
13
+ notice -> { "Pull from origin/master" }
14
+ end
15
+
16
+ command(:assets_precompile) do
17
+ command -> { "echo precompile assets" }
18
+ end
19
+
20
+ command(:unicorn_upgrade) do
21
+ command -> { "echo unicorns upgrade" }
22
+ end
23
+
24
+ command(:delayed_job_restart) do
25
+ command -> { "echo restart delayed job worker" }
26
+ end
27
+
28
+ command(:newrelic) do
29
+ command ->(context) { "echo '#{context.commits}' | newrelic deployments -c" }
30
+ end
31
+
32
+ command(:bundler) do
33
+ command ->(context) { ". ~/.profile && cd #{context.server.root} && bundle --quiet --without development test" }
34
+ notice -> { "Run Bundler install" }
35
+ end
@@ -0,0 +1,44 @@
1
+ require 'kanaveral'
2
+
3
+ Kanaveral::Base.deployer do
4
+
5
+ commands(File.join(File.dirname(__FILE__), 'commands.rb'))
6
+
7
+ server 'server-1' do |s|
8
+ s.user = 'philippe'
9
+ s.host = 'philae'
10
+ s.root = '/home/www/application'
11
+ s.password = true
12
+ end
13
+
14
+ server 'server-2' do |s|
15
+ s.user = 'philippe'
16
+ s.host = 'philae'
17
+ s.root = '/home/www/application'
18
+ s.password = true
19
+ end
20
+
21
+ deploy(:production) do
22
+
23
+ local do
24
+ run :changelog, to: :commits
25
+ run :git_push
26
+ end
27
+
28
+ remotes('server-1', 'server-2') do
29
+ run :git_pull
30
+ run :bundler
31
+ run :assets_precompile
32
+ run :unicorn_upgrade
33
+ end
34
+
35
+ remote('server-2') do
36
+ run :delayed_job_restart
37
+ end
38
+
39
+ local do
40
+ run :newrelic
41
+ end
42
+ end
43
+
44
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kanaveral
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Philippe Cantin
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-ssh
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rainbow
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Simple application deployer
84
+ email:
85
+ - anoiaque@me.com
86
+ executables:
87
+ - kanaveral
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - exe/kanaveral
99
+ - kanaveral.gemspec
100
+ - lib/kanaveral.rb
101
+ - lib/kanaveral/extensions.rb
102
+ - lib/kanaveral/output.rb
103
+ - lib/kanaveral/version.rb
104
+ - sample/commands.rb
105
+ - sample/kanaveral.rb
106
+ homepage: http://www.artizencoder.com
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.2.3
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Simple application deployer
130
+ test_files: []
131
+ has_rdoc: