require 'deployml/exceptions/config_not_found' require 'deployml/exceptions/invalid_config' require 'deployml/exceptions/unknown_environment' require 'deployml/environment' require 'deployml/remote_shell' require 'yaml' module DeploYML class Project # The general configuration directory. CONFIG_DIR = 'config' # The configuration file name. CONFIG_FILE = 'deploy.yml' # The configuration directory. ENVIRONMENTS_DIR = 'deploy' # The name of the directory to stage deployments in. STAGING_DIR = '.deploy' # The root directory of the project attr_reader :root # The deployment environments of the project attr_reader :environments # # Creates a new project using the given configuration file. # # @param [String] root # The root directory of the project. # # @raise [ConfigNotFound] # The configuration file for the project could not be found # in any of the common directories. # def initialize(root) @root = File.expand_path(root) @config_file = File.join(@root,CONFIG_DIR,CONFIG_FILE) @environments_dir = File.join(@root,CONFIG_DIR,ENVIRONMENTS_DIR) unless (File.file?(@config_file) || File.directory?(@environments_dir)) raise(ConfigNotFound,"could not find '#{CONFIG_FILE}' or '#{ENVIRONMENTS_DIR}' in #{root}") end load_environments! end # # @param [Symbol, String] name # The name of the environment to use. # # @return [Environment] # The environment with the given name. # # @raise [UnknownEnvironment] # No environment was configured with the given name. # # @since 0.3.0 # def environment(name=:production) name = name.to_sym unless @environments[name] raise(UnknownEnvironment,"unknown environment: #{name}") end return @environments[name] end # # Conveniance method for accessing the development environment. # # @return [Environment] # The development environment. # # @since 0.3.0 # def development environment(:development) end # # Conveniance method for accessing the staging environment. # # @return [Environment] # The staging environment. # # @since 0.3.0 # def staging environment(:staging) end # # Conveniance method for accessing the production environment. # # @return [Environment] # The production environment. # # @since 0.3.0 # def production environment(:production) end # # Deploys the project. # # @param [Array<Symbol>] tasks # The tasks to run during the deployment. # # @param [Symbol, String] env # The environment to deploy to. # # @return [true] # # @since 0.2.0 # def invoke(tasks,env=:production) env = environment(env) env.remote_shell do |shell| # setup the deployment repository env.setup(shell) if tasks.include?(:setup) # cd into the deployment repository shell.cd env.dest.path # update the deployment repository env.update(shell) if tasks.include?(:update) # framework tasks env.install(shell) if tasks.include?(:install) env.migrate(shell) if tasks.include?(:migrate) # server tasks if tasks.include?(:config) env.server_config(shell) elsif tasks.include?(:start) env.server_start(shell) elsif tasks.include?(:stop) env.server_stop(shell) elsif tasks.include?(:restart) env.server_restart(shell) end end return true end # # Sets up the deployment repository for the project. # # @param [Symbol, String] env # The environment to deploy to. # def setup!(env=:production) invoke [:setup], env end # # Updates the deployed repository of the project. # # @param [Symbol, String] env # The environment to deploy to. # def update!(env=:production) invoke [:update], env end # # Installs the project on the destination server. # # @param [Symbol, String] env # The environment to deploy to. # def install!(env=:production) invoke [:install], env end # # Migrates the database used by the project. # # @param [Symbol, String] env # The environment to deploy to. # def migrate!(env=:production) invoke [:migrate], env end # # Configures the Web server to be ran on the destination server. # # @param [Symbol, String] env # The environment to deploy to. # def config!(env=:production) invoke [:config], env end # # Starts the Web server for the project. # # @param [Symbol, String] env # The environment to deploy to. # def start!(env=:production) invoke [:start], env end # # Stops the Web server for the project. # # @param [Symbol, String] env # The environment to deploy to. # def stop!(env=:production) invoke [:stop], env end # # Restarts the Web server for the project. # # @param [Symbol, String] env # The environment to deploy to. # def restart!(env=:production) invoke [:restart], env end # # Deploys a new project. # # @param [Symbol, String] env # The environment to deploy to. # # @since 0.2.0 # def deploy!(env=:production) invoke [:setup, :install, :migrate, :config, :start], env end # # Redeploys a project. # # @param [Symbol, String] env # The environment to deploy to. # # @since 0.2.0 # def redeploy!(env=:production) invoke [:update, :install, :migrate, :restart], env end protected # # Loads the project configuration. # # @raise [InvalidConfig] # The YAML configuration file did not contain a Hash. # # @raise [MissingOption] # The `source` or `dest` options were not specified. # # @since 0.3.0 # def load_environments! base_config = {} load_config_data = lambda { |path| config_data = YAML.load_file(path) unless config_data.kind_of?(Hash) raise(InvalidConfig,"DeploYML file '#{path}' does not contain a Hash") end config_data } if File.file?(@config_file) base_config.merge!(load_config_data[@config_file]) end @environments = {} if File.directory?(@environments_dir) Dir.glob(File.join(@environments_dir,'*.yml')) do |path| config_data = base_config.merge(load_config_data[path]) name = File.basename(path).sub(/\.yml$/,'').to_sym @environments[name] = Environment.new(name,config_data) end else @environments[:production] = Environment.new(:production,base_config) end end end end