Reputation: 677
I'm looking to build a nice little Capistrano recipe for deploying sites version controlled in Git.
In addition to some other things I'm working on adding, my first task is to tag the current release with the current date...and when that tag already exists (e.g. multiple releases in a day), append a letter.
I've written some working code, and I've tested it in my production.rb (using multistage in capistrano-ext)...but I have to think I could have written this better. For one, there's some huge repetition in the actual checking for existence of a tag. However, no matter what order I move things around, this is the only configuration that produces results.
Any ideas? Thanks in advance.
before 'deploy' do
# Tag name is build_YYYYMMDD
tag_name = "build_#{Time.now.strftime('%Y%m%d')}"
check_tag = `git tag -l #{tag_name}`
# If the tag exists, being appending letter suffix
if not check_tag.empty?
suffix = 'a'
check_tag = `git tag -l #{tag_name}#{suffix}`
while not check_tag.empty? do
suffix.next!
check_tag = `git tag -l #{tag_name}#{suffix}`
end
tag_name = "#{tag_name}#{suffix}"
end
# Tag with computed tag name
p "Tagging #{tag_name}" # TODO How to output via Capistrano?
system "git tag #{tag_name}"
# Push tags to origin remote
p "Pushing tag to origin" # TODO How to output via Capistrano?
system "git push origin master --tags"
end
Upvotes: 13
Views: 5524
Reputation: 1151
This updated version of the accepted answer worked for me:
desc 'Tag the deployed revision'
task :push_deploy_tag do
env = fetch(:rails_env)
timestamp = fetch(:release_timestamp)
user = `git config --get user.name`.chomp
email = `git config --get user.email`.chomp
puts `git tag #{env}-#{timestamp} #{fetch :current_revision} -m "Deployed by #{user} <#{email}>"`
puts `git push --tags origin`
end
Upvotes: 0
Reputation: 988
Thanks to @dunedain289 for a great answer. I took it a step further to try replicate heroku releases for capistrano. I needed a nice tool to know what was already deployed on the servers, and to make a diff with my current local branch:
first, use @dunedain289's code, slightly modified to work for me
task :push_deploy_tag do
user = `git config --get user.name`.chomp
email = `git config --get user.email`.chomp
stage = "production" unless stage # hack, stage undefined for me
puts `git tag #{stage}_#{release_name} -m "Deployed by #{user} <#{email}>"`
puts `git push --tags origin`
end
Add a task to filter the release tags and diff the last
task :diff do
stage = "production" unless stage
last_stage_tag = `git tag -l #{stage}* | tail -1`
system("git diff #{last_stage_tag}", out: $stdout, err: :out)
end
#this preserves coloring if you have a .gitconfig with
[color "diff"]
meta = yellow bold
frag = magenta bold
old = red bold
new = green bold
execute
$ cap diff
# awesome colored diff of production and local
Upvotes: 3
Reputation: 515
Regarding your question in the code about how to output the text via Capistrano. Just change p to puts and it displays fine.
Upvotes: 1
Reputation: 129584
Just add the short hash of the commit you are building from.
git log -1 --format=%h
Upvotes: 3
Reputation: 2388
I've done something similar with Capistrano. The easiest thing to do is tag using the timestamp name that Capistrano used during the deploy - that's YYYYMMDDHHMMSS, so it's really hard to get duplicates.
Example:
task :push_deploy_tag do
user = `git config --get user.name`.chomp
email = `git config --get user.email`.chomp
puts `git tag #{stage}_#{release_name} #{current_revision} -m "Deployed by #{user} <#{email}>"`
puts `git push --tags origin`
end
Upvotes: 24