Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Technicalpickles integration #2

Merged
merged 67 commits into from

4 participants

@apinstein
Owner

Been using this branch for a while now, seems quite stable. Promoting to master!

technicalpickles and others added some commits
@technicalpickles technicalpickles First pass at making a gem. f755c00
@technicalpickles technicalpickles Some code cleanup for last_tag_matching. 342c66d
@technicalpickles technicalpickles Added a recipe such that lib gets added to LOAD_PATH f33abdd
@technicalpickles technicalpickles Updated to 1.3.0 and generated gemspec. d64c489
@technicalpickles technicalpickles Updated readme. 9c792dc
@technicalpickles technicalpickles Rename variables to be snake cased. b7fbcec
@technicalpickles technicalpickles Added summary and description. d725ba8
@technicalpickles technicalpickles Added checks to verify local branch is up to date with remote branch. 49c77f6
@technicalpickles technicalpickles Use github branch compare for update_log if the repo is hosted on git…
…hub.
848baad
@technicalpickles technicalpickles Collect additional information for staging tag, including who did it,…
… and a one-line summary of changes.
c231943
@technicalpickles technicalpickles Use abort instead of raise, to avoid spitting out huge stacktraces. bf58eec
@technicalpickles technicalpickles Finally fixing whitespace. 0eb2df2
@technicalpickles technicalpickles Additional code cleanup. Also, fixed regular expression for yanking n…
…ame out of staging take, to use when promoting to production.
d9f0965
@technicalpickles technicalpickles Shuffle namespace under capistrano. fe08833
@technicalpickles technicalpickles Added deploy:pending:compare, as short hand for gitflow:commit_log. 46f2074
@technicalpickles technicalpickles Fixed errors when trying to access tag from configuration. 4b825e0
@technicalpickles technicalpickles Tweaks to README. dc96412
@technicalpickles technicalpickles Doc and whitespace cleanup. da2d254
@technicalpickles technicalpickles Made README be README.rdoc 7529573
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.0 a9e7c96
@technicalpickles technicalpickles Fixed gem name... whoops. 930e7f1
@technicalpickles technicalpickles Fixed homepage. 67b25b9
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.1 facca29
@technicalpickles technicalpickles Blurgh.... 020041e
@technicalpickles technicalpickles Version bump. 4b8f392
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.1 6ba15e4
@technicalpickles technicalpickles Fixed gitflow:commit_log to use master instead of head. ef38dab
@technicalpickles technicalpickles Version bump to 1.3.2 37675a0
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.2 a87c51f
@wfarr wfarr Fix a bug in sha detection 74e7d9e
@wfarr wfarr Version bump to 1.3.3 8bafa21
@wfarr wfarr Regenerated gemspec for version 1.3.3 cfd376d
@technicalpickles technicalpickles jeweler hax. 28a0a59
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.3 a4bcc66
@technicalpickles technicalpickles Fixed bug in determining last tag's number. Extracted logic to determ…
…ine next tag to its own method.
a079fa6
@technicalpickles technicalpickles Removed old gemspec. 2f2682b
@technicalpickles technicalpickles Version bump to 1.3.4. 655d098
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.4 17eb92c
@technicalpickles technicalpickles Removed breakpoint... doh. a074dd4
@technicalpickles technicalpickles Version bump to 1.3.5. 20ffeed
@technicalpickles technicalpickles Regenerated gemspec for version 1.3.5 2ea8f84
@wfarr wfarr Safely try to use the last staging tag for a new production deploy un…
…less otherwise specified
86f5329
@wfarr wfarr Version bump to 1.3.6 e5dd4f9
@technicalpickles technicalpickles Revert "Version bump to 1.3.6"
This reverts commit e5dd4f9.
5a4d6a8
@technicalpickles technicalpickles Version bump, for real. 245101e
@technicalpickles technicalpickles Regenerated gemspec for version 1.4.0 9241a4f
@wfarr wfarr Update README 4af7a3c
@technicalpickles technicalpickles Don't prompt for a tag, if we're not going to tag. d9685ad
@technicalpickles technicalpickles Don't try to do git trickery if scm isn't git. This is useful for tes…
…ting with ':scm: none' and ':deploy_via: copy'.
f5088a2
@technicalpickles technicalpickles Version bump to 1.4.1. 08cc721
@technicalpickles technicalpickles Added gitignore. ea9775a
@technicalpickles technicalpickles Regenerate gemspec for version 1.4.1 5d9a1f4
@mattscilipoti mattscilipoti Allow other stages (beyond staging/production)
Signed-off-by: Joshua Nichols <josh@technicalpickles.com>
96f0022
@technicalpickles technicalpickles Version bump to 1.4.2. 80cc749
@technicalpickles technicalpickles Regenerate gemspec for version 1.4.2 c1e5941
@technicalpickles technicalpickles Add better handling to tag_production when latest staging is already …
…in production. Make language a little more consistent between staging/production.
88f8fc1
@technicalpickles technicalpickles Don't push unless we're going to tag. 325e1ec
@technicalpickles technicalpickles Version bump to 1.4.3 45a28f5
@technicalpickles technicalpickles Regenerate gemspec for version 1.4.3 6f95478
@apinstein add license info 9116284
@apinstein improve readme 6c7753b
@apinstein update loading to work from cap or github install ebb56fc
@apinstein fix bug when deploying a non-explicitly-declared stage (ie staging or…
… production) which would cause master to be deployed rather than the current branch.
8e605ac
@apinstein clean up commit_log to respect custom setting over fancy new github t…
…rick. simplify code since we pre-calculate from/to tags before this block.
0c98040
@apinstein Fix bug in last_tag_matching which was introduced by alpha-naming tag…
… structure. updating to be strictly chronologically based.
21318eb
@apinstein further bug fix to last_tag_matching to improve on changes introduced…
… in 21318eb.
c0ac685
@apinstein for production deploys, show commit log before asking for deploy conf…
…irmation.
4881357
@apinstein apinstein merged commit b482492 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 11, 2010
  1. @technicalpickles
