Distribuzione di una sottodirectory Git in Capistrano
-
09-06-2019 - |
Domanda
Il layout del mio ramo principale è così:
/ <- livello superiore
/cliente <-- file di origine del client desktop
/server <--App per le rotaie
Quello che mi piacerebbe fare è solo aprire la directory /server nel mio file deploy.rb
, ma non riesco a trovare alcun modo per farlo.La directory /client è enorme, quindi impostare un hook per copiare /server in / non funzionerà molto bene, è necessario solo estrarre l'app Rails.
Soluzione
Senza alcuna azione di biforcazione sporca ma ancora più sporca!
Nel mio config/deploy.rb:
set :deploy_subdir, "project/subdir"
Quindi ho aggiunto questa nuova strategia al mio 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)
Altri suggerimenti
Per Capistrano 3.0, utilizzo quanto segue:
Nel mio 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
E nel mio 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'
Tutto il codice importante è nella strategia release
metodo, che utilizza git archive
per archiviare solo una sottodirectory del repository, quindi utilizza il file --strip
argomento a tar
per estrarre l'archivio al giusto livello.
AGGIORNAMENTO
A partire da Capistrano 3.3.3, ora puoi utilizzare il file :repo_tree
variabile di configurazione, che rende questa risposta obsoleta.Per esempio:
set :repo_url, 'https://example.com/your_repo.git'
set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo
Vedere http://capistranorb.com/documentation/getting-started/configuration.
Stiamo facendo lo stesso anche con Capistrano clonando l'intero repository, eliminando i file e le cartelle inutilizzati e spostando la cartella desiderata più in alto nella gerarchia.
distribuire.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
Finché il progetto non diventa troppo grande, per noi funziona abbastanza bene, ma se puoi, crea un proprio repository per ciascun componente e raggruppali insieme con i sottomoduli git.
Puoi avere due repository git (client e server) e aggiungerli a un "super-progetto" (app).In questo "super-progetto" puoi aggiungere i due repository come sottomoduli (controlla questo tutorial).
Un'altra possibile soluzione (un po' più sporca) è quella di avere rami separati per client e server, e quindi poter eseguire il pull dal ramo 'server'.
C'è una soluzione.Prendi Crdlo's toppa per capistrano e il fonte capistrano da github.Rimuovi il tuo capistrano gem esistente, applica la patch, installa setup.rb e poi puoi usare la sua semplicissima riga di configurazione set :project, "mysubdirectory"
per impostare una sottodirectory.
L'unico problema è che apparentemente github non "supporta il comando archive"...almeno quando lo scrisse.Sto usando il mio repository Git privato su svn e funziona bene, non l'ho provato con github ma immagino che se un numero sufficiente di persone si lamentasse aggiungeranno quella funzionalità.
Vedi anche se riesci a convincere gli autori di Capistrano ad aggiungere questa funzionalità a cap al bug pertinente.
Per Capistrano 3, basato sulla risposta di @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"
Sfortunatamente, Git non fornisce alcun modo per farlo.Invece, il "metodo git" è avere due repository: client e server, e clonare quello o quelli che ti servono.
Ho creato uno snipped che funziona con Capistrano 3.x in base alle risposte precedenti e ad altre informazioni trovate 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
È disponibile anche come Gist su Github.
Sembra che non funzioni nemmeno con codebasehq.com, quindi ho finito per creare attività di Capistrano che puliscono il caos :-) Forse in realtà c'è un modo meno complicato per farlo sovrascrivendo alcune attività di Capistrano...
Questo ha funzionato per me per alcune ore.
# 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'
Potresti dichiarare una variabile per la directory (qui rails_app).
Vediamo quanto è robusto.Usare "prima" è piuttosto debole.