Can you make folder with rake build? - ruby-on-rails

I have no experience with Ruby or rake or anything, but I am using slate for API documentation, and it uses Ruby and rake and stuff to build the file. I know nothing at all about these things, but what I do know is this: when I do a rake build it updates a folder (slate/build). I then have to manually copy slate/build to ../app/docs after every single rake build. Is there something I can do that will copy that folder on every rake build automatically for me?

Add to your Rakefile:
ROOT = File.expand_path('..', __FILE__)
task :build_and_move => [:build] do
cp_r(File.join(ROOT, 'slate/build'), File.join(ROOT, '../app/docs'))
# or
# mv(File.join(ROOT, 'slate/build'), File.join(ROOT, '../app/docs'))
end
and then run rake build_and_move.

You can use FileUtils for this.
Docs: http://ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html#method-c-copy
Example from the docs:
Copies src to dest. If src is a directory, this method copies all its contents recursively. If dest is a directory, copies src to dest/src.
FileUtils.cp 'eval.c', 'eval.c.org'
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true
FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink

Related

Rails: create symlink with capistrano before initializer from config/initializers is executed

I have a capistrano task that is executed like this in deploy.rb:
after 'deploy:update_code', 'deploy:create_symlink'
The task:
Capistrano::Configuration.instance.load do
namespace :deploy do
task :create_symlink do
run "touch #{shared_path}/somefile.yml"
run "ln -nfs #{shared_path}/somefile.yml #{release_path}/config/somefile.yml"
end
end
end
configs are loaded from somefile.yml like this:
customconf = OpenStruct.new(YAML::load_file(File.join(Rails.root, 'config', 'somefile.yml'))[Rails.env]||{})
The issue that I'm having is that the configs are loaded in config/initializers/customconfig.rb. but the symlink seems to be created after the code in customconfig.rb is created.
This is the error I'm getting when trying to cap deploy:
Errno::ENOENT: No such file or directory - /var/www/vhosts/mysite/rails/releases/20170705083649/config/somefile.yml
Basically how can I load the configs from somefile.yml after the symlink is created. Or how can I run the cap task before the initializer is executed?
I solved my issue by changing after 'deploy:update_code' to after after 'deploy:finalize_update'. But I want to ask if this is the correct way of doing it before I accept this as accepted answer.

Add TODO list (rake notes) output to source control

I want my TODO list which I get as output of 'rake notes' to be under source control (Git).
Is there a way I can configure 'rake notes' to spit out out a text file which can be under source control?
Not completely understanding your question's direction, so I'll just go from the beginning. :)
Create a rake file :)
The most common is under Rails.root / lib, but it's preferable (depending on Elitests or purists) to put it under lib/tasks/output_notes.rake (yes, .rake, not .rb)
Rake scripts have namespaces. "db" is a namespace for running "rake db:migrate" for example. You can see some examples here: https://github.com/rails/rails/tree/master/railties/lib/rails/tasks
Your script might look something like this.
namespace :vasa do
desc "Output notes"
task :output_notes do
output_file_name = "#{DateTime.now.to_i}_notes.txt"
File.open(output_file_name, 'w') { |file| file.write(Note.dump_all) }
end
end
You can then run rake vasa:output_notes. Want to add the file to your repo automagically?
# after File.open ...
`
git add #{output_file_name}
git commit -m "added notes"
`
The backticks will run it as a system command.

rake task that writes to file on local filesystem and not heroku

I would like a rake task that gets some information and then writes to the local filesytem
I thought I had this working but not sure how.
namespace :arc do
task :vday => :environment do
locations=Location.with_current_mec "something"
jt={}
jt[:locations]={}
locations.each do |location|
jt[:locations][location.id]=location.to_small_hash
end
# want this to write to local filesytem
File.write('/Users/jt/output.json', JSON.pretty_generate(jt))
end
end
and then call like
heroku run rake arc:vday
But this is not working and gives me an error on writing the file. Is there a workaround to make it write to my local filesystem and not heroku?
Can you try this
File.open('/Users/jt/output.json', 'w') {|file| file.write(JSON.pretty_generate(jt))}
instead of
File.write('/Users/jt/output.json', JSON.pretty_generate(jt))

Capistrano: deploy.rb file refactoring