Commits on Jun 12, 2010
  1. @technicalpickles
  2. @technicalpickles
  3. @technicalpickles
  4. @technicalpickles

    Updated readme.

    technicalpickles authored
  5. @technicalpickles
  6. @technicalpickles
  7. @technicalpickles
  8. @technicalpickles
  9. @technicalpickles

    Collect additional information for staging tag, including who did it,…

    technicalpickles authored
    … and a one-line summary of changes.
  10. @technicalpickles
  11. @technicalpickles
Commits on Jun 15, 2010
  1. @technicalpickles

    Additional code cleanup. Also, fixed regular expression for yanking n…

    technicalpickles authored
    …ame out of staging take, to use when promoting to production.
  2. @technicalpickles
  3. @technicalpickles
  4. @technicalpickles
  5. @technicalpickles

    Tweaks to README.

    technicalpickles authored
Commits on Jun 16, 2010
  1. @technicalpickles
  2. @technicalpickles
  3. @technicalpickles
  4. @technicalpickles
  5. @technicalpickles

    Fixed homepage.

    technicalpickles authored
  6. @technicalpickles
  7. @technicalpickles

    Blurgh....

    technicalpickles authored
  8. @technicalpickles

    Version bump.

    technicalpickles authored
  9. @technicalpickles
  10. @technicalpickles
  11. @technicalpickles

    Version bump to 1.3.2

    technicalpickles authored
  12. @technicalpickles
Commits on Jun 18, 2010
  1. @wfarr

    Fix a bug in sha detection

    wfarr authored
  2. @wfarr

    Version bump to 1.3.3

    wfarr authored
  3. @wfarr
  4. @technicalpickles

    jeweler hax.

    technicalpickles authored
  5. @technicalpickles
Commits on Jun 23, 2010
  1. @technicalpickles

    Fixed bug in determining last tag's number. Extracted logic to determ…

    technicalpickles authored
    …ine next tag to its own method.
  2. @technicalpickles

    Removed old gemspec.

    technicalpickles authored
  3. @technicalpickles
  4. @technicalpickles
