deployml 0.3.0

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