How to get new release path in Capistrano 3? - capistrano

Trying to use Capistrano 3 to deploy a project and have run into an issue. In one of my tasks I'm trying to change directories and then run composer install.
For the life of me I can't get it to cd into the proper folder.
Right now if I do
set :theme_path, "#{release_path}/web/app/themes/sage"
append :linked_dirs, "web/app/uploads"
append :linked_files, ".env"
set :keep_releases, 3
namespace :deploy do
desc "Build"
after :updated, :build do
on roles(:app) do
within release_path do
execute :composer, "install --no-dev --quiet"
execute :cd, "#{fetch(:theme_path)}; composer install --no-dev --quiet"
end
end
end
end
It's for some reason running it in the previous release. Doing a pwd instead of the composer install shows that it is inside /current/ and not in the new /release/ directory. So it runs my composer install in current, and then does all the symlinking, so I end up with it always running composer in the previous deploy, so my current deploy never works.
So if release_path is /current/ and not the release currently being deployed... how do I get that path? Or how should I go about running composer install in two places?

The within syntax is how you tell Capistrano where to execute a command. I am not sure why this isn't working for you. I've copied and pasted your example into one of my apps at it works fine:
namespace :deploy do
after :updated, :build do
on roles(:app) do
within release_path do
puts capture("pwd")
end
end
end
end
When I run cap production deploy I see the pwd I expect in the output:
/home/deployer/apps/[REDACTED]/releases/20180405162938
You definitely should not be using execute :cd. Use within instead. So for example, if you need to do two executions, one in release_path and another in :theme_path, then I would do the following:
within release_path do
execute :composer, "install --no-dev --quiet"
end
within fetch(:theme_path) do
execute :composer, "install --no-dev --quiet"
end

Related

How to run a capistrano task within a whenever task?

I have whenever gem setup properly. How can I run that capistrano from my whenever schedule.rb?
my schedule.rb
every 1.minute, roles: [:app] do
# how to run here a capistrano task
# invoke 'my_app:test'
end
My capistrano task:
namespace :my_app do
desc 'test'
task :test do
on roles(:web) do
puts "the task runs"
end
end
end
Or should I move that task into a rake task. And should I run that rake task within whenever and capistrano?
Jan, you may find documentation very useful https://github.com/javan/whenever. The code example below - I just copied and edited it from the doc.
schedule.rb
# run this task only on servers with the :app role in Capistrano
# see Capistrano roles section below
every :day, at: '12:20am', roles: [:web] do
rake "app_server:task"
end
lib/tasks/test_task.rb
namespace :my_app do
desc 'test'
task :test do
puts "the task runs"
end
end
I believe it's easier to create Rake task and run it via Whenever. You can choose the Role, so basically you don't need to use Capistrano task (I believe you want to use it just because of Role).
I'd suggest your latter option, moving the logic to a rake task and executing it from both whenever and Capistrano. It'll be vastly easier and cleaner to do.

Run local executable file on remote servers with Capistrano

I have a pretty long .sh file in my Capistrano tools directory that is intended to be executed on servers, not locally. Is there a simple way to execute this file on servers inside a Capistrano task without manually copying it on each server?
Assuming that the script is in your repository, you can create a custom task which allows you to do exactly that. Something like:
namespace :deploy do
desc 'Run custom command'
task :run_custom_command do
on roles(:app) do
# Your restart mechanism here, for example:
execute release_path.join('tools/command.sh')
end
end
before :publishing, :run_custom_command
end

Set umask for remote commands

How can I direct processes started on remote machines via ssh to run with a certain umask? I want this to apply to commands run as part of standard Capistrano recipes too, so I can't just make an explicit call to "umask" part of the command.
It does not appear that ~/.bash_profile on the remote machine is read, with the way that Capistrano invokes remote commands.
I was confronted to the same issue and got around it by using the then-undocumented SSHKit.config.umask in config/deploy.rb. Note that this will set the umask for every ssh command.
Put umask 0002 in the .bashrc of the user account you use to deploy.
Agreed with Alain--set the umask in your .bashrc instead of .bash_profile. When deploying with Capistrano in a typical setup, your .bash_profile isn't loaded by default. Reading up on the difference between .bashrc and .bash_profile will help in understanding the purposes of the two.
I have environment variables set in my .bashrc file and they are certainly used when I deploy or for running any other commands with capistrano.
Another option is to create a task to set your umask value before you begin creating files on deploy. For example, in Cap 3, you can use this:
task :set_umask do
on roles(:all) do |host|
execute "umask 0002"
end
end
before "deploy:starting", "set_umask"
#beauby's answer using SSHKit is good, but it works only for Capistrano 3 as Capistrano 2 doesn't use SSHKit.
A common problem in relation to umask and Capistrano is that bundle install installs gems with permissions that are too restrictive. For this specific issue, the solution I've found for Capistrano 2 is to say:
namespace :bundle do
task :postinstall do
run "chmod -R u=rwX,go=rX #{bundle_dir}"
end
end
after 'bundle:install', 'bundle:postinstall'

Delayed_job + sitemap:refresh

So im trying to get delayed_jobs to run my sitemap:refresh command from the sitemap gem. Not sure why its not showing up in my local rake jobs:work. If i run sitemap:refresh in the terminal it runs fine and delayed_jobs runs all my other rake tasks.
in sitemap_refresh.rb
require 'sitemap_generator/tasks'
require 'delayed_job'
require 'delayed/tasks'
module Sitemap
class Refresh
def perform
`rake sitemap:refresh`
end
end
end
in my rakefile thats calling this:
task :sitemap => :environment do
load 'sitemap_refresh.rb'
puts "Refreshing Sitemap"
Delayed::Job.enqueue Sitemap::Refresh.new
puts "Sitemap has been refreshed"
end
Ive also tried replacing rake sitemap:refresh with system "sitemap:refresh" both appear to work just not in my worker from rake jobs:work.
solved the problem turns out for just needed to replace rake sitemap:refresh with Rake::Task["sitemap:refresh"].execute

How can I call a rake task on a git submodule?

I have a project including a number of vendored javascripts, e.g. jQuery. I'm including these scripts as git submodules. However, for my build process, I need the built script, not the whole repository of that script. So I'm trying to set up a rake task to build each script - preferably using the script's own rakefile - and then copy the built script into my asset directory.
file "app/vendor/scriptname.js" do
# Call the task that builds the script here
sh "cp app/vendor/script-submodule/dist/scriptname.js app/vendor/"
end
desc "Make vendor scripts available for build"
task :vendor => "app/vendor/scriptname.js" do
end
If I use import 'app/vendor/scriptname/Rakefile' in my Rakefile, I should have access to the rake task that builds the script, right? How would I call it? Or should I just use sh "cd app/vendor/script-submodule/ && rake dist" and call it good?
I'm working out a similar problem and it would seem to work just fine by calling the rake task as you normally would. Here's what my example looks like, see if you can get yours to fit.
# Rakefile
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
load 'engines/foo_engine/Rakefile'
MyApp::Application.load_tasks
Then in my submodule's Rakefile:
# engines/foo_engine/Rakefile
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each do |f|
load f
end
And a sample rake task:
# engines/foo_engine/lib/tasks/foo/bar/task.rake
namespace :foo do
namespace :bar do
desc "FooBar task"
task :foo_bar => :environment do
# perform task
end
end
end
Then from the command prompt:
rake foo:bar:task