deployml 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.document +3 -0
  2. data/.rspec +1 -0
  3. data/.yardopts +1 -0
  4. data/ChangeLog.md +22 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +107 -0
  7. data/Rakefile +35 -0
  8. data/bin/deployml +5 -0
  9. data/deployml.gemspec +10 -0
  10. data/gemspec.yml +21 -0
  11. data/lib/deployml/cli.rb +192 -0
  12. data/lib/deployml/configuration.rb +149 -0
  13. data/lib/deployml/environment.rb +273 -0
  14. data/lib/deployml/exceptions/config_not_found.rb +4 -0
  15. data/lib/deployml/exceptions/invalid_config.rb +4 -0
  16. data/lib/deployml/exceptions/missing_option.rb +6 -0
  17. data/lib/deployml/exceptions/unknown_environment.rb +4 -0
  18. data/lib/deployml/exceptions/unknown_framework.rb +6 -0
  19. data/lib/deployml/exceptions/unknown_server.rb +6 -0
  20. data/lib/deployml/frameworks/rails2.rb +9 -0
  21. data/lib/deployml/frameworks/rails3.rb +20 -0
  22. data/lib/deployml/frameworks.rb +2 -0
  23. data/lib/deployml/local_shell.rb +54 -0
  24. data/lib/deployml/options/mongrel.rb +46 -0
  25. data/lib/deployml/options/thin.rb +72 -0
  26. data/lib/deployml/options.rb +1 -0
  27. data/lib/deployml/project.rb +304 -0
  28. data/lib/deployml/remote_shell.rb +130 -0
  29. data/lib/deployml/servers/apache.rb +19 -0
  30. data/lib/deployml/servers/mongrel.rb +41 -0
  31. data/lib/deployml/servers/thin.rb +41 -0
  32. data/lib/deployml/servers.rb +3 -0
  33. data/lib/deployml/shell.rb +46 -0
  34. data/lib/deployml/version.rb +4 -0
  35. data/lib/deployml.rb +2 -0
  36. data/spec/configuration_spec.rb +73 -0
  37. data/spec/deployml_spec.rb +11 -0
  38. data/spec/environment_spec.rb +34 -0
  39. data/spec/helpers/projects/bad_config/config/deploy.yml +1 -0
  40. data/spec/helpers/projects/basic/config/deploy.yml +3 -0
  41. data/spec/helpers/projects/invalid_server/config/deploy.yml +4 -0
  42. data/spec/helpers/projects/missing_config/.gitkeep +0 -0
  43. data/spec/helpers/projects/missing_dest/config/deploy.yml +2 -0
  44. data/spec/helpers/projects/missing_source/config/deploy.yml +2 -0
  45. data/spec/helpers/projects/rails/config/deploy/production.yml +10 -0
  46. data/spec/helpers/projects/rails/config/deploy/staging.yml +10 -0
  47. data/spec/helpers/projects/rails/config/deploy.yml +3 -0
  48. data/spec/helpers/projects.rb +11 -0
  49. data/spec/project_spec.rb +66 -0
  50. data/spec/spec_helper.rb +8 -0
  51. metadata +207 -0
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ LICENSE.txt
3
+ ChangeLog.*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title 'DeploYML Documentation' --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,22 @@
1
+ ### 0.3.0 / 2010-11-21
2
+
3
+ * Initial release:
4
+ * Requires only **one YAML file** (`config/deploy.yml`) with a minimum of
5
+ **two** things (`source` and `dest`).
6
+ * Supports multiple deployment environments (`config/deploy/staging.yml`).
7
+ * Supports [Git](http://www.git-scm.com/).
8
+ * Can deploy Ruby web applications or static sites.
9
+ * Supports common Web Servers:
10
+ * [Apache](http://www.apache.org/)
11
+ * [Mongrel](https://github.com/fauna/mongrel)
12
+ * [Thin](http://code.macournoyer.com/thin/)
13
+ * Supports common Web Application frameworks:
14
+ * [Rails](http://rubyonrails.org/):
15
+ * [Bundler](http://gembundler.com/)
16
+ * ActiveRecord
17
+ * [DataMapper](http://datamapper.org/)
18
+ * **Does not** require anything else to be installed on the servers.
19
+ * **Does not** use `net-ssh`.
20
+ * Supports any Operating System that supports Ruby and SSH.
21
+ * Provides a simple command-line interface using Thor.
22
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+
2
+ Copyright (c) 2010 Hal Brodigan
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ 'Software'), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # DeploYML
2
+
3
+ * [Source](http://github.com/postmodern/deployml)
4
+ * [Issues](http://github.com/postmodern/deployml/issues)
5
+ * Postmodern (postmodern.mod3 at gmail.com)
6
+
7
+ ## Description
8
+
9
+ DeploYML is a simple deployment solution that uses a single YAML file,
10
+ Git and SSH.
11
+
12
+ ## Features
13
+
14
+ * Requires only **one YAML file** (`config/deploy.yml`) with a minimum of
15
+ **two** things (`source` and `dest`).
16
+ * Supports multiple deployment environments (`config/deploy/staging.yml`).
17
+ * Supports [Git](http://www.git-scm.com/).
18
+ * Can deploy Ruby web applications or static sites.
19
+ * Supports common Web Servers:
20
+ * [Apache](http://www.apache.org/)
21
+ * [Mongrel](https://github.com/fauna/mongrel)
22
+ * [Thin](http://code.macournoyer.com/thin/)
23
+ * Supports common Web Application frameworks:
24
+ * [Rails](http://rubyonrails.org/):
25
+ * [Bundler](http://gembundler.com/)
26
+ * ActiveRecord
27
+ * [DataMapper](http://datamapper.org/)
28
+ * **Does not** require anything else to be installed on the servers.
29
+ * **Does not** use `net-ssh`.
30
+ * Supports any Operating System that supports Ruby and SSH.
31
+ * Provides a simple command-line interface using Thor.
32
+
33
+ ## Examples
34
+
35
+ Specifying `source` and `dest` URIs as Strings:
36
+
37
+ source: git@github.com:user/project.git
38
+ dest: deploy@www.example.com/var/www/site
39
+
40
+ Specifying `dest` URI as a Hash:
41
+
42
+ source: git@github.com:user/project.git
43
+ dest:
44
+ user: deploy
45
+ host: www.example.com
46
+ path: /var/www/site
47
+
48
+ Specifying a `server` option:
49
+
50
+ source: git@github.com:user/project.git
51
+ dest: deploy@www.example.com/var/www/site
52
+ server: apache
53
+
54
+ Specifying a `server` with options:
55
+
56
+ source: git@github.com:user/project.git
57
+ dest: deploy@www.example.com/var/www/site
58
+ server:
59
+ name: thin
60
+ options:
61
+ servers: 4
62
+ deamonize: true
63
+ socket: /var/run/thin.sock
64
+ rackup: true
65
+
66
+ ## Synopsis
67
+
68
+ Cold-Deploy a new project:
69
+
70
+ $ deployml deploy
71
+
72
+ Redeploy a project:
73
+
74
+ $ deployml redeploy
75
+
76
+ Run a rake task on the deploy server:
77
+
78
+ $ deployml rake 'db:automigrate'
79
+
80
+ Execute a command on the deploy server:
81
+
82
+ $ deployml exec 'whoami'
83
+
84
+ SSH into the deploy server:
85
+
86
+ $ deployml ssh
87
+
88
+ List available tasks:
89
+
90
+ $ deployml help
91
+
92
+ ## Requirements
93
+
94
+ * [addressable](http://addressable.rubyforge.org/) ~> 2.1.1
95
+ * [rprogram](http://github.com/postmodern/rprogram) ~> 0.2.0
96
+ * [thor](http://github.com/wycats/thor) ~> 0.14.3
97
+
98
+ ## Install
99
+
100
+ $ sudo gem install deployml
101
+
102
+ ## Copyright
103
+
104
+ Copyright (c) 2010 Hal Brodigan
105
+
106
+ See {file:LICENSE.txt} for license information.
107
+
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ gem 'ore-tasks', '~> 0.3.0'
6
+ require 'ore/tasks'
7
+
8
+ Ore::Tasks.new
9
+ rescue LoadError => e
10
+ STDERR.puts e.message
11
+ STDERR.puts "Run `gem install ore-tasks` to install 'ore/tasks'."
12
+ end
13
+
14
+ begin
15
+ gem 'rspec', '~> 2.1.0'
16
+ require 'rspec/core/rake_task'
17
+
18
+ RSpec::Core::RakeTask.new
19
+ rescue LoadError => e
20
+ task :spec do
21
+ abort "Please run `gem install rspec` to install RSpec."
22
+ end
23
+ end
24
+ task :default => :spec
25
+
26
+ begin
27
+ gem 'yard', '~> 0.6.0'
28
+ require 'yard'
29
+
30
+ YARD::Rake::YardocTask.new
31
+ rescue LoadError => e
32
+ task :yard do
33
+ abort "Please run `gem install yard` to install YARD."
34
+ end
35
+ end
data/bin/deployml ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'deployml/cli'
4
+
5
+ DeploYML::CLI.start
data/deployml.gemspec ADDED
@@ -0,0 +1,10 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ begin
4
+ Ore::Specification.new do |gemspec|
5
+ # custom logic here
6
+ end
7
+ rescue NameError
8
+ STDERR.puts "The 'deployml.gemspec' file requires Ore."
9
+ STDERR.puts "Run `gem install ore-core` to install Ore."
10
+ end
data/gemspec.yml ADDED
@@ -0,0 +1,21 @@
1
+ name: deployml
2
+ summary: A simple deployment solution that works.
3
+ description:
4
+ DeploYML is a simple deployment solution that uses a single YAML file,
5
+ Git and SSH.
6
+
7
+ license: MIT
8
+ authors: Postmodern
9
+ email: postmodern.mod3@gmail.com
10
+ homepage: http://github.com/postmodern/deployml
11
+ has_yard: true
12
+
13
+ dependencies:
14
+ addressable: ~> 2.1.1
15
+ rprogram: ~> 0.2.0
16
+ thor: ~> 0.14.3
17
+
18
+ development_dependencies:
19
+ ore-tasks: ~> 0.3.0
20
+ rspec: ~> 2.1.0
21
+ yard: ~> 0.6.0
@@ -0,0 +1,192 @@
1
+ require 'deployml/project'
2
+
3
+ require 'thor'
4
+ require 'pathname'
5
+
6
+ module DeploYML
7
+ class CLI < Thor
8
+
9
+ namespace 'deploy'
10
+
11
+ desc 'exec', 'Runs a command on the deploy server'
12
+ method_option :environment, :type => :string, :default => 'production'
13
+ def exec(command)
14
+ environment.exec(command)
15
+ end
16
+
17
+ desc 'rake', 'Executes a rake task on the deploy server'
18
+ method_option :environment, :type => :string, :default => 'production'
19
+ method_option :args, :type => :array
20
+ def rake(task)
21
+ environment.rake(task,*(options[:args]))
22
+ end
23
+
24
+ desc 'ssh', 'Starts a SSH session with the deploy server'
25
+ method_option :environment, :type => :string, :default => 'production'
26
+ def ssh
27
+ environment.ssh
28
+ end
29
+
30
+ desc 'setup', 'Sets up the deployment repository for the project'
31
+ method_option :environment, :type => :string, :default => 'production'
32
+ def setup
33
+ status 'Setting up ...'
34
+
35
+ project.setup!(options[:environment])
36
+
37
+ status 'Setup'
38
+ end
39
+
40
+ desc 'update', 'Updates the deployment repository of the project'
41
+ method_option :environment, :type => :string, :default => 'production'
42
+ def update
43
+ status 'Updating'
44
+
45
+ project.update!(options[:environment])
46
+
47
+ status 'Updated'
48
+ end
49
+
50
+ desc 'install', 'Installs the project on the deploy server'
51
+ method_option :environment, :type => :string, :default => 'production'
52
+ def install
53
+ status 'Installing ...'
54
+
55
+ project.install!(options[:environment])
56
+
57
+ status 'Installed'
58
+ end
59
+
60
+ desc 'migrate', 'Migrates the database for the project'
61
+ method_option :environment, :type => :string, :default => 'production'
62
+ def migrate
63
+ status 'Migrating ...'
64
+
65
+ project.migrate!(options[:environment])
66
+
67
+ status 'Migrated'
68
+ end
69
+
70
+ desc 'config', 'Configures the server for the project'
71
+ method_option :environment, :type => :string, :default => 'production'
72
+ def config
73
+ status 'Configuring ...'
74
+
75
+ project.config!(options[:environment])
76
+
77
+ status 'Configured'
78
+ end
79
+
80
+ desc 'start', 'Starts the server for the project'
81
+ method_option :environment, :type => :string, :default => 'production'
82
+
83
+ def start
84
+ status 'Starting ...'
85
+
86
+ project.start!(options[:environment])
87
+
88
+ status 'Started'
89
+ end
90
+
91
+ desc 'stop', 'Stops the server for the project'
92
+ method_option :environment, :type => :string, :default => 'production'
93
+
94
+ def stop
95
+ status 'Stopping ...'
96
+
97
+ project.stop!(options[:environment])
98
+
99
+ status 'Stopped'
100
+ end
101
+
102
+ desc 'restart', 'Restarts the server for the project'
103
+ method_option :environment, :type => :string, :default => 'production'
104
+
105
+ def restart
106
+ status 'Restarting ...'
107
+
108
+ project.restart!(options[:environment])
109
+
110
+ status 'Restarted'
111
+ end
112
+
113
+ desc 'deploy', 'Cold-Deploys a new project'
114
+ method_option :environment, :type => :string, :default => 'production'
115
+
116
+ def deploy
117
+ status 'Deploying ...'
118
+
119
+ project.deploy!(options[:environment])
120
+
121
+ status 'Deployed'
122
+ end
123
+
124
+ desc 'redeploy', 'Redeploys the project'
125
+ method_option :environment, :type => :string, :default => 'production'
126
+
127
+ def redeploy
128
+ status 'Redeploying ...'
129
+
130
+ project.redeploy!(options[:environment])
131
+
132
+ status 'Redeployed'
133
+ end
134
+
135
+ protected
136
+
137
+ #
138
+ # Finds the root of the project, starting at the current working
139
+ # directory and ascending upwards.
140
+ #
141
+ # @return [Pathname]
142
+ # The root of the project.
143
+ #
144
+ # @since 0.3.0
145
+ #
146
+ def find_root
147
+ Pathname.pwd.ascend do |root|
148
+ config_dir = root.join(Project::CONFIG_DIR)
149
+
150
+ if config_dir.directory?
151
+ config_file = config_dir.join(Project::CONFIG_FILE)
152
+ return root if config_file.file?
153
+
154
+ environments_dir = config_dir.join(Project::ENVIRONMENTS_DIR)
155
+ return root if environments_dir.directory?
156
+ end
157
+ end
158
+
159
+ shell.say "Could not find '#{Project::CONFIG_FILE}' in any parent directories", :red
160
+ exit -1
161
+ end
162
+
163
+ #
164
+ # The project.
165
+ #
166
+ # @return [Project]
167
+ # The project object.
168
+ #
169
+ # @since 0.3.0
170
+ #
171
+ def project
172
+ @project ||= Project.new(find_root)
173
+ end
174
+
175
+ #
176
+ # The selected environment.
177
+ #
178
+ # @return [Environment]
179
+ # A deployment environment of the project.
180
+ #
181
+ # @since 0.3.0
182
+ #
183
+ def environment
184
+ project.environment(options[:environment])
185
+ end
186
+
187
+ def status(message)
188
+ shell.say_status "[#{options[:environment]}]", message
189
+ end
190
+
191
+ end
192
+ end
@@ -0,0 +1,149 @@
1
+ require 'deployml/exceptions/missing_option'
2
+
3
+ require 'addressable/uri'
4
+
5
+ module DeploYML
6
+ #
7
+ # The {Configuration} class loads in the settings from a `deploy.yml`
8
+ # file.
9
+ #
10
+ class Configuration
11
+
12
+ # Default SCM to use
13
+ DEFAULT_SCM = :rsync
14
+
15
+ # The server run the deployed project under
16
+ attr_reader :server_name
17
+
18
+ # Options for the server
19
+ attr_reader :server_options
20
+
21
+ # The source URI of the project Git repository.
22
+ attr_reader :source
23
+
24
+ # The destination URI to upload the project to.
25
+ attr_reader :dest
26
+
27
+ # The framework used by the project
28
+ attr_reader :framework
29
+
30
+ # The ORM used by the project
31
+ attr_reader :orm
32
+
33
+ # The environment to run the project in
34
+ attr_reader :environment
35
+
36
+ # Specifies whether to enable debugging.
37
+ attr_accessor :debug
38
+
39
+ #
40
+ # Creates a new {Configuration} using the given configuration.
41
+ #
42
+ # @param [Hash] config
43
+ # The configuration for the project.
44
+ #
45
+ # @option config [String] :source
46
+ # The source URI of the project Git repository.
47
+ #
48
+ # @option config [String, Hash] :dest
49
+ # The destination URI to upload the project to.
50
+ #
51
+ # @option config [Symbol] :framework
52
+ # The framework used by the project.
53
+ #
54
+ # @option config [Symbol] :orm
55
+ # The ORM used by the project.
56
+ #
57
+ # @option config [Symbol] :environment
58
+ # The environment to run the project in.
59
+ #
60
+ # @option config [Boolean] :debug (false)
61
+ # Specifies whether to enable debugging.
62
+ #
63
+ # @raise [MissingOption]
64
+ # The `server` option Hash did not contain a `name` option.
65
+ #
66
+ def initialize(config={})
67
+ @source = nil
68
+ @dest = nil
69
+
70
+ @server_name = nil
71
+ @server_options = {}
72
+
73
+ @framework = nil
74
+ @orm = nil
75
+
76
+ @environment = nil
77
+ @debug = false
78
+
79
+ config = normalize_hash(config)
80
+
81
+ if config[:framework]
82
+ @framework = config[:framework].to_sym
83
+ end
84
+
85
+ if config[:orm]
86
+ @orm = config[:orm].to_sym
87
+ end
88
+
89
+ case config[:server]
90
+ when Symbol, String
91
+ @server_name = config[:server].to_sym
92
+ when Hash
93
+ unless config[:server].has_key?(:name)
94
+ raise(MissingOption,"the 'server' option must contain a 'name' option for which server to use",caller)
95
+ end
96
+
97
+ if config[:server].has_key?(:name)
98
+ @server_name = config[:server][:name].to_sym
99
+ end
100
+
101
+ if config[:server].has_key?(:options)
102
+ @server_options.merge!(config[:server][:options])
103
+ end
104
+ end
105
+
106
+ @source = config[:source]
107
+ @dest = case config[:dest]
108
+ when Hash
109
+ Addressable::URI.new(config[:dest])
110
+ when String
111
+ Addressable::URI.parse(config[:dest])
112
+ end
113
+
114
+ if config[:environment]
115
+ @environment = config[:environment].to_sym
116
+ end
117
+
118
+ if config[:debug]
119
+ @debug = config[:debug]
120
+ end
121
+ end
122
+
123
+ protected
124
+
125
+ #
126
+ # Converts all the keys of a Hash to Symbols.
127
+ #
128
+ # @param [Hash{Object => Object}] hash
129
+ # The hash to be converted.
130
+ #
131
+ # @return [Hash{Symbol => Object}]
132
+ # The normalized Hash.
133
+ #
134
+ def normalize_hash(hash)
135
+ new_hash = {}
136
+
137
+ hash.each do |key,value|
138
+ new_hash[key.to_sym] = if value.kind_of?(Hash)
139
+ normalize_hash(value)
140
+ else
141
+ value
142
+ end
143
+ end
144
+
145
+ return new_hash
146
+ end
147
+
148
+ end
149
+ end