I have following code in my deploy.rb
namespace :app do
desc "copies the configuration frile from ~/shared/config/*.yml to ~/config"
task :copy_config_files,:roles => :app do
run "cp -fv #{deploy_to}/shared/config/hoptoad.rb #{release_path}/config/initializers"
run "cp -fv #{deploy_to}/shared/config/app_config.yml #{release_path}/config/app_config.yml"
end
end
I thought it would be a good idea to keep my deploy.rb file clean and I attempted to move above code to capistrano_utilities.rb under config. I am using Rails application. And I added following line of code to deploy.rb
require File.expand_path(File.dirname(__FILE__) + "/../lib/capistrano_utilities")
Now I am getting following error.
undefined method `namespace' for main:Object (NoMethodError)
The value of self in the deploy.rb is Capistrano::Configuration . While the value of self in capistrano_utilities is Main. So I understand why I am getting namespace method error. What is the fix for this problem?
In your config/deploy.rb, try load instead of require. Also, capistrano already runs as if you're at the RAILS_ROOT, so there's no need to use __FILE__:
load "lib/capistrano_utilities"
In a capistrano config file, load is redefined to load another configuration file into the current configuration. When passing a path to it, it actually calls load_from_file (a private method defined by capistrano) that just reads the file from disk and instance_eval's it.
Check your Capfile on Rails.root.
if you use capistrano 3, you see this line;
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
Now, put your file on "lib/capistrano/tasks/capistrano_utilities.cap" and it will be loaded.

Deploying a Git subdirectory in Capistrano

My master branch layout is like this:
/ <-- top level
/client <-- desktop client source files
/server <-- Rails app
What I'd like to do is only pull down the /server directory in my deploy.rb, but I can't seem to find any way to do that. The /client directory is huge, so setting up a hook to copy /server to / won't work very well, it needs to only pull down the Rails app.
Without any dirty forking action but even dirtier !
In my config/deploy.rb :
set :deploy_subdir, "project/subdir"
Then I added this new strategy to my Capfile :
require 'capistrano/recipes/deploy/strategy/remote_cache'
class RemoteCacheSubdir < Capistrano::Deploy::Strategy::RemoteCache
private
def repository_cache_subdir
if configuration[:deploy_subdir] then
File.join(repository_cache, configuration[:deploy_subdir])
else
repository_cache
end
end
def copy_repository_cache
logger.trace "copying the cached version to #{configuration[:release_path]}"
if copy_exclude.empty?
run "cp -RPp #{repository_cache_subdir} #{configuration[:release_path]} && #{mark}"
else
exclusions = copy_exclude.map { |e| "--exclude=\"#{e}\"" }.join(' ')
run "rsync -lrpt #{exclusions} #{repository_cache_subdir}/* #{configuration[:release_path]} && #{mark}"
end
end
end
set :strategy, RemoteCacheSubdir.new(self)
For Capistrano 3.0, I use the following:
In my Capfile:
# Define a new SCM strategy, so we can deploy only a subdirectory of our repo.
module RemoteCacheWithProjectRootStrategy
def test
test! " [ -f #{repo_path}/HEAD ] "
end
def check
test! :git, :'ls-remote', repo_url
end
def clone
git :clone, '--mirror', repo_url, repo_path
end
def update
git :remote, :update
end
def release
git :archive, fetch(:branch), fetch(:project_root), '| tar -x -C', release_path, "--strip=#{fetch(:project_root).count('/')+1}"
end
end
And in my deploy.rb:
# Set up a strategy to deploy only a project directory (not the whole repo)
set :git_strategy, RemoteCacheWithProjectRootStrategy
set :project_root, 'relative/path/from/your/repo'
All the important code is in the strategy release method, which uses git archive to archive only a subdirectory of the repo, then uses the --strip argument to tar to extract the archive at the right level.
UPDATE
As of Capistrano 3.3.3, you can now use the :repo_tree configuration variable, which makes this answer obsolete. For example:
set :repo_url, 'https://example.com/your_repo.git'
set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo
See http://capistranorb.com/documentation/getting-started/configuration.
We're also doing this with Capistrano by cloning down the full repository, deleting the unused files and folders and move the desired folder up the hierarchy.
deploy.rb
set :repository, "git#github.com:name/project.git"
set :branch, "master"
set :subdir, "server"
after "deploy:update_code", "deploy:checkout_subdir"
namespace :deploy do
desc "Checkout subdirectory and delete all the other stuff"
task :checkout_subdir do
run "mv #{current_release}/#{subdir}/ /tmp && rm -rf #{current_release}/* && mv /tmp/#{subdir}/* #{current_release}"
end
end
As long as the project doesn't get too big this works pretty good for us, but if you can, create an own repository for each component and group them together with git submodules.
You can have two git repositories (client and server) and add them to a "super-project" (app). In this "super-project" you can add the two repositories as submodules (check this tutorial).
Another possible solution (a bit more dirty) is to have separate branches for client and server, and then you can pull from the 'server' branch.
There is a solution. Grab crdlo's patch for capistrano and the capistrano source from github. Remove your existing capistrano gem, appy the patch, setup.rb install, and then you can use his very simple configuration line set :project, "mysubdirectory" to set a subdirectory.
The only gotcha is that apparently github doesn't "support the archive command" ... at least when he wrote it. I'm using my own private git repo over svn and it works fine, I haven't tried it with github but I imagine if enough people complain they'll add that feature.
Also see if you can get capistrano authors to add this feature into cap at the relevant bug.
For Capistrano 3, based on #Thomas Fankhauser answer:
set :repository, "git#github.com:name/project.git"
set :branch, "master"
set :subdir, "relative_path_to_my/subdir"
namespace :deploy do
desc "Checkout subdirectory and delete all the other stuff"
task :checkout_subdir do
subdir = fetch(:subdir)
subdir_last_folder = File.basename(subdir)
release_subdir_path = File.join(release_path, subdir)
tmp_base_folder = File.join("/tmp", "capistrano_subdir_hack")
tmp_destination = File.join(tmp_base_folder, subdir_last_folder)
cmd = []
# Settings for my-zsh
# cmd << "unsetopt nomatch && setopt rmstarsilent"
# create temporary folder
cmd << "mkdir -p #{tmp_base_folder}"
# delete previous temporary files
cmd << "rm -rf #{tmp_base_folder}/*"
# move subdir contents to tmp
cmd << "mv #{release_subdir_path}/ #{tmp_destination}"
# delete contents inside release
cmd << "rm -rf #{release_path}/*"
# move subdir contents to release
cmd << "mv #{tmp_destination}/* #{release_path}"
cmd = cmd.join(" && ")
on roles(:app) do
within release_path do
execute cmd
end
end
end
end
after "deploy:updating", "deploy:checkout_subdir"
Unfortunately, git provides no way to do this. Instead, the 'git way' is to have two repositories -- client and server, and clone the one(s) you need.
I created a snipped that works with Capistrano 3.x based in previous anwers and other information found in github:
# Usage:
# 1. Drop this file into lib/capistrano/remote_cache_with_project_root_strategy.rb
# 2. Add the following to your Capfile:
# require 'capistrano/git'
# require './lib/capistrano/remote_cache_with_project_root_strategy'
# 3. Add the following to your config/deploy.rb
# set :git_strategy, RemoteCacheWithProjectRootStrategy
# set :project_root, 'subdir/path'
# Define a new SCM strategy, so we can deploy only a subdirectory of our repo.
module RemoteCacheWithProjectRootStrategy
include Capistrano::Git::DefaultStrategy
def test
test! " [ -f #{repo_path}/HEAD ] "
end
def check
test! :git, :'ls-remote -h', repo_url
end
def clone
git :clone, '--mirror', repo_url, repo_path
end
def update
git :remote, :update
end
def release
git :archive, fetch(:branch), fetch(:project_root), '| tar -x -C', release_path, "--strip=#{fetch(:project_root).count('/')+1}"
end
end
It's also available as a Gist on Github.
dont know if anyone is still interested on this. but just letting you guys if anyone is looking for an answer.
now we can use: :repo_tree
https://capistranorb.com/documentation/getting-started/configuration/
Looks like it's also not working with codebasehq.com so I ended up making capistrano tasks that cleans the mess :-) Maybe there's actually a less hacky way of doing this by overriding some capistrano tasks...
This has been working for me for a few hours.
# Capistrano assumes that the repository root is Rails.root
namespace :uploads do
# We have the Rails application in a subdirectory rails_app
# Capistrano doesn't provide an elegant way to deal with that
# for the git case. (For subversion it is straightforward.)
task :mv_rails_app_dir, :roles => :app do
run "mv #{release_path}/rails_app/* #{release_path}/ "
end
end
before 'deploy:finalize_update', 'uploads:mv_rails_app_dir'
You might declare a variable for the directory (here rails_app).
Let's see how robust it is. Using "before" is pretty weak.

Resources