Implementación de un subdirectorio Git en Capistrano
-
09-06-2019 - |
Pregunta
El diseño de mi rama maestra es así:
/ <-- nivel superior
/cliente <-- archivos fuente del cliente de escritorio
/servidor <-- Aplicación Rails
Lo que me gustaría hacer es simplemente desplegar el directorio /server en mi deploy.rb
, pero parece que no puedo encontrar ninguna manera de hacerlo.El directorio /cliente es enorme, por lo que configurar un enlace para copiar /servidor a / no funcionará muy bien, solo necesita desplegar la aplicación Rails.
Solución
¡Sin ninguna acción de bifurcación sucia pero aún más sucia!
En mi config/deploy.rb:
set :deploy_subdir, "project/subdir"
Luego agregué esta nueva estrategia a mi 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)
Otros consejos
Para Capistrano 3.0, uso lo siguiente:
En mi 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
y en mi 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'
Todo el código importante está en la estrategia. release
método, que utiliza git archive
para archivar solo un subdirectorio del repositorio, luego usa el --strip
argumento para tar
para extraer el archivo en el nivel correcto.
ACTUALIZAR
A partir de Capistrano 3.3.3, ahora puede utilizar el :repo_tree
variable de configuración, lo que hace que esta respuesta quede obsoleta.Por ejemplo:
set :repo_url, 'https://example.com/your_repo.git'
set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo
Ver http://capistranorb.com/documentation/getting-started/configuration.
También estamos haciendo esto con Capistrano clonando el repositorio completo, eliminando los archivos y carpetas no utilizados y moviendo la carpeta deseada hacia arriba en la jerarquía.
desplegar.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
Siempre que el proyecto no crezca demasiado, esto funciona bastante bien para nosotros, pero si puede, cree un repositorio propio para cada componente y agrúpelos con submódulos de git.
Puede tener dos repositorios de git (cliente y servidor) y agregarlos a un "superproyecto" (aplicación).En este "superproyecto" puedes agregar los dos repositorios como submódulos (consulta este tutorial).
Otra posible solución (un poco más sucia) es tener ramas separadas para el cliente y el servidor, y luego poder extraer datos de la rama 'servidor'.
Hay una solucion.Agarra crdlo's parche para capistrano y el fuente capistrano desde github.Elimine su gema capistrano existente, aplique el parche, instale setup.rb y luego podrá usar su línea de configuración muy simple. set :project, "mysubdirectory"
para establecer un subdirectorio.
El único problema es que aparentemente github no "admite el comando de archivo"...al menos cuando lo escribió.Estoy usando mi propio repositorio privado de git sobre svn y funciona bien, no lo he probado con github pero imagino que si suficientes personas se quejan, agregarán esa característica.
Vea también si puede conseguir que los autores de Capistrano agreguen esta función a cap en el error relevante.
Para Capistrano 3, basado en la respuesta 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"
Desafortunadamente, git no proporciona ninguna forma de hacer esto.En cambio, la 'forma git' es tener dos repositorios: cliente y servidor, y clonar los que necesite.
Creé un recorte que funciona con Capistrano 3.x según respuestas anteriores y otra información encontrada en 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
También está disponible como Gist en GitHub.
Parece que tampoco funciona con codebasehq.com, así que terminé creando tareas de capistrano que limpian el desorden :-) Tal vez en realidad haya una forma menos complicada de hacer esto anulando algunas tareas de capistrano...
Esto ha estado funcionando para mí durante algunas horas.
# 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'
Podrías declarar una variable para el directorio (aquí rails_app).
Veamos qué tan robusto es.Usar "antes" es bastante débil.