How do I "copy unless later version exists" in Capistrano? - ruby-on-rails

I want to protect my database.yml file by keeping it out of version control. Thus, I have two tasks in my Capistrano deploy recipe:
task :copy_db_config do
# copy local config file if it exists and is more
# recent than the remote one
end
task :symlink_db_config do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
Can you help fill in the first task?

I don't have functioning code for you here and now but..
you can the the local timestamp by using ruby. File class has a function ctime which let's You know when it was changed.
Run the same command on the servers database.yml
If the local one is newest, capistrano has a method for secure upload
upload("products.txt", "/home/medined", :via => :scp)

I had the same problem, but I approached it differently. Maybe it will be helpful.
The setup task copies database.yml.example to database.yml. The deploy task does not touch database.yml. I have separate tasks for changing the database names, usernames, and passwords. Here's an example:
desc "Change the database name"
task :change_db_database, :roles => :app do
database = prompt('Enter new database name: ')
run <<-CMD
cd #{shared_path}/config &&
perl -i -pe '$env = $1 if /^(\\w+)/; s/database:.*/database: #{database}/ if $env eq "#{ENV['CONNECTION'] || ENV['TARGET']}"' database.yml
CMD
end
I run these after setup but before the first deploy on new boxes. Then any time after that when I need to change database parameters, I use these tasks instead of copying in a new file.

Related

execute bash script inside deploy.rb using capistrano

I am learning (by doing) Rails and Capistrano.
How can I execute a scrpit inside deploy.rb?
I came across run(command), exec(command), execute: or run:.
I don't have to specify :db or web so I have the following backbone:
task :myTask do
on roles(:app) do
execute "bash myScript.sh"
puts "#{:server} reports: #{myTask}"
end
end
Is this correct?
Is the ssh part of the whole process or I have to ssh in the command?
How do people develope deploy.rb without cap deploy every time they make a change?
Thank you!
Ruby allows you to run a shell script using backtick
for example
output = `pwd`
puts "output is #{output}"
see more https://ruby-doc.org/core-1.9.3/Kernel.html#method-i-60
This is what worked for me:
role :app, 'user#domain1.com'
on roles(:app) do
within 'remote_path' do
execute 'bash', ' myScript.sh'
end
end

Deploying .env file with Capistrano

I want to upload .env file to my remote machine from local machine while deploying with Capistrano, but as I am not a Ruby pro I do not get the result I want. What I want to do is take my local .env and make it available on remote machine in the shared_path. Afterwards, just symlink it with the current_path.
namespace :env do
desc "We take local env and set up on remote"
task :setup do
on roles(:app), in: :sequence, wait: 5 do
puts File.read(".env"), "#{shared_path}/config/.env"
execute "ln -nfs #{shared_path}/config/.env #{current_path}/.env"
end
end
end
Now this code creates .env as an empty file. What I am doing wrong? Or should I just execute rsync or something with Capistrano in order to achieve what I want?
I don't think puts will work there.
Try the capistrano's upload method.
upload(from, to, options={}, &block)

database.yml deployment best practice

I don't check my database.yml file into source control and I was wondering what others do/best practice for copying this file over to the server when deploying.
I use Capistrano for deployment.
Currently, I keep a shared folder called shared that lives outside of my deply_to dirs. I keep my database.yml and other config files there and have a hook in cap to cp those over during deployment. Here is my simple cap task for doing the copy:
after "deploy:update_code","deploy:config_symlink"
namespace :deploy do
task :config_symlink do
run "cp #{shared_path}/../../shared/database.yml #{release_path}/config/database.yml"
end
end
My deployment script was breaking using the after "deploy:update_code" hook because that step seemed to be trying to access the DB already. So I do:
before "deploy:assets:precompile", 'deploy:symlink_shared'
namespace :deploy do
task :symlink_shared do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
end
I've been beating my head on this one for quite some time, and have figured out an easier solution for Capistrano 3. Hope this helps those out there.
I couldn't for the life of me get the "run" or "execute" commands to work in my deploy.rb file. As it turns out, in Capistrano 3, you should put your database.yml underneath the deployment_directory/shared folder. Then, in your deployment.rb file, include the file in the linked_files variable and it automatically gets symlinked to the same path during deployment.
Here's an example:
For starters, I don't have database.yml checked into source control. My database.yml is located here on the production server:
var/www/myapp/shared/config/database.yml
In my deployment.rb, I've added this line
set :linked_files, %w{config/database.yml}
During the deployment, capistrano automatically symlinks the file to:
var/www/myapp/current/config/database.yml
Hope this helps others out there. I've really been beating my head on the wall on this today.

