21 Commits
0.7.0 ... 0.9.1

Author SHA1 Message Date
Karl Matthias
90177a7ff5 Rev for bugifxed release 0.9.1. 2014-01-14 20:17:01 -08:00
Karl Matthias
257b59c37d Rev for release 0.9.0. 2014-01-13 21:14:29 -08:00
Karl Matthias
b5b1cae948 Fix a bunch of test failures due to new git fetch code. 2014-01-13 21:06:45 -08:00
Karl Matthias
72224b2d96 Add test for validating git fetch. 2014-01-13 20:57:13 -08:00
Karl Matthias
d5a6d036c9 Merge pull request #17 from aspiers/master
correctly handle failing git fetch
2014-01-13 20:39:04 -08:00
Adam Spiers
c247629356 correctly handle failing git fetch
If the repository doesn't have an upstream branch configured, git fetch
will output an error; handle this separately to prevent it interfering
with the git diff call which checks to see if we have any pending
changes.
2013-12-13 11:53:56 +00:00
Karl Matthias
b8b4ffce03 Added information about running deployments from Jenkins. 2013-11-19 15:43:01 -08:00
Karl Matthias
bcecbcc885 Added utc to the tag to make the change obvious. 2013-10-16 11:36:54 -07:00
relistan
85a7fcd2f4 Merge pull request #15 from tute/patch-1
Use UTC timestamp for teams in different timezones [fixes #14]
2013-10-16 11:30:23 -07:00
Tute Costa
368ec7e2a2 Use UTC timestamp for teams in different timezones [fixes #14] 2013-10-11 23:25:57 +02:00
Karl Matthias
06b6042ab9 Rev for release 0.8.0. 2013-08-27 15:24:18 +01:00
Karl Matthias
b0133c88c0 Use a configurable remote, or default to the first in git remote list.
Also, don't use double quotes where we don't need them.
2013-08-27 15:22:53 +01:00
Karl Matthias
e934cead87 Make it explicit that the plugin will do a git pull. 2013-08-27 14:28:24 +01:00
Karl Matthias
2dbec99914 Documenation bug fix. 2013-08-27 12:23:15 +01:00
Karl Matthias
c24bab3f37 Further documentation improvements. 2013-08-27 12:22:28 +01:00
Karl Matthias
3c6fc42623 Added explanation of how to disable tagging in the README. 2013-08-27 12:20:42 +01:00
Karl Matthias
bb520be7e3 Add ability to disable all tagging/git checking based on a setting. 2013-08-27 12:15:34 +01:00
Karl Matthias
a24c306e6b Updated README to talk about editing deployment scripts. 2013-08-27 11:53:38 +01:00
Karl Matthias
221b7246c1 Added clarification on deployment history. 2013-07-29 12:08:14 +01:00
Karl Matthias
b85a7a3e48 Added info to README on how to show your deployment history. 2013-07-29 12:06:33 +01:00
Karl Matthias
01f5e36a89 Update on deploying a previous commit. 2013-05-15 09:09:47 +01:00
4 changed files with 171 additions and 25 deletions

View File

@@ -39,19 +39,78 @@ In your Capistrano `config/deploy.rb` you should add:
This will create two tasks, one that runs before deployment and one
that runs after.
NOTE: You will be creating and pushing tags from the version of the
code in the current checkout. This plugin needs to be run from a
clean checkout of your codebase. You should be deploying from a
clean checkout anyway, so in most cases this is not a restriction
on how you already do things. The plugin will check if your code
is clean and complain if it is not.
*NOTE:* You will be creating and pushing tags from the version of the code in the
current checkout. This plugin needs to be run from a clean checkout of your
codebase. You should be deploying from a clean checkout anyway, so in most
cases this is not a restriction on how you already do things. The plugin will
check if your code is clean and complain if it is not.
*ALSO:* The plugin will do a pull to make sure you have the code on your local
system that will actually be deployed before checking the tree for changes.
Know this ahead of time as this may affect how you deal with your deployment
branches.
Setting the Remote
------------------
By default, Capistrano Deploytags will use the first remote in the list returned
by `git remote`. If you prefer to use a different remote, then you may change the
`:git_remote` setting from your `deploy.rb`, the stage, or on the command line with
`-S git_remote=your-remote`.
Working on Your Deployment Scripts
----------------------------------
Because you must have a clean tree to deploy, working on your deployment
scripts themselves can be a bit frustrating unless you know how to make it
work. The easiest way around this problem is to simply commit your changes
before you deploy. You do not have to push them. The plugin will then
happily carry on deploying without complaint.
Alternatively, you could disable the plugin temporarily with one of the
methods described below.
Disabling Tagging for a Stage
-----------------------------
Sometimes you do not want to enable deployment tagging for a particular
stage. In that event, you can simply disable tagging by setting `no_deploytags`
lik so:
```ruby
set :no_deploytags, true
```
You can also set this from the command line at any time with `-S no_deploytags=true`.
*NOTE:* this will disable the use of the plugin's functionality entirely for
that stage. The tasks will run, but will do nothing. This means that tasks that
are hooked to the Capistrano Deploytags tasks will also still run, but they may
find their expectations are not met with regards to the cleanliness of the git
tree.
Viewing Deployment History
--------------------------
It's trivial to view the deployment history for a repo. From a checkout
of the repo, type `git tag -l -n1`. The output looks something like:
```
dev-2013.07.22-105130 baz deployed a4d522d9d to dev
dev-2013.07.22-113207 karl deployed 4c43f8464 to dev
dev-2013.07.22-114437 gavin deployed 776e15414 to dev
dev-2013.07.22-115103 karl deployed 619ff5724 to dev
dev-2013.07.22-144121 joshmyers deployed cf1ed1a02 to dev
```
A little use of `grep` and you can easily get the history for a
particular (e.g. `git tag -l -n1 | grep dev`).
It should be noted that the names used when tags are created are the
local user name on the box where the deployment is done.
Helpful Git Config
------------------
You might find it useful to add this to your ~/.gitconfig in order
to get a nice history view of the commits and tags.
```
```ini
[alias]
lol = log --pretty=oneline --abbrev-commit --graph --decorate
```
@@ -59,6 +118,22 @@ to get a nice history view of the commits and tags.
You can then view the list by typing `git lol` from the checked out
code path.
Deploying a Previous Commit
---------------------------
Because you have to actually be on the head of the branch you are
deploying in order for tagging to work properly, deploying a previous
commit doesn't work as you might expect. The simple solution is to
create a new branch from the previous commit you wish to deploy and
supplying `-S branch=<new branch>` as arguments to Capistrano.
Running from Jenkins
--------------------
Because Jenkins will check out the code with the current revision
number you will be in a detached state. This causes the plugin to be
unhappy about the git tree. The solution is to add `-S branch=$GIT_COMMIT`
to the cap deploy line called from your Jenkins build. This will cause
the diffs and comparisons done by the deploytags gem to be correct.
Credits
-------
This software was written by [Karl Matthias](https://github.com/relistan)

View File

@@ -1,7 +1,7 @@
Gem::Specification.new do |s|
s.name = 'capistrano-deploytags'
s.version = '0.7.0'
s.date = '2012-10-02'
s.version = '0.9.1'
s.date = '2014-01-14'
s.summary = "Add dated, environment-specific tags to your git repo at each deployment."
s.description = <<-EOS
Capistrano Deploytags is a simple plugin to Capistrano that works with your deployment framework to track your code releases. All you have to do is require capistrano-deploytags and each deployment will add a new tag for that deployment, pointing to the latest commit. This lets you easily see which code is deployed on each environment, and allows you to figure out which code was running in an environment at any time in the past.

View File

@@ -2,20 +2,27 @@ module Capistrano
module DeployTags
def pending_git_changes?
# Do we have any changes vs HEAD on deployment branch?
!(`git fetch && git diff #{branch} --shortstat`.strip.empty?)
`git fetch #{remote}`.tap do |output|
return !(`git diff #{branch} --shortstat`.strip.empty?) if exec_success?
raise "'git fetch #{remote}' failed:\n #{output}"
end
end
def git_tag_for(stage)
"#{stage}-#{Time.now.strftime("%Y.%m.%d-%H%M%S")}"
"#{stage}-#{Time.new.utc.strftime('%Y.%m.%d-%H%M%S-utc')}"
end
def safe_run(*args)
raise "#{args.join(" ")} failed!" unless system(*args)
end
def exec_success?
$?.success?
end
def validate_git_vars
unless exists?(:branch) && exists?(:stage)
logger.log Capistrano::Logger::IMPORTANT, "Capistrano Deploytags requires that :branch and :stage be defined."
logger.log Capistrano::Logger::IMPORTANT, 'Capistrano Deploytags requires that :branch and :stage be defined.'
raise 'define :branch and :stage'
end
end
@@ -28,16 +35,22 @@ module Capistrano
!`git remote`.strip.empty?
end
def remote
exists?(:git_remote) ? git_remote : `git remote`.strip.split(/\n/).first
end
def self.load_into(configuration)
configuration.load do
before "deploy", 'git:prepare_tree'
before "deploy:migrations", 'git:prepare_tree'
after "deploy", 'git:tagdeploy'
after "deploy:migrations", 'git:tagdeploy'
before 'deploy', 'git:prepare_tree'
before 'deploy:migrations', 'git:prepare_tree'
after 'deploy', 'git:tagdeploy'
after 'deploy:migrations', 'git:tagdeploy'
desc 'prepare git tree so we can tag on successful deployment'
namespace :git do
task :prepare_tree, :except => { :no_release => true } do
next if fetch(:no_deploytags, false)
cdt.validate_git_vars
logger.log Capistrano::Logger::IMPORTANT, "Preparing to deploy HEAD from branch '#{branch}' to '#{stage}'"
@@ -47,21 +60,23 @@ module Capistrano
raise 'Dirty git tree'
end
cdt.safe_run "git", "checkout", branch
cdt.safe_run "git", "pull", "origin", branch if cdt.has_remote?
cdt.safe_run 'git', 'checkout', branch
logger.log Capistrano::Logger::IMPORTANT, "Pulling from #{branch}"
cdt.safe_run 'git', 'pull', cdt.remote, branch if cdt.has_remote?
end
desc 'add git tags for each successful deployment'
task :tagdeploy, :except => { :no_release => true } do
next if fetch(:no_deploytags, false)
cdt.validate_git_vars
current_sha = `git rev-parse #{branch} HEAD`.strip[0..8]
logger.log Capistrano::Logger::INFO, "Tagging #{current_sha} for deployment"
tag_user = (ENV['USER'] || ENV['USERNAME']).strip
cdt.safe_run "git", "tag", "-a", cdt.git_tag_for(stage), "-m", "#{tag_user} deployed #{current_sha} to #{stage}"
cdt.safe_run "git", "push", "--tags" if cdt.has_remote?
cdt.safe_run 'git', 'tag', '-a', cdt.git_tag_for(stage), '-m', "#{tag_user} deployed #{current_sha} to #{stage}"
cdt.safe_run 'git', 'push', '--tags' if cdt.has_remote?
end
end

View File

@@ -24,27 +24,73 @@ describe Capistrano::DeployTags do
end
context "prepare_tree" do
it "raises an error when not in a git tree" do
FileUtils.chdir '/tmp'
before do
configuration.set(:branch, 'master')
configuration.set(:stage, 'test')
end
it "raises an error when not in a git tree" do
FileUtils.chdir '/tmp'
configuration.cdt.stub(exec_success?: true)
expect { configuration.find_and_execute_task('git:prepare_tree') }.to raise_error('git checkout master failed!')
end
it "raises when unable to fetch" do
with_clean_repo do
configuration.cdt.should_receive(:exec_success?).and_return(false)
expect { configuration.find_and_execute_task('git:prepare_tree') }.to raise_error(/'git fetch ' failed/)
end
end
context "with a clean git tree" do
before :each do
configuration.set(:branch, 'master')
configuration.set(:stage, 'test')
end
it "raises an error if :stage or :branch are undefined" do
with_clean_repo do
configuration.unset(:branch)
configuration.unset(:stage)
expect { configuration.find_and_execute_task('git:prepare_tree') }.to raise_error('define :branch and :stage')
end
end
it "does not raise an error when run from a clean tree" do
with_clean_repo do
configuration.set(:branch, 'master')
configuration.set(:stage, 'test')
configuration.cdt.stub(exec_success?: true)
expect { configuration.find_and_execute_task('git:prepare_tree') }.to_not raise_error
end
end
it "does not run when :no_deploytags is defined by (i.e. by the stage)" do
with_clean_repo do
configuration.set(:no_deploytags, true)
configuration.cdt.should_not_receive(:validate_git_vars)
configuration.find_and_execute_task('git:prepare_tree')
end
end
it "uses a different remote when one is defined" do
with_clean_repo do
system('git remote add nowhere git@example.com:nowhere')
configuration.set(:git_remote, 'nowhere')
configuration.cdt.stub(pending_git_changes?: false)
configuration.cdt.should_receive(:safe_run).with('git', 'checkout', 'master')
configuration.cdt.should_receive(:safe_run).with('git', 'pull', 'nowhere', 'master')
configuration.find_and_execute_task('git:prepare_tree')
end
end
it "uses the first remote when one is not specified" do
with_clean_repo do
configuration.cdt.stub(pending_git_changes?: false)
system('git remote add somewhere git@example.com:somewhere')
configuration.cdt.should_receive(:safe_run).with('git', 'checkout', 'master')
configuration.cdt.should_receive(:safe_run).with('git', 'pull', 'somewhere', 'master')
configuration.find_and_execute_task('git:prepare_tree')
end
end
end
end
@@ -69,5 +115,15 @@ describe Capistrano::DeployTags do
tags.first.should =~ /^test-\d{4}\.\d{2}\.\d{2}/
end
end
it "does not run when :no_deploytags is defined by (i.e. by the stage)" do
with_clean_repo do
configuration.set(:branch, 'master')
configuration.set(:stage, 'test')
configuration.set(:no_deploytags, true)
configuration.cdt.should_not_receive(:validate_git_vars)
expect { configuration.find_and_execute_task('git:prepare_tree') }.to_not raise_error
end
end
end
end