Commits on Jun 28, 2010
  1. @technicalpickles
  2. @technicalpickles
  3. @technicalpickles
Commits on Jul 16, 2010
  1. @wfarr

    Safely try to use the last staging tag for a new production deploy un…

    wfarr authored
    …less otherwise specified
  2. @wfarr

    Version bump to 1.3.6

    wfarr authored
  3. @technicalpickles

    Revert "Version bump to 1.3.6"

    technicalpickles authored
    This reverts commit e5dd4f9.
  4. @technicalpickles
  5. @technicalpickles
Commits on Aug 19, 2010
  1. @wfarr

    Update README

    wfarr authored
Commits on Sep 6, 2010
  1. @technicalpickles
Commits on Oct 26, 2010
  1. @technicalpickles

    Don't try to do git trickery if scm isn't git. This is useful for tes…

    technicalpickles authored
    …ting with ':scm: none' and ':deploy_via: copy'.
  2. @technicalpickles
  3. @technicalpickles

    Added gitignore.

    technicalpickles authored
  4. @technicalpickles
Commits on Nov 30, 2010
  1. @mattscilipoti @technicalpickles

    Allow other stages (beyond staging/production)

    mattscilipoti authored technicalpickles committed
    Signed-off-by: Joshua Nichols <josh@technicalpickles.com>
  2. @technicalpickles
  3. @technicalpickles
Commits on Apr 8, 2011
  1. @technicalpickles

    Add better handling to tag_production when latest staging is already …

    technicalpickles authored
    …in production. Make language a little more consistent between staging/production.
  2. @technicalpickles
  3. @technicalpickles
  4. @technicalpickles
Commits on May 17, 2011
  1. add license info

    authored
  2. improve readme

    authored
  3. fix bug when deploying a non-explicitly-declared stage (ie staging or…

    authored
    … production) which would cause master to be deployed rather than the current branch.
Commits on May 18, 2011
  1. clean up commit_log to respect custom setting over fancy new github t…

    authored
    …rick. simplify code since we pre-calculate from/to tags before this block.
Commits on May 19, 2011
  1. Fix bug in last_tag_matching which was introduced by alpha-naming tag…

    authored
    … structure. updating to be strictly chronologically based.
