Bereitstellen eines Git-Unterverzeichnisses in Capistrano
-
09-06-2019 - |
Frage
Mein Master-Branch-Layout sieht so aus:
/ <-- oberste Ebene
/Klient <-- Desktop-Client-Quelldateien
/Server <-- Rails-App
Ich möchte nur das Verzeichnis /server in meinem Verzeichnis herunterziehen deploy.rb
, aber ich kann anscheinend keine Möglichkeit finden, das zu tun.Das /client-Verzeichnis ist riesig, daher funktioniert das Einrichten eines Hooks zum Kopieren von /server nach / nicht sehr gut, es muss nur die Rails-App heruntergezogen werden.
Lösung
Ohne schmutzige Gabelung, aber noch schmutziger!
In meiner config/deploy.rb:
set :deploy_subdir, "project/subdir"
Dann habe ich diese neue Strategie zu meinem Capfile hinzugefügt:
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)
Andere Tipps
Für Capistrano 3.0 verwende ich Folgendes:
In meinem 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
Und in meinem 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'
Der gesamte wichtige Code ist in der Strategie enthalten release
Methode, die verwendet git archive
um nur ein Unterverzeichnis des Repos zu archivieren, verwendet dann das --strip
Argument zu tar
um das Archiv auf der richtigen Ebene zu extrahieren.
AKTUALISIEREN
Ab Capistrano 3.3.3 können Sie jetzt das verwenden :repo_tree
Konfigurationsvariable, was diese Antwort überflüssig macht.Zum Beispiel:
set :repo_url, 'https://example.com/your_repo.git'
set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo
Sehen http://capistranorb.com/documentation/getting-started/configuration.
Wir tun dies auch mit Capistrano, indem wir das gesamte Repository klonen, die nicht verwendeten Dateien und Ordner löschen und den gewünschten Ordner in der Hierarchie nach oben verschieben.
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
Solange das Projekt nicht zu groß wird, funktioniert das für uns ziemlich gut, aber wenn Sie können, erstellen Sie ein eigenes Repository für jede Komponente und gruppieren Sie sie mit Git-Submodulen.
Sie können zwei Git-Repositorys (Client und Server) haben und diese zu einem „Superprojekt“ (App) hinzufügen.In diesem „Superprojekt“ können Sie die beiden Repositories als Submodule hinzufügen (siehe dieses Tutorial).
Eine andere mögliche Lösung (etwas schmutziger) besteht darin, separate Zweige für Client und Server zu haben und dann aus dem Zweig „Server“ zu ziehen.
Es gibt eine Lösung.Schnapp dir Crdlos Patch für Capistrano und das Capistrano-Quelle von Github.Entfernen Sie Ihr vorhandenes Capistrano-Gem, wenden Sie den Patch an, installieren Sie setup.rb, und dann können Sie seine sehr einfache Konfigurationszeile verwenden set :project, "mysubdirectory"
um ein Unterverzeichnis festzulegen.
Das einzige Problem ist, dass Github anscheinend „den Archivierungsbefehl nicht unterstützt“ ...Zumindest als er es schrieb.Ich verwende mein eigenes privates Git-Repo über SVN und es funktioniert gut. Ich habe es nicht mit Github versucht, aber ich kann mir vorstellen, dass sie diese Funktion hinzufügen werden, wenn sich genügend Leute beschweren.
Sehen Sie auch nach, ob Sie Capistrano-Autoren dazu bringen können, diese Funktion in Cap hinzuzufügen am entsprechenden Fehler.
Für Capistrano 3, basierend auf der Antwort von @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"
Leider bietet Git keine Möglichkeit, dies zu tun.Stattdessen besteht der „Git-Weg“ darin, zwei Repositorys zu haben – Client und Server – und die benötigten zu klonen.
Ich habe einen Ausschnitt erstellt, der mit Capistrano 3.x funktioniert, basierend auf früheren Antworten und anderen Informationen 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
Es ist auch als Gist on erhältlich Github.
Sieht so aus, als würde es auch nicht mit codebasehq.com funktionieren, also habe ich am Ende Capistrano-Aufgaben erstellt, die das Chaos beseitigen :-) Vielleicht gibt es tatsächlich eine weniger knifflige Möglichkeit, dies zu tun, indem ich einige Capistrano-Aufgaben überschreibe ...
Bei mir funktioniert das seit ein paar Stunden.
# 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'
Sie können eine Variable für das Verzeichnis deklarieren (hier „rails_app“).
Mal sehen, wie robust es ist.Die Verwendung von „before“ ist ziemlich schwach.