使用Capistrano从不同的Git分支部署

140
我正在使用Capistrano部署RoR应用程序。 代码库在git存储库中,并且在开发中广泛使用分支。 Capistrano使用deploy.rb文件进行设置,其中之一是要部署的分支。
我的问题是这样的:假设我从主干创建一个新的A分支。 部署文件将引用主干分支。 我编辑它,以便可以将A部署到测试环境中。 我完成了这个功能的工作,并将A分支合并到主干分支。 由于A中的deploy.rb文件更加新鲜,因此它被合并,现在master分支中的deploy.rb引用A。 现在需要再次编辑。
这看起来像很多看似不必要的手动编辑 - 参数应始终与当前分支名称匹配。 除此之外,很容易忘记每次都编辑设置。
最佳自动化此过程的方法是什么?
编辑:原来有人已经完全做到了我所需的

This morning I had occasion to deploy a branch of a git repository to a staging server but hadn’t the foggiest idea how. A quick search through the capistrano source code revealed that I could use set :branch "branch_name" in my deploy script. I tried it and it worked. I then figured I would need to make a similar change across all my branches. Of course, I’m a lazy sod and wondered if there wasn’t a better way.

If you’re not familiar with git, the output of the git branch command is a list of branches with an asterisk marking the one currently checked out on your local machine. For example:

> git branch
* drupal_authentication
fragment_caching
master

So, I figured, what if I just parsed the output and searched for the branch marked as current:

set :branch, $1 if `git branch` =~ /\* (\S+)\s/m

Now I’m able to deploy whatever branch is current on my local machine from a single, shared, deploy script.


这是更新后的链接:使用Capistrano部署分支 - wacko
13个回答

183

这适用于 Capistrano >= 3.1:

config/deploy.rb 中添加以下行:

set :branch, ENV['BRANCH'] if ENV['BRANCH']

然后使用以下命令调用Capistrano:

cap production deploy BRANCH=master

这个解决方案适用于 Capistrano < 3.1:

# call with cap -s env="<env>" branch="<branchname>" deploy

set :branch, fetch(:branch, "master")
set :env, fetch(:env, "production")

4
如果使用mustistage扩展,无需设置env,但是我只使用一个分支就使其生效。 - Tom Harrison
根据@lulalala的说法,我需要使用小写-s才能获取指定的分支。 - Jahan Zinedine
@Jani:谢谢,看起来他们在更新的Capistrano版本中进行了更改,我已相应地编辑了我的答案。 - wintersolutions
我遇到的问题与@Jani完全相反:当使用fetch(:var_name,'default')获取参数时,我必须将-S大写,否则参数无法传递给cap。 - Frederik Struck-Schøning
1
选项“-s”(--set)表示“在加载配方后设置变量”,而选项“S”(--set-before)表示“在加载配方之前设置变量”。 - Ramon Caldeira

35

使用Capistrano 3.1.0+,这些方法都不能再起作用了。相反,按照他们的注释说明:

   ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }

但是,您不想使用ask,否则它会提示您。相反,您应该使用setHEAD是最顶层的分支; 也称为“边缘”。如果您想要不同的分支,请使用您的分支名称替换HEAD,例如:masterstaging等。
举个例子,在/config/deploy/production.rb中,您可能包含以下行:
   set :branch, proc { `git rev-parse --abbrev-ref master`.chomp }

...or

   set :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }

顺便提一下,HEAD 是默认设置,因此在文件中不需要真正说明。可能更好地在 /config/deploy/edge.rb 中使用。

/config/deploy/staging.rb 中,您可以包含以下行:

   set :branch, proc { `git rev-parse --abbrev-ref staging`.chomp }

...or

   set :branch, proc { `git rev-parse --abbrev-ref test`.chomp }

你明白了!

我希望这些例子能够帮助未来使用 capistrano 的用户 (^_^)


7
git rev-parse --abbrev-ref HEAD 用于查找当前所在的分支名。运行 git rev-parse --abbrev-ref staging 会(几乎)总是输出 staging。你可以直接使用 set :branch, 'staging' - MiniGod

33
我可以确认以下内容在Cap 3.11.0 13/10/18版本以及Cap 2版本中仍然有效:
在deploy.rb / stage.rb文件中:
set :branch, ENV['BRANCH'] || 'develop'

在命令行上:

