Déployer un sous-répertoire Git dans Capistrano
-
09-06-2019 - |
Question
La disposition de ma branche principale ressemble à ceci :
/ <-- niveau supérieur
/client <-- fichiers sources du client de bureau
/serveur <-- Application Rails
Ce que j'aimerais faire, c'est uniquement dérouler le répertoire /server dans mon deploy.rb
, mais je n'arrive pas à trouver un moyen de le faire.Le répertoire /client est énorme, donc configurer un hook pour copier /server vers / ne fonctionnera pas très bien, il suffit de dérouler l'application Rails.
La solution
Sans aucune sale action de fourche mais encore plus sale !
Dans mon config/deploy.rb :
set :deploy_subdir, "project/subdir"
Ensuite j'ai ajouté cette nouvelle stratégie à mon 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)
Autres conseils
Pour Capistrano 3.0, j'utilise ce qui suit :
Dans mon 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
Et dans mon 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'
Tout le code important est dans la stratégie release
méthode qui utilise git archive
pour archiver uniquement un sous-répertoire du dépôt, puis utilise le --strip
argument à tar
pour extraire l'archive au bon niveau.
MISE À JOUR
Depuis Capistrano 3.3.3, vous pouvez désormais utiliser le :repo_tree
variable de configuration, ce qui rend cette réponse obsolète.Par exemple:
set :repo_url, 'https://example.com/your_repo.git'
set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo
Voir http://capistranorb.com/documentation/getting-started/configuration.
Nous faisons également cela avec Capistrano en clonant le référentiel complet, en supprimant les fichiers et dossiers inutilisés et en déplaçant le dossier souhaité vers le haut de la hiérarchie.
déployer.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
Tant que le projet ne devient pas trop gros, cela fonctionne plutôt bien pour nous, mais si vous le pouvez, créez votre propre référentiel pour chaque composant et regroupez-les avec des sous-modules git.
Vous pouvez avoir deux référentiels git (client et serveur) et les ajouter à un "super-projet" (application).Dans ce "super-projet" vous pouvez ajouter les deux référentiels en tant que sous-modules (cochez ce tutoriel).
Une autre solution possible (un peu plus sale) consiste à avoir des branches distinctes pour le client et le serveur, puis à extraire de la branche « serveur ».
Il existe une solution.Prenez les crdlo patch pour Capistrano et le source capistrano de github.Supprimez votre gemme Capistrano existante, appliquez le correctif, installez setup.rb, puis vous pourrez utiliser sa ligne de configuration très simple. set :project, "mysubdirectory"
pour définir un sous-répertoire.
Le seul problème est qu'apparemment, github ne "prend pas en charge la commande archive"...du moins quand il l'a écrit.J'utilise mon propre dépôt git privé sur svn et cela fonctionne bien, je ne l'ai pas essayé avec github mais j'imagine que si suffisamment de personnes se plaignent, elles ajouteront cette fonctionnalité.
Vérifiez également si vous pouvez demander aux auteurs de Capistrano d'ajouter cette fonctionnalité dans Cap. au bug concerné.
Pour Capistrano 3, basé sur la réponse de @Thomas Fankhauser :
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"
Malheureusement, git ne fournit aucun moyen de le faire.Au lieu de cela, la « méthode git » consiste à avoir deux référentiels – client et serveur, et à cloner celui(s) dont vous avez besoin.
J'ai créé un extrait qui fonctionne avec Capistrano 3.x basé sur les réponses précédentes et d'autres informations trouvées dans 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
Il est également disponible en résumé sur GitHub.
On dirait que cela ne fonctionne pas non plus avec codebasehq.com, j'ai donc fini par créer des tâches Capistrano qui nettoient les dégâts :-) Peut-être qu'il existe en fait une façon moins compliquée de procéder en remplaçant certaines tâches Capistrano...
Cela fonctionne pour moi depuis quelques heures.
# 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'
Vous pouvez déclarer une variable pour le répertoire (ici rails_app).
Voyons à quel point il est robuste.Utiliser "avant" est assez faible.