Apache2, Git, Capistrano & Rails - creating symlinks

I'm sort of stuck with adding symlinks to my app on the server. I currently have the following in .gitignore:
/non-public/system/uploads/*
I basically don't want Git to store the contents of the upload directory. So far so good.
On my server, inside my deploy.rb, I have the following:
namespace :customs do
task :symlink, :roles => :app do
run <<-CMD
ln -nfs #{shared_path}/system/uploads #{release_path}/non-public/system/uploads
CMD
end
end
after "deploy:symlink","customs:symlink"
after "deploy", "deploy:cleanup"
I want to create a symlink after each deployment for the uploads directory, but I keep getting a failed error message because the non-public/system/uploads directory doesn't exist in the git repository in the first place.
I've verified this by taking a look at the repository, and the structure /non-public/system/uploads doesn't exist because I have that set in .gitignore to ignore it.
I've looked at the Git wiki and it doesn't track directories, so I must be missing something. How do other developers symlink the uploads directory with their server?
What I'll usually do on my cap deploys is to create the directories, by doing a basic
set :deploy_to, "/this/dir"
run "mkdir -p #{deploy_to}/then/more/dirs"
after "deploy:symlink"
namespace :deploy....
....
....
then provide the run code to do some symlinks either on an after or whatever. This probably not optimal for all situations, but for the simple stuff it usually gets the job done.

capistrano put() and upload() both failing

With capistrano, I am deploying a Rails application from Mac OS X 10.5 to CentOS 5.2
Note that deploy.rb and the server environment have not changed in over a year.
There is a task within our deploy.rb file called upload:
put(File.read( file ),"#{shared_path}/#{filename}", :via => :scp)
This fails each and every time with the following exception:
No such file or directory - /srv/ourapp/releases/20100104194410/config/database.yml
My local copy of config/database.yml is failing to upload properly. I've verified it's not our internet connection, as this happens on three different connections and two different systems.
I've also tried to swap out put() for upload() but get the same result; also, dropping :via => :scp, and/or trying to force :sftp instead similarly fails.
Relevant info:
$ cap -V
Capistrano v2.5.10
$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.6.0]
If I understand your question correctly, it sounds like Capistrano is successfully uploading the files, but Rails is failing to start because it can't find the deploy.yml file. This might be happening during the Capistrano deploy as part of the deploy:restart task, making it look like a Capistrano error.
Based on the information you've given Capistrano is uploading the file to /svr/ourapp/shared/ and Rails is almost definitely looking for it in /svr/ourapp/releases/20100104194410/config/.
If that's the case, what you'll need to do is create a task which symlinks the shared database file to the expected location then add a hook so that task will be run after finalize_update. For instance:
task :symlink_database do
run "ln -s #{shared_path}/database.yml #{latest_release}/config/database.yml"
end
after 'deploy:finalize_update', :symlink_database
namespace :deploy do
task :upload_settings, :roles => :app do
run "mkdir -p #{shared_path}/config/"
top.upload "config/database.yml", "#{shared_path}/config/database.yml", :via => :scp
end
task :symlink_yml, :roles => :app do
run "ln -sf #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
end
after 'deploy:setup', 'deploy:upload_settings'
after 'deploy:update_code', 'deploy:symlink_yml'
This is purely from a server-side view, but have you checked to make sure that the user you're using to upload has proper permissions for the directory?
Doing a recursive change for the user (or group) depending on your server environment should fix this.
chown -R user_name_here /srv/ourapp/releases/
chgrp -R group_name_here /srv/ourapp/releases/
You might also want to clean up any code repositories e.g. git gc or svn cleanup. As well as updating any symbolic links.
The "No such file or directory" error occurs when you are trying to copy a file to a destination path that does not exist. As far as I know, the put and upload methods of Capistrano merely attempt to transfer the file, but do not make the required path. Is it possible that the config/ directory, or even the shared_path itself, has not been created when you are trying to upload this file?

Resources