cap deploy BRANCH=featurex
这为您提供了一个默认分支(在不同环境下可能会有所不同),并且使您能够在需要时更改分支。

28

使用多阶段构建,现在实际上是这样的:

cap production deploy -s branch=my-branch

之前的帖子语法在我的环境中不起作用


1
在加载配方后,“-s branch=foo”将capistrano变量branch设置为“foo”。 - alvin

15

或者你可以从命令行对其进行结构化,其中你有一个默认的分支和环境,并且还可以向cap调用传递参数,其中包括要使用的环境和分支。这可以是显式传递的分支,或者您可以拥有一个参数,该参数将指示当前分支,如您列出的链接中所述。

#call with cap -S env="<env>" branch="<branchname>" deploy
...

# Prevents error if not parameter passed, assumes that default 'cap deploy' command
# and should deploy the master branch to the production server
set(:env, ‘production’) unless exists?(:env)
set(:branch, ‘master’) unless exists?(:branch)

if !env.nil? && env == "production"
   role :web, "production_ip_address"
else   # add more as needed 
   role :web, "development_ip_address"
end

if !branch.nil? && branch == "current"
   set :branch, $1 if `git branch` =~ /\* (\S+)\s/m
elsif !branch.nil?
   set :branch, branch
else   # add more as needed 
   set :branch, "master"
end
...

这里借鉴了许多代码示例


3
为了获取指定的分支,我需要使用小写字母s - lulalala
我遇到的问题与@lulula完全相反:当使用fetch(:var_name,'default')获取参数时,我必须将-S大写,否则参数无法传递给cap。 - Frederik Struck-Schøning

10

如果您正在使用capistrano-multistage,则只需要运行:

cap -s branch=$MY_BRANCH deploy

或者

cap -s branch=$MY_BRANCH production deploy

不需要对你的deploy.rb进行任何进一步的编辑。


2
应该是 branch=,而不是 branch- - Jimothy
3
OptionParser::AmbiguousOption: ambiguous option: -s
翻译:OptionParser::AmbiguousOption:选项模糊:-s
- giorgio

9
这个命令已经没法使用了:
cap deploy -s branch=your_branch

在 capistrano v3+ 中,不再支持使用 -sS 标志。
您可以在这里阅读有关此问题的更多信息:link
它在一些答案中提到了,但目前不正确。

对我有效的解决方法是:
deploy.rb 文件中添加以下代码:

set :branch, ENV['BRANCH'] || :master

接着运行:

BRANCH=your_branch cap deploy

请注意,在运行此命令时,您需要在主分支上才能成功运行。


4

我使用的是3.3.5版本,并且我已经成功地运行了以下代码:

set :branch, 'develop'

3
此解决方案适用于所有版本的Capistrano。
def branch_name(default_branch)
  branch = ENV.fetch('BRANCH', default_branch)

  if branch == '.'
    # current branch
    `git rev-parse --abbrev-ref HEAD`.chomp
  else
    branch
  end
end

set :branch, branch_name('master')

使用方法:

BRANCH=. cap [staging] deploy
# => deploy current branch

BRANCH=master cap [staging] deploy
# => deploy master branch

cap [staging] deploy
# => deploy default branch

2

方法一:为部署设置特定阶段的分支(例如测试,生产)

branch 配置放在阶段文件中而不是 'deploy.rb' 中,并设置该阶段的目标分支以进行部署。

对于具有相关分支名称 testproduction 的两个阶段应用程序,配置如下:

# app_root/config/deploy/test.rb
...
set :branch, "test"
...

# app_root/config/deploy/production.rb
...
set :branch, "production"
...

这个方法可以让你从特定阶段的分支部署。因此,唯一需要的额外步骤是将最新的代码从基础分支合并或变基。
第二种方法是使用标签直接部署。为了使用标签进行部署,请在“deploy.rb”中设置“branch”配置如下:
set :branch, `git describe --tags $(git rev-list --tags --max-count=1)`.chomp

同时,配置CI以条件地部署到不同的阶段,如果关联标签模式匹配(例如/.*-test$/)。

现在,可以从任何分支进行部署,

  • 首先,从任何分支创建一个标签,

    git tag -a v0.1.0-test -m“版本0.1.0-test”

  • 然后,推送

    git push origin v0.1.0-test

注意:上述方法基于Capistrano 3。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接