I need to trigger a capistrano deployment from within an existing ruby scrpit.
For example, assume I want to start service that will listen to some messages, and on some messages I want to trigger a capistrano deployment of another app using cap staging deploy (which does work if I run this command directly from a shell).
~/app-to-deploy
- Gemfile #including many dependencies
- config/deploy # capistrano files
~/my-service
- Gemfile # including different dependencies than `app-to-deploy`
- my_script.rb # that wishes to call `cap app-to-deploy deploy`
I was thinking I could run the capistrano bash script from my service using something like
# my_service.rb
Dir.chdir(ENV['HOME'] + '/app-to-deploy') do
result = system('bash', '-c', "cap staging deploy")
end
If I run it with or without bundle exec this gives something like
cap aborted!
LoadError: cannot load such file -- active_support/all
/deploy/hermes/Capfile:2:in `require'
/deploy/hermes/Capfile:2:in `<top (required)>'
(See full trace by running task with --trace)
(I have ActiveSupport as a gem in my app-to-deploy but I don't have it in the Gemfile of my-service)
Seems like I have a lib dependency problem, but I'm not sure how to solve it...
Anyone has ideas or ways to go around the problem ? (or even better a way to call capistrano without using bash, assuming I may still have different dependencies ?)
(Note that app-to-deploy is an actual Rails app with many capistrano scripts that I don't want to touch if possible...)
The problem is that in unix systems environment is inherited. So when you call Capistrano from your rails app you don't have access to other gems. bash -c doesn't seem to clean env. You can with su -l probably.
One solution is to use
Bundler.with_clean_env do
Dir.chdir(ENV['HOME'] + '/app-to-deploy') do
result = system('bundle', 'exec', "cap", "staging", "deploy")
end
end
Just for reference: http://bundler.io/man/bundle-exec.1.html#Shelling-out
Related
So I have a rails 6 app that doesn't load any css or javascript assets when I run cap production deploy.
So what I do is after I run cap production deploy, I ssh into my server, navigate to myapp/current/ and run bin/webpack and then everything works. So I'd like my deployment process to do this for me so that I don't have to go into my server and run this everytime.
I've looked on how to run custom capistrano "tasks," but all the tutorials show you only how to run custom rake tasks, but this isn't a rake task.
I don't run rake bin/webpack, i just run bin/webpack.
So how I would go about implementing this in my capistrano setup? I assume I have to enter some sort of capistrano command in my deploy.rb.
Any ideas?
Capistrano at its core is just ssh. It's doing something similar to what you're doing when you ssh (although slightly different because it's not typically an interactive session).
You could write a custom task to run Webpack.
To do that you need to load them first if they're not already being loaded.
Check for this line in your Capfile or add it yourself. This will load your custom tasks which come in the form of rake tasks:
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
Then, create a task in that folder. Call it something like lib/capistrano/tasks/webpack.rake
namespace :webpack do
task :build do
on roles(:app) do
within release_path do
# https://github.com/capistrano/sshkit#the-command-map
with path: "#{release_path}/bin:$PATH" do
execute :webpack
end
end
end
end
end
Now, you need to tell Capistrano when to execute it. I usually do this with before/after hooks. For more info check out Capistrano flow
after the namespace block add:
# lib/capistrano/tasks/webpack.rake
# ...
after "deploy:updated", "webpack:build"
you can test out task execution with bundle exec cap production deploy --dry-run
Deploying rails app throw Capistrano first time: I deployed my rails app on another machine (server)
File structure for rails app ## this is my server
akshay#akshay:/var/www/model_demo$ ls
current releases repo revisions.log shared
cap -T ## showing a lots of rake task
like
cap deploy:migrate # Runs rake db:migrate if migrations are set
If I run this task it is not working saying
Stage not set, please call something such as `cap production deploy`, where production is a stage you have defined.
But when I run
cap production deploy # It works
Among all the listed task only cap production deploy
1: what exactly going on under the hood?
2: How might i run rake task which is provided by cap?
Any help would be appreciated !!!
Capistrano recepies are meant to run on local system.
Run it locally.
I catch my mistake. And as I followed Railscasts Capistrano screencasts, stackoverflow Capistrano Tags and deploying-rails-apps-to-a-vps-with-capistrano-v3.
As all cap tasks run locally.
cap production deploy:migrate # Worked for me
Thanks to #maxd !!!
I am new to ruby and I want to learn more about how it works. So I have been testing a server configuration in a virtual machine to make quick Rails deployments.
I have RVM, Ruby, Rails, Git, Gitolite, PostgreSQL, Thin and Nginx running in an Ubuntu 10.04 environment.
Now I want to tie everything together. I got stuck, though, in the deployment process.
After I commit the project to the Git trunk, I want to hook a deployment action to put the application in the correct place, set to production, install the bundles, make the migrations and restart Nginx.
But I fail to find simple references on how it works. All I find in google are guides to use passenger, capistrano and others. I want to trigger the deployment on the git commit action, similar to heroku, but what would be the best tools to do that 100% server-side?
What about making some shell scripts? How do I deploy a project manually? What are the steps? Are there any guides out there that do not assume I know every details in Rails deployment?
Thanks!
The think you are probably looking for is a git post-receive hook (a tutorial could be found here: http://toroid.org/ams/git-website-howto).
By this hook you should trigger eg. a shell script which should perform all the steps you need - which are:
checkout HEAD commit from the git repo (git checkout -f, see linked tutorial)
run bundle install
run bundle exec rake db:migrate - this assumed that you have already created your DB
restart/start the Thin server cluster (no sure exactly here, if it is similar to passenger which I use this operation is just to create some restart.txt file) - I presume that you have your nginx as a reverse proxy in front of it, right?
This is the long-story short. It is little bit more complicated, eg. if you use the asset pipeline (rails >= 3.1), you would like to precompile you assets, etc. But the above is a good starting point.
Well, I managed to get it almost completely operational.
The main actions I could trace until now are:
User pushes to trunk, must use git hooks to trigger the next steps using a script.
The script must do the following:
Clone the project to the /var/www folder;
Insert the 'thin' gem into the Gemfile;
Run 'bundle' command in the application folder;
Precompile the assets in the application folder;
Migrate the database;
Stop nginx and thin;
Restart thin and nginx again.
If the application is new, we must also:
Create a new user that matches the database information;
Create the production database;
Insert a new nginx configuration file;
Export the thin configuration from the application folder, like this:
thin config -C /etc/thin/app.yml -c /var/www/app --servers 1 -e production
The sequence of actions is more or less this:
$ bundle package
$ bundle install --deployment
$ RAILS_ENV=production rake db:migrate
$ rake assets:precompile
$ thin start -C /etc/thin/app.yml
This is the basic by now. I want to make it work 100% and then I want to post a guide on the Internet.
Update
The guide I said I would do:
https://github.com/sentient06/RDH/wiki
I am unable to run rake tasks with cron. The error it throws up is:-
/Library/Ruby/Gems/1.8/gems/bundler-1.2.0/lib/bundler/runtime.rb:199: warning: Insecure world writable dir /Library/Ruby/Gems/1.8 in PATH, mode 040777
/Library/Ruby/Gems/1.8/gems/bundler-1.2.0/lib/bundler/spec_set.rb:90:in `materialize': Could not find unf_ext-0.0.5 in any of the sources (Bundler::GemNotFound)
However, when I run the same rake task directly from the terminal, it works fine. In case of the cron job, as well as while running the rake task directly from the terminal, i cd into the (exact) same directory. Starting the rails server works as well.
What is the problem and how should I resolve this?
It could be an issue with your daemon user and your user when you're running it directly. Or it could be a problem with Ruby and/or your cron file commands.
Firstly, use this gem for making cron jobs with rake tasks:
https://github.com/javan/whenever
Then install RVM since you're using the standard ruby library provided by OSX and that can lead to some problems when you're developing various projects. This should fix the permissions error that you have displayed.
I just encountered a subtle issue with capistrano deployment gem dependencies and I would like to enforce how capistrano is invoked.
How can I detect that capistrano was invoked using 'bundle exec' like this:
bundle exec cap app deploy
And not like this:
cap app deploy
I would like to raise an error in the latter case by detecting the method of invocation at the top of my deploy.rb file.
It appears that Bundler sets the $BUNDLE_BIN_PATH and $BUNDLE_GEMFILE environment variables when running executables. For example, do this:
env >/tmp/1
bundler exec env >/tmp/2
diff -u /tmp/[12]
You'll see the differences in the environment.
So then in your deployment script, you can do something like this:
abort "You must run this using 'bundle exec ...'" unless ENV['BUNDLE_BIN_PATH'] || ENV['BUNDLE_GEMFILE']
Hope this helps.