Commits on Jun 21, 2011
Commits on Oct 17, 2011
This page is out of date. Refresh to see the latest.
View
5 .document
@@ -0,0 +1,5 @@
+README.rdoc
+lib/**/*.rb
+bin/*
+features/**/*.feature
+LICENSE
View
2  .gitignore
@@ -0,0 +1,2 @@
+rdoc
+pkg
View
57 README
@@ -1,57 +0,0 @@
-A Capistrano recipe for git deployment via tags in a multistage environment.
-
-The best thing about this recipe is that there is almost nothing to learn -- your cap deploy process barely changes.
-Gitflow simply adds some tagging/logging/workflow magic.
-
-BEFORE
-cap deploy # 'head' goes to staging
-cap production deploy # 'head' goes to production
-
-AFTER
-cap deploy # 'head' goes to staging; tag staging-YYYY-MM-DD.X created
-cap production deploy -s tag=staging-YYYY-MM-DD.X # tag 'staging-YYYY-MM-DD.X' goes to production
- # tag 'production-YYYY-MM-DD.X' created; points to staging tag
-
-BONUS
-cap gitflow:update_log # shows you a log of what will be pushed to staging that isn't already there
-cap production gitflow:update_log # shows you a log of what will be pushed to production that isn't already there
-
-INSTALLATION
-* require the gitflow file after your multistage require
-require 'capistrano/ext/multistage'
-require 'git-deployment/gitflow.rb'
-
-Expects stages "staging" and "production".
-
-DETAILS
-After experimenting with several workflows for deployment in git, I've finally found one I really like.
-
-* You can push to staging at any time; every staging push is automatically tagged with a unique tag.
-* You can only push a staging tag to production. This helps to enforce QA of all pushes to production.
-
-PUSH TO STAGING:
-Whenever you want to push the currently checked-out code to staging, just do:
-
-cap staging deploy
-
-gitflow will automatically:
-* create a unique tag in the format of 'staging-YYYY-MM-DD.X'
-* configure multistage to use that tag for the deploy
-* push the code and tags to the remote "origin"
-* and run the normal deploy task for the staging stage.
-
-PUSH TO PRODUCTION:
-Whenever you want to push code to production, you must specify the staging tag you wish to promote to production:
-
-cap production deploy -s tag=staging-2009-09-08.2
-
-gitflow will automatically:
-* alias the staging tag to a production tag like: production-2008-09-08.2
-* configure multistage to use that tag for the deploy
-* push the code and tags to the remote "origin"
-* and run the normal deploy task for the production stage.
-
-NOTES:
-* you may need to wipe out the cached-copy on the remote server that cap uses when switching to this workflow; I have seen situations where the cached copy cannot cleanly checkout to the new branch/tag. it's safe to try without wiping it out first, it will fail gracefully.
-* if your stages already have a "set :branch, 'my-staging-branch'" call in your configs, remove it. This workflow configures it automatically.
-* it'd be cool to package this up as a gem to make installation easier; don't know how at the moment. just clone the code...
View
107 README.rdoc
@@ -0,0 +1,107 @@
+= gitflow: a Capistrano recipe for git deployment using tags in a multistage environment.
+
+The best thing about this recipe is that there is almost nothing to learn -- your cap deploy process barely changes.
+Gitflow simply adds some tagging/logging/workflow magic.
+
+ # BEFORE
+ $ cap deploy # 'master' goes to staging
+ $ cap production deploy # 'master' goes to production
+
+ # AFTER
+ $ cap deploy
+ # 'master' goes to staging; tag staging-YYYY-MM-DD.X created
+ $ cap production deploy
+ # deploys latest staging tag, or if last tag is a production tag then that, to production
+ # for specifying the tag by hand add `-s tag=staging-YYYY-MM-DD-X-user-description`
+ # tag 'staging-YYYY-MM-DD-X' goes to production
+ # tag 'production-YYYY-MM-DD-X' created; points to staging-YYYY-MM-DD-X
+
+ # BONUS
+ cap gitflow:commit_log
+ # displays a commit log pushed to staging
+ # ... alternatively, if you're using GitHub, will open a page using branch compare
+ cap production gitflow:log_log
+ # displays a commit log of what will be pushed to production
+
+== INSTALLATION
+
+First, install the gem:
+
+ gem install capistrano-gitflow
+
+Then update config/deploy.rb
+
+ require 'capistrano/ext/multistage'
+ require 'capistrano/gitflow' # needs to come after multistage
+
+More info at: http://rubygems.org/gems/capistrano-gitflow
+
+== DETAILS
+
+After experimenting with several workflows for deployment in git, I've finally found one I really like.
+
+* You can push to staging at any time; every staging push is automatically tagged with a unique tag.
+* You can only push a staging tag to production. This helps to enforce QA of all pushes to production.
+
+=== PUSH TO STAGING
+
+Whenever you want to push the currently checked-out code to staging, just do:
+
+ cap staging deploy
+
+gitflow will automatically:
+
+* create a unique tag in the format of 'staging-YYYY-MM-DD.X'
+* configure multistage to use that tag for the deploy
+* push the code and tags to the remote "origin"
+* and run the normal deploy task for the staging stage.
+
+=== PUSH TO PRODUCTION:
+
+Whenever you want to push code to production, you must specify the staging tag you wish to promote to production:
+
+ cap production deploy -s tag=staging-2009-09-08.2
+
+gitflow will automatically:
+
+* alias the staging tag to a production tag like: production-2008-09-08.2
+* configure multistage to use that tag for the deploy
+* push the code and tags to the remote "origin"
+* and run the normal deploy task for the production stage.
+
+=== NOTES:
+
+* you may need to wipe out the cached-copy on the remote server that cap uses when switching to this workflow; I have seen situations where the cached copy cannot cleanly checkout to the new branch/tag. it's safe to try without wiping it out first, it will fail gracefully.
+* if your stages already have a "set :branch, 'my-staging-branch'" call in your configs, remove it. This workflow configures it automatically.
+
+== CREDIT
+
+Originally created by Alan Pinstein.
+
+Gemified and hacked by Josh Nichols.
+
+== LICENSE
+
+MIT licensed.
+
+Copyright (c) 2009-2010 Alan Pinstein <apinstein@mac.com>
+
+Copyright (c) 2010 Josh Nichols
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
47 Rakefile
@@ -0,0 +1,47 @@
+require 'rubygems'
+require 'rake'
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |gem|
+ gem.name = "capistrano-gitflow"
+ gem.summary = %Q{Capistrano recipe for a deployment workflow based on git tags }
+ gem.description = %Q{Capistrano recipe for a deployment workflow based on git tags}
+ gem.email = "josh@technicalpickles.com"
+ gem.homepage = "http://github.com/technicalpickles/capistrano-gitflow"
+ gem.authors = ["Joshua Nichols"]
+ gem.add_dependency "capistrano"
+ gem.add_dependency "stringex"
+ gem.add_development_dependency "rspec", ">= 1.2.9"
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
+ end
+ Jeweler::GemcutterTasks.new
+rescue LoadError
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
+end
+
+require 'spec/rake/spectask'
+Spec::Rake::SpecTask.new(:spec) do |spec|
+ spec.libs << 'lib' << 'spec'
+ spec.spec_files = FileList['spec/**/*_spec.rb']
+end
+
+Spec::Rake::SpecTask.new(:rcov) do |spec|
+ spec.libs << 'lib' << 'spec'
+ spec.pattern = 'spec/**/*_spec.rb'
+ spec.rcov = true
+end
+
+task :spec => :check_dependencies
+
+task :default => :spec
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "gitflow #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
View
2  VERSION
@@ -1 +1 @@
-1.2
+1.4.3
View
59 capistrano-gitflow.gemspec
@@ -0,0 +1,59 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{capistrano-gitflow}
+ s.version = "1.4.3"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Joshua Nichols"]
+ s.date = %q{2011-04-07}
+ s.description = %q{Capistrano recipe for a deployment workflow based on git tags}
+ s.email = %q{josh@technicalpickles.com}
+ s.extra_rdoc_files = [
+ "README.rdoc"
+ ]
+ s.files = [
+ ".document",
+ "README.rdoc",
+ "Rakefile",
+ "VERSION",
+ "capistrano-gitflow.gemspec",
+ "lib/capistrano/gitflow.rb",
+ "lib/capistrano/gitflow/natcmp.rb",
+ "recipes/gitflow_recipes.rb",
+ "spec/gitflow_spec.rb",
+ "spec/spec.opts",
+ "spec/spec_helper.rb"
+ ]
+ s.homepage = %q{http://github.com/technicalpickles/capistrano-gitflow}
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.7}
+ s.summary = %q{Capistrano recipe for a deployment workflow based on git tags}
+ s.test_files = [
+ "spec/gitflow_spec.rb",
+ "spec/spec_helper.rb"
+ ]
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<capistrano>, [">= 0"])
+ s.add_runtime_dependency(%q<stringex>, [">= 0"])
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
+ else
+ s.add_dependency(%q<capistrano>, [">= 0"])
+ s.add_dependency(%q<stringex>, [">= 0"])
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
+ end
+ else
+ s.add_dependency(%q<capistrano>, [">= 0"])
+ s.add_dependency(%q<stringex>, [">= 0"])
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
+ end
+end
+
View
132 gitflow.rb
@@ -1,132 +0,0 @@
-Capistrano::Configuration.instance(true).load do |configuration|
- before "deploy:update_code", "gitflow:calculate_tag"
- namespace :gitflow do
- def last_tag_matching(pattern)
- lastTag = nil
-
- allTagsMatching = `git tag -l '#{pattern}'`
- allTagsMatching = allTagsMatching.split
- natcmpSrc = File.join(File.dirname(__FILE__), '/natcmp.rb')
- require natcmpSrc
- allTagsMatching.sort! do |a,b|
- String.natcmp(b,a,true)
- end
-
- if allTagsMatching.length > 0
- lastTag = allTagsMatching[0]
- end
- return lastTag
- end
-
- def last_staging_tag()
- return last_tag_matching('staging-*')
- end
-
- def last_production_tag()
- return last_tag_matching('production-*')
- end
-
- desc "Calculate the tag to deploy"
- task :calculate_tag do
- # make sure we have any other deployment tags that have been pushed by others so our auto-increment code doesn't create conflicting tags
- `git fetch`
-
- tagMethod = "tag_#{stage}"
- send tagMethod
-
- # push tags and latest code
- system 'git push'
- if $? != 0
- raise "git push failed"
- end
- system 'git push --tags'
- if $? != 0
- raise "git push --tags failed"
- end
- end
-
- desc "Show log between most recent staging tag (or given tag=XXX) and last production release."
- task :update_log do
- fromTag = nil
- toTag = nil
-
- # do different things based on stage
- if stage == :production
- fromTag = last_production_tag
- elsif stage == :staging
- fromTag = last_staging_tag
- else
- raise "Unsupported stage #{stage}"
- end
-
- # no idea how to properly test for an optional cap argument a la '-s tag=x'
- toTag = configuration[:tag]
- if toTag == nil
- puts "Calculating 'end' tag for :update_log for '#{stage}'"
- # do different things based on stage
- if stage == :production
- toTag = last_staging_tag
- elsif stage == :staging
- toTag = 'head'
- else
- raise "Unsupported stage #{stage}"
- end
- end
-
- # run comp
- logSubcommand = 'log'
- if ENV['git_log_command'] && ENV['git_log_command'].strip != ''
- logSubcommand = ENV['git_log_command']
- end
- command = "git #{logSubcommand} #{fromTag}..#{toTag}"
- puts command
- system command
- end
-
- desc "Mark the current code as a staging/qa release"
- task :tag_staging do
- # find latest staging tag for today
- newTagDate = Date.today.to_s
- newTagSerial = 1
-
- lastStagingTag = last_tag_matching("staging-#{newTagDate}.*")
- if lastStagingTag
- # calculate largest serial and increment
- lastStagingTag =~ /staging-[0-9]{4}-[0-9]{2}-[0-9]{2}\.([0-9]*)/
- newTagSerial = $1.to_i + 1
- end
- newStagingTag = "staging-#{newTagDate}.#{newTagSerial}"
-
- shaOfCurrentCheckout = `git log --pretty=format:%H HEAD -1`
- shaOfLastStagingTag = nil
- if lastStagingTag
- shaOfLastStagingTag = `git log --pretty=format:%H #{lastStagingTag} -1`
- end
-
- if shaOfLastStagingTag == shaOfCurrentCheckout
- puts "Not re-tagging staging because the most recent tag (#{lastStagingTag}) already points to current head"
- newStagingTag = lastStagingTag
- else
- puts "Tagging current branch for deployment to staging as '#{newStagingTag}'"
- system "git tag -a -m 'tagging current code for deployment to staging' #{newStagingTag}"
- end
-
- set :branch, newStagingTag
- end
-
- desc "Push the passed staging tag to production. Pass in tag to deploy with '-s tag=staging-YYYY-MM-DD.X'."
- task :tag_production do
- promoteToProductionTag = configuration[:tag]
- raise "Staging tag required; use '-s tag=staging-YYYY-MM-DD.X'" unless promoteToProductionTag
- raise "Staging tag required; use '-s tag=staging-YYYY-MM-DD.X'" unless promoteToProductionTag =~ /staging-.*/
- raise "Staging Tag #{promoteToProductionTag} does not exist." unless last_tag_matching(promoteToProductionTag)
-
- promoteToProductionTag =~ /staging-([0-9]{4}-[0-9]{2}-[0-9]{2}\.[0-9]*)/
- newProductionTag = "production-#{$1}"
- puts "promoting staging tag #{promoteToProductionTag} to production as '#{newProductionTag}'"
- system "git tag -a -m 'tagging current code for deployment to production' #{newProductionTag} #{promoteToProductionTag}"
-
- set :branch, newProductionTag
- end
- end
-end
View
198 lib/capistrano/gitflow.rb
@@ -0,0 +1,198 @@
+require 'capistrano'
+require File.join(File.dirname(__FILE__), 'gitflow', 'natcmp')
+require 'stringex'
+
+module Capistrano
+ class Gitflow
+ def self.load_into(capistrano_configuration)
+ capistrano_configuration.load do
+ before "deploy:update_code", "gitflow:calculate_tag"
+ before "gitflow:calculate_tag", "gitflow:verify_up_to_date"
+
+ namespace :gitflow do
+ def last_tag_matching(pattern)
+ # search for most recent (chronologically) tag matching the passed pattern, then get the name of that tag.
+ last_tag = `git describe --exact-match --match '#{pattern}' \`git log --tags='#{pattern}*' --format="%H" -1\``.chomp
+ return nil if last_tag == ''
+ return last_tag
+ end
+
+ def last_staging_tag()
+ last_tag_matching('staging-*')
+ end
+
+ def next_staging_tag
+ hwhen = Date.today.to_s
+ who = `whoami`.chomp.to_url
+ what = Capistrano::CLI.ui.ask("What does this release introduce? (this will be normalized and used in the tag for this release) ").to_url
+
+ last_staging_tag = last_tag_matching("staging-#{hwhen}-*")
+ new_tag_serial = if last_staging_tag && last_staging_tag =~ /staging-[0-9]{4}-[0-9]{2}-[0-9]{2}\-([0-9]*)/
+ $1.to_i + 1
+ else
+ 1
+ end
+
+ "#{stage}-#{hwhen}-#{new_tag_serial}-#{who}-#{what}"
+ end
+
+ def last_production_tag()
+ last_tag_matching('production-*')
+ end
+
+ def using_git?
+ fetch(:scm, :git).to_sym == :git
+ end
+
+ task :verify_up_to_date do
+ if using_git?
+ set :local_branch, `git branch --no-color 2> /dev/null | sed -e '/^[^*]/d'`.gsub(/\* /, '').chomp
+ set :local_sha, `git log --pretty=format:%H HEAD -1`.chomp
+ set :origin_sha, `git log --pretty=format:%H #{local_branch} -1`
+ unless local_sha == origin_sha
+ abort """
+Your #{local_branch} branch is not up to date with origin/#{local_branch}.
+Please make sure you have pulled and pushed all code before deploying:
+
+ git pull origin #{local_branch}
+ # run tests, etc
+ git push origin #{local_branch}
+
+ """
+ end
+ end
+ end
+
+ desc "Calculate the tag to deploy"
+ task :calculate_tag do
+ if using_git?
+ # make sure we have any other deployment tags that have been pushed by others so our auto-increment code doesn't create conflicting tags
+ `git fetch`
+
+ if respond_to?("tag_#{stage}")
+ send "tag_#{stage}"
+
+ system "git push --tags origin #{local_branch}"
+ if $? != 0
+ abort "git push failed"
+ end
+ else
+ puts "Will deploy tag: #{local_branch}"
+ set :branch, local_branch
+ end
+ end
+ end
+
+ desc "Show log between most recent staging tag (or given tag=XXX) and last production release."
+ task :commit_log do
+ from_tag = if stage == :production
+ last_production_tag
+ elsif stage == :staging
+ last_staging_tag
+ else
+ abort "Unsupported stage #{stage}"
+ end
+
+ # no idea how to properly test for an optional cap argument a la '-s tag=x'
+ to_tag = capistrano_configuration[:tag]
+ to_tag ||= begin
+ puts "Calculating 'end' tag for :commit_log for '#{stage}'"
+ to_tag = if stage == :production
+ last_staging_tag
+ elsif stage == :staging
+ 'master'
+ else
+ abort "Unsupported stage #{stage}"
+ end
+ end
+
+
+ # use custom compare command if set
+ if ENV['git_log_command'] && ENV['git_log_command'].strip != ''
+ command = "git #{ENV['git_log_command']} #{from_tag}..#{to_tag}"
+ else
+ # default compare command
+ # be awesome for github
+ if `git config remote.origin.url` =~ /git@github.com:(.*)\/(.*).git/
+ command = "open https://github.com/#{$1}/#{$2}/compare/#{from_tag}...#{to_tag}"
+ else
+ command = "git log #{from_tag}..#{to_tag}"
+ end
+ end
+ puts "Displaying commits from #{from_tag} to #{to_tag} via:\n#{command}"
+ system command
+
+ puts ""
+ end
+
+ desc "Mark the current code as a staging/qa release"
+ task :tag_staging do
+ current_sha = `git log --pretty=format:%H HEAD -1`
+ last_staging_tag_sha = if last_staging_tag
+ `git log --pretty=format:%H #{last_staging_tag} -1`
+ end
+
+ if last_staging_tag_sha == current_sha
+ puts "Not re-tagging staging because latest tag (#{last_staging_tag}) already points to HEAD"
+ new_staging_tag = last_staging_tag
+ else
+ new_staging_tag = next_staging_tag
+ puts "Tagging current branch for deployment to staging as '#{new_staging_tag}'"
+ system "git tag -a -m 'tagging current code for deployment to staging' #{new_staging_tag}"
+ end
+
+ set :branch, new_staging_tag
+ end
+
+ desc "Push the approved tag to production. Pass in tag to deploy with '-s tag=staging-YYYY-MM-DD-X-feature'."
+ task :tag_production do
+ promote_to_production_tag = capistrano_configuration[:tag] || last_staging_tag
+
+ unless promote_to_production_tag && promote_to_production_tag =~ /staging-.*/
+ abort "Couldn't find a staging tag to deploy; use '-s tag=staging-YYYY-MM-DD.X'"
+ end
+ unless last_tag_matching(promote_to_production_tag)
+ abort "Staging tag #{promote_to_production_tag} does not exist."
+ end
+
+ promote_to_production_tag =~ /^staging-(.*)$/
+ new_production_tag = "production-#{$1}"
+
+ if new_production_tag == last_production_tag
+ puts "Not re-tagging #{last_production_tag} because it already exists"
+ really_deploy = Capistrano::CLI.ui.ask("Do you really want to deploy #{last_production_tag}? [y/N]").to_url
+
+ exit(1) unless really_deploy =~ /^[Yy]$/
+ else
+ puts "Preparing to promote staging tag '#{promote_to_production_tag}' to '#{new_production_tag}'"
+ gitflow.commit_log
+ unless capistrano_configuration[:tag]
+ really_deploy = Capistrano::CLI.ui.ask("Do you really want to deploy #{new_production_tag}? [y/N]").to_url
+
+ exit(1) unless really_deploy =~ /^[Yy]$/
+ end
+ puts "Promoting staging tag #{promote_to_production_tag} to production as '#{new_production_tag}'"
+ system "git tag -a -m 'tagging current code for deployment to production' #{new_production_tag} #{promote_to_production_tag}"
+ end
+
+ set :branch, new_production_tag
+ end
+ end
+
+ namespace :deploy do
+ namespace :pending do
+ task :compare do
+ gitflow.commit_log
+ end
+ end
+ end
+
+ end
+
+ end
+ end
+end
+
+if Capistrano::Configuration.instance
+ Capistrano::Gitflow.load_into(Capistrano::Configuration.instance)
+end
View
0  natcmp.rb → lib/capistrano/gitflow/natcmp.rb
File renamed without changes
View
2  recipes/gitflow_recipes.rb
@@ -0,0 +1,2 @@
+# Just need to add to LOAD_PATH, so we can require 'gitflow'
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
View
7 spec/gitflow_spec.rb
@@ -0,0 +1,7 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe "Gitflow" do
+ it "fails" do
+ fail "hey buddy, you should probably rename this file and start specing for real"
+ end
+end
View
1  spec/spec.opts
@@ -0,0 +1 @@
+--color
View
9 spec/spec_helper.rb
@@ -0,0 +1,9 @@
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+require 'gitflow'
+require 'spec'
+require 'spec/autorun'
+
+Spec::Runner.configure do |config|
+
+end
Something went wrong with that request. Please try again.