cap_git_tools 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in cap_git_tools.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # cap_git_tools
2
+
3
+ Re-usable, composable [Capistrano](https://github.com/capistrano/capistrano) tasks for git tagging and other work with the
4
+ git repository you use for your Cap deploys.
5
+
6
+ * Ensure your local git is committed and pushed, so you are deploying what you
7
+ think you are.
8
+ * Automatically git tag the deploy
9
+ * Enforce a [multistage](https://github.com/capistrano/capistrano/wiki/2.x-Multistage-Extension) workflow where only a tagged staging release can be deployed
10
+ to production (ala [gitflow](https://github.com/apinstein/git-deployment))
11
+
12
+ Functionality is split into discrete yet composable tasks, with sensible defaults
13
+ but configurable, so you can build a cap recipe that fits *your*
14
+ requirements and workflow. Ordinary single stage or multi-stage; with or without
15
+ interactive confirmation prompts; using git however you're already or would like
16
+ to be using it.
17
+
18
+ (_Inspired by Alan Pinstein and Josh Nichols' neat
19
+ [gitflow](https://github.com/apinstein/git-deployment), but refactored for more
20
+ flexiblity with less hardcoded workflow. Some functionality changed in the
21
+ process.)_
22
+
23
+ ## Installation
24
+
25
+ gem install cap_git_tools
26
+
27
+ Or if in the context of something using bundler such as Rails, add to Gemfile
28
+ eg:
29
+
30
+ gem 'cap_git_tools', :group => :development
31
+
32
+ Add to top of a relevant Capistrano file (such as config/deploy.rb ordinarily):
33
+
34
+ require 'cap_git_tools/tasks'
35
+
36
+ This makes cap_git_tool's tasks available to you, but doesn't automatically wire
37
+ them up to be used by your `cap deploy`. See below.
38
+
39
+ You probably want to make sure you have an `ssh-agent` set up, or you'll have to
40
+ enter your private key password to access git several times. You will need to be
41
+ running your cap recipes from a directory with a git checkout (usual behavior
42
+ for cap usage, but not actually required otherwise by cap).
43
+
44
+ ## Ensure git is committed and pushed when deploying
45
+
46
+ Have you ever deployed the 'wrong' thing, because you forgot to commit and/or
47
+ push your changes to git? I have.
48
+
49
+ Have cap make sure you're committed and pushed before deploying by adding to
50
+ your recipe in deploy.rb:
51
+
52
+ before "deploy:update_code", "git:guard_committed", "git:guard_upstream"
53
+
54
+ Or use just one or the other
55
+
56
+ * `guard_committed` makes sure you have no uncommitted changes. _IF_ you have a :branch set
57
+ in your cap recipe, it will also make sure your curent checkout matches that branch.
58
+ * `guard_upstream` makes sure the current working copy branch committed tip (or local branch matching Cap
59
+ :branch, if set) matches the upstream remote version.
60
+
61
+ ## Automatically tag on deploy
62
+
63
+ Every time you deploy, want to have Capistrano automatically tag exactly what
64
+ gets deployed, with a tag like "deploy-2012-04-11-1517"?
65
+
66
+ Add this to your Cap recipe, usefully combining with the tasks to make sure
67
+ your git copy is 'clean' as discussed above:
68
+
69
+ before "deploy:update_code", "git:guard_committed", "git:guard_pushed", "git:tag"
70
+
71
+ That's a date and timestamp, deploy-yyyy-mm-dd-hhmm.
72
+
73
+ If you are using multistage, instead of "deploy-" as a prefix, it'll use
74
+ the current stage name like "production" or "staging" (but see below for
75
+ fancier multi-stage workflow).
76
+
77
+ Ordinarily what's in your current git checkout will be tagged; but if
78
+ you have set cap's `:branch`, it'll tag and deploy the HEAD of that branch
79
+ even if that's not your current checkout.
80
+
81
+ You can customize the prefix and other aspects of tagging, both in your recipe
82
+ and with command line over-rides, see `cap -E git:tag` for more info.
83
+
84
+ ## Multistage workflow
85
+
86
+ Are you using Capistrano's [multistage
87
+ extension](https://github.com/capistrano/capistrano/wiki/2.x-Multistage-Extension)?
88
+ In one commonly desired multistage workflow (similar to what
89
+ [gitflow](https://github.com/apinstein/git-deployment) enforces):
90
+
91
+ * Under staging, you want automatic tagging with staging-yyyy-mm-dd-hhmm, just
92
+ as above under 'Automatically tag on deploy'. Add to your `config/staging.rb`:
93
+
94
+ before "deploy:update_code", "git:guard_committed", "git:guard_upstream", "git:tag"
95
+
96
+ * Under production, you want to take the most recent 'staging' tag, and promote
97
+ it by deploying that tag to production, re-tagging with a "production-" tag.
98
+ Maybe you also want to print out the commit log between the last production
99
+ tag and what you're about to deploy, and require interactive confirmation.
100
+ Add to your `config/deploy.rb`:
101
+
102
+ before "deploy:update_code", "git:commit_log", "git:retag"
103
+ set :confirm_tag, true
104
+
105
+ Say you `cap staging deploy` on April 1 2012 at noon, your deploy will be
106
+ tagged `staging-2012-04-01-1200`.
107
+
108
+ Say on April 2 at noon, you run `cap production deploy`
109
+
110
+ * you'll be a shown a commit log of changes between the previous `production-`
111
+ commit and your most recent `staging-` commit, `staging-2012-04-01-1200`.
112
+ (`git:commit_log`)
113
+ * You'll be asked to confirm, (`set :confirm_tag, true`)
114
+ * And then the deploy will happen, with new tag added `production-2012-04-02-1200`
115
+ (`git:retag`).
116
+ * Note it's timestamped with date of production deploy. The commit message
117
+ for the `production-` tag will say which `staging-` tag was retagged.
118
+
119
+ The `git:retag` task has some configurable options (in your recipe or on the
120
+ individual command line invocation) too, see `cap -e git:retag`.
121
+
122
+ ## Make your own recipe
123
+
124
+ Look at `cap -T git` to see the tasks added by cap_git_tools. Run `cap -e
125
+ taskname` to see expanded documentation info on each one, covering more
126
+ specifics of what it does and what cap variables can alter it's behavior.
127
+
128
+ Some behaviors can be customized by 'capistrano variables'. These can be set in
129
+ a recipe:
130
+
131
+ set :variable, "value"
132
+
133
+ Or set/over-ridden on the individual cap command line invocation:
134
+
135
+ cap deploy -s variable=value
136
+
137
+ Doesn't matter if you use cap '-s' or '-S', cap_git_tools tasks always lazily
138
+ look up these values.
139
+
140
+ ## Other tools
141
+
142
+ `cap git:commit_log` to see the commits between the *last* tagged release
143
+ and what you'd deploy now with `cap deploy`. Works in singlestage recipe, or
144
+ multistage under 'cap staging git:commit_log' or 'cap production
145
+ git:commit_log'.
146
+
147
+ `cap git:show_tags` to show the last 3 deploy tags, with meta information.
148
+ Works in single stage recipe or multistage.
149
+
150
+ ## To Be Done
151
+
152
+ * Tag names are automatically created with a year-month-day-hour-minute timestamp.
153
+ However, if you try to deploy again before the minute's changed on the clock,
154
+ the tasks will try to re-tag using an already used name. You'll get an error and
155
+ the task will abort, but the task could be written to catch this and add a
156
+ suffix. But it ain't yet.
157
+
158
+ * There is some limited experimental functionality to change the format and add
159
+ new components to the automatically created tag name, using a
160
+ [:tag_template](https://github.com/jrochkind/cap_git_tools/blob/master/lib/cap_git_tools/task_helpers.rb#L162)
161
+ variable. This theoretically allows the `who` and `what` components used by
162
+ gitflow. But doing the 'right thing' in multistage (copying the 'what' from the
163
+ previous tag, but regenerating the rest) is a bit tricky, and hasn't been done
164
+ yet, which is what keeps this functionality limited and experimental at this
165
+ point.
166
+
167
+ ## Let me know
168
+
169
+ Feedback, pull requests, complaints, welcome. Not sure if anyone's gonna use
170
+ this.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "cap_git_tools/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "cap_git_tools"
7
+ s.version = CapGitTools::VERSION
8
+ s.authors = ["Jonathan Rochkind"]
9
+ s.email = ["jonathan@dnil.net"]
10
+ s.homepage = ""
11
+ s.summary = %q{re-usable, composable Capistrano tasks for git tagging and other work with a git repo}
12
+
13
+ s.rubyforge_project = "cap_git_tools"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+
21
+ s.add_dependency "capistrano", "~> 2.0"
22
+ end
@@ -0,0 +1,5 @@
1
+ require "cap_git_tools/version"
2
+
3
+ module CapGitTools
4
+ # We don't really do anything by default on gem load.
5
+ end
@@ -0,0 +1,194 @@
1
+ # methods used by tasks defined in tasks.rb
2
+ #
3
+ # generally this module is 'include'd into a cap
4
+ # :namespace, seems to do what we want.
5
+ require 'cap_git_tools'
6
+
7
+ module CapGitTools::TaskHelpers
8
+ ####
9
+ # Some functions used by the tasks
10
+ #
11
+
12
+ # say with an indent in spaces
13
+ def say_formatted(msg, options = {})
14
+ options.merge!(:indent => 4)
15
+ Capistrano::CLI.ui.say(' ' * options[:indent] + msg )
16
+ end
17
+
18
+ # execute a 'git fetch', but mark in a private variable that
19
+ # we have, so we only do it once per cap execution.
20
+ def ensure_git_fetch
21
+ unless @__git_fetched
22
+ local_sh "git fetch #{upstream_remote}"
23
+ @__git_fetched = true
24
+ end
25
+ end
26
+
27
+ # execute locally as a shell command, echo'ing to output, as
28
+ # well as capturing error and aborting.
29
+ def local_sh(cmd)
30
+ say_formatted("executing locally: #{cmd}")
31
+ `#{cmd}`
32
+ abort("failed: #{cmd}") unless $? == 0
33
+ end
34
+
35
+ # How to refer to the upstream git repo configured in cap :repository?
36
+ # Will _usually_ return 'origin', will sometimes return another remote,
37
+ # will occasionally return a raw git url when it's not configured in
38
+ # remotes for some reason.
39
+ #
40
+ # This used to be hard-coded to 'origin'. Then it was configurable.
41
+ # Then I realized it _has_ to be whatever is set in cap :repository.
42
+ # We'll look up the remote alias for that, if available, and cache
43
+ # the lookup. Usually it'll be 'origin', yeah.
44
+ def upstream_remote
45
+ @__upstream_remote = begin
46
+ git_url = fetch(:repository)
47
+
48
+ remote_info =
49
+ `git remote -v`.
50
+ split("\n").
51
+ collect {|line| line.split(/[\t ]/) }.
52
+ find {|list| list[1] == git_url }
53
+
54
+ remote_info ? remote_info[0] : git_url
55
+ end
56
+ end
57
+
58
+
59
+ # what branch we're going to tag and deploy -- if cap 'branch' is set,
60
+ # use that one, otherwise use current branch in checkout
61
+ def working_branch
62
+ @__git_working_branch ||= begin
63
+ if exists?("branch")
64
+ fetch(:branch)
65
+ else
66
+ b = `git symbolic-ref -q HEAD`.sub(%r{^refs/heads/}, '').chomp
67
+ b.empty? ? "HEAD" : b
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ # current SHA fingerprint of local branch mentioned in :branch
74
+ def local_sha
75
+ `git log --pretty=format:%H #{working_branch} -1`.chomp
76
+ end
77
+
78
+ def tag_prefix
79
+ fetch(:tag_prefix, fetch(:stage, "deploy"))
80
+ end
81
+
82
+ def from_prefix
83
+ fetch("from_prefix", "staging")
84
+ end
85
+
86
+
87
+ # mostly used by git:retag, calculate the tag we'll be retagging FROM.
88
+ #
89
+ # can set cap :from_tag. Or else find last tag matching from_prefix,
90
+ # which by default is "staging-*"
91
+ def from_tag
92
+ t = nil
93
+ if exists?("from_tag")
94
+ t = fetch("from_tag")
95
+ else
96
+ t = fetch_last_tag( self.from_prefix )
97
+
98
+ if t.nil? || t.empty?
99
+ abort("failed: can't find existing tag matching #{self.from_prefix}-*")
100
+ end
101
+ end
102
+ return t
103
+ end
104
+
105
+ # find the last (chronological) tag with given prefix.
106
+ # prefix can include shell-style wildcards like '*'. Defaults to
107
+ # last tag with current default tag_prefix.
108
+ #
109
+ # Note: Will only work on git 'full' annotated tags (those signed or
110
+ # with -m message or -a) because git only stores dates for annotated tags.
111
+ # others will end up sorted lexicographically BEFORE any annotated tags.
112
+ def fetch_last_tag(pattern_prefix = self.tag_prefix)
113
+ # make sure we've fetched to get latest from upstream.
114
+ ensure_git_fetch
115
+
116
+ # crazy git command, yeah. Sort by tagged date descending, one line only,
117
+ # output refname:short, look for tags matching our pattern.
118
+ last_tag = `git for-each-ref --count=1 --sort='-taggerdate' --format='%(refname:short)' 'refs/tags/#{pattern_prefix}-*' 2>/dev/null`.chomp
119
+ return nil if last_tag == ''
120
+ return last_tag
121
+ end
122
+
123
+ # show commit lot from commit-ish to commit-ish,
124
+ # using appropriate UI tool.
125
+ #
126
+ # If you have cap :github_browser_compare set and the remote is github,
127
+ # use `open` to open in browser.
128
+ #
129
+ # else if you have ENV['git_log_command'] set, pass to `git` (don't know
130
+ # what this is for, inherited from gitflow)
131
+ #
132
+ # else just use an ordinary command line git log
133
+ def show_commit_log(from_tag, to_tag)
134
+ if fetch("github_browser_compare", false ) && `git config remote.#{upstream_remote}.url` =~ /git@github.com:(.*)\/(.*).git/
135
+ # be awesome for github, use `open` in browser
136
+ command = "open https://github.com/#{$1}/#{$2}/compare/#{from_tag}...#{to_tag}"
137
+ elsif ENV['git_log_command'] && ENV['git_log_command'].strip != ''
138
+ # use custom compare command if set
139
+ command = "git #{ENV['git_log_command']} #{from_tag}..#{to_tag}"
140
+ else
141
+ # standard git log command
142
+ command = "git log #{from_tag}..#{to_tag}"
143
+ end
144
+
145
+ say_formatted "Displaying commits from #{from_tag} to #{to_tag}\n\n"
146
+ say_formatted command + "\n\n"
147
+ system command
148
+ puts "" # newline
149
+ end
150
+
151
+
152
+ def calculate_new_tag
153
+ # if capistrano :tag is already set, just use it
154
+ if exists?("tag")
155
+ return fetch("tag")
156
+ end
157
+
158
+ # otherwise calculate, based on template
159
+
160
+ tag_suffix = fetch("tag_template", "%{datetime}")
161
+
162
+ tag_suffix.gsub!(/\%\{([^}]+)\}/) do
163
+ case $1
164
+ when 'date'
165
+ Time.now.localtime.strftime('%Y-%m-%d')
166
+ when 'datetime'
167
+ Time.now.localtime.strftime('%Y-%m-%d-%H%M')
168
+ when 'what'
169
+ (@__git_what = Capistrano::CLI.ui.ask("What does this release introduce? (this will be normalized and used in the tag for this release) ").gsub(/[ '"]+/, "_"))
170
+ when 'who'
171
+ `whoami`.chomp
172
+ end
173
+ end
174
+
175
+ return "#{tag_prefix}-#{tag_suffix}"
176
+ end
177
+
178
+ # will prompt to confirm new tag, if :confirm_tag is true, otherwise
179
+ # no-op.
180
+ def guard_confirm_tag(new_tag)
181
+ if exists?("confirm_tag") && [true, "true"].include?( confirm_tag )
182
+ prompt = "Do you really want to deploy "
183
+ prompt += new_tag
184
+ prompt += " to #{stage}" if exists? :stage
185
+ prompt += "?"
186
+
187
+ unless Capistrano::CLI.ui.agree(prompt)
188
+ abort("exiting, user cancelled.")
189
+ end
190
+ end
191
+ end
192
+
193
+
194
+ end
@@ -0,0 +1,301 @@
1
+ # Written using crazy meta-code cribbed from capistrano_ext so you
2
+ # can (and must) 'require' this file rather than 'load' it.
3
+ require 'capistrano'
4
+
5
+ unless Capistrano::Configuration.respond_to?(:instance)
6
+ abort "cap_git_tools requires Capistrano 2"
7
+ end
8
+
9
+ require 'cap_git_tools/task_helpers'
10
+
11
+
12
+
13
+ Capistrano::Configuration.instance.load do
14
+
15
+
16
+ namespace :git do
17
+ # include our helper methods, I believe just into this namespace
18
+ # if we do it this way.
19
+ extend CapGitTools::TaskHelpers
20
+
21
+ desc <<-DESC
22
+ Ensure git working copy has no uncommitted changes, or abort.
23
+
24
+ If cap :branch is set, will also ensure git working copy is on same
25
+ branch as :cap branch.
26
+
27
+ The idea is to make sure you're deploying what you're looking at.
28
+ See also git:guard_upstream, you often want to use both to ensure
29
+ this.
30
+
31
+ before "git:tag", "git:check_committed", "git:check_upstream"
32
+ or
33
+ before "deploy", , "git:check_committed", "git:check_upstream"
34
+
35
+ setting cap :skip_guard_committed to true will skip even if task is
36
+ invoked. (eg, `cap deploy -s skip_guard_upstream=true`)
37
+ DESC
38
+ task :guard_committed do
39
+ if [true, "true"].include? fetch("skip_guard_committed", false)
40
+ say_formatted("Skipping git:guard_committed")
41
+ else
42
+ if exists?("branch")
43
+ working_branch = `git symbolic-ref -q HEAD`.sub(%r{^refs/heads/}, '').chomp
44
+ unless fetch("branch") == working_branch
45
+ abort %Q{failed: guard_committed: wrong branch
46
+
47
+ You have configured to deploy from branch #{fetch("branch")}
48
+ but your git working copy is on branch #{working_branch}
49
+
50
+ git checkout #{fetch("branch")}
51
+
52
+ and try again. Or, to skip this check, execute cap again with:
53
+
54
+ -s skip_guard_committed=true
55
+ }
56
+ end
57
+ end
58
+
59
+ # cribbed from bundle release rake task
60
+ `git diff HEAD --exit-code`
61
+ return_code = $?.to_i
62
+ if return_code == 0
63
+ say_formatted("guard_clean: passed")
64
+ else
65
+ abort %Q{failed: guard_committed: uncomitted changes
66
+
67
+ There are files that need to be committed first.
68
+
69
+ Or, to skip this check, execute cap again with:
70
+ -s skip_guard_committed=true
71
+ }
72
+ end
73
+ end
74
+ end
75
+
76
+ desc <<-DESC
77
+ Ensure sure local git has been pushed to upstream, or abort
78
+
79
+ * 'upstream' is whatever you have configured as cap :repository
80
+ * Looks in :branch (default 'master') to see what branch should be checked,
81
+ Assumes local :branch tracks upstream_remote/branch
82
+
83
+ The idea is to ensure what you're deploying is what you're looking at.
84
+ See also git:guard_committed, you usually want to use both to ensure this.
85
+
86
+ before "git:tag", "git:check_committed", "git:check_upstream"
87
+ or if not using git:tag, eg
88
+ before "deploy", , "git:check_committed", "git:check_upstream"
89
+
90
+ setting cap :skip_guard_upstream to truewill skip even if task is invoked.
91
+ (eg, `cap deploy -s skip_guard_upstream=true`)
92
+ DESC
93
+ task :guard_upstream do
94
+ if [true, "true"].include? fetch("skip_guard_upstream", false)
95
+ say_formatted("Skipping git:guard_upstream")
96
+ else
97
+
98
+ ensure_git_fetch
99
+
100
+ remote_sha = `git log --pretty=format:%H #{upstream_remote}/#{working_branch} -1`.chomp
101
+
102
+ unless local_sha == remote_sha
103
+ abort %Q{failed:
104
+ Your local #{working_branch} branch is not up to date with #{upstream_remote}/#{working_branch}.
105
+ This will likely result in deploying something other than you expect.
106
+
107
+ Please make sure you have pulled and pushed all code before deploying:
108
+
109
+ git pull #{upstream_remote} #{working_branch}
110
+ # run tests, etc
111
+ git push #{upstream_remote} #{working_branch}
112
+
113
+ Or, to skip this check run cap again with `-s skip_guard_upstream=true`
114
+ }
115
+ end
116
+
117
+ say_formatted("guard_upstream: passed")
118
+ end
119
+ end
120
+
121
+ desc <<-DESC
122
+ Tags the current checkout and pushes tag to remote.
123
+
124
+ Normally will tag and deploy whatever is in your current git working
125
+ copy -- you may want to use with the guard tasks to make sure
126
+ you're deploying what you think and sync'ing it to your upstream
127
+ repository:
128
+
129
+ before "deploy", "git:guard_committed", "git:guard_upstream", "git:tag"
130
+
131
+ However, if you have set cap :branch, git:retag will tag the HEAD
132
+ of THAT branch, rather than whatever is the current working copy
133
+ branch.
134
+
135
+ Either way, git:tag:
136
+ * pushes the new tag to upstream remote git
137
+ * sets the cap :branch variable to the newly created tag, to be
138
+ sure cap deploys that tag.
139
+
140
+ What will the created tag look like?
141
+
142
+ Without multi-stage, by default something like `deploy-yyyy-mm-dd-hhmm`.
143
+
144
+ * The deploy- prefix will be the current stage name if multi-stage.
145
+ * The prefix can be manually set in config file or command line
146
+ with cap :tag_prefix variable instead.
147
+ * Somewhat experimental, you can also set :tag_template to change the
148
+ part after the prefix.
149
+ * or you can specify a complete tag on the cap command line `-s tag=deploy-whatever`.
150
+
151
+ `set :confirm_tag, true` in the config file to force an interactive
152
+ prompt and confirmation before continuing.
153
+ DESC
154
+ task :tag do
155
+
156
+ # make sure we have any other deployment tags that have been pushed by
157
+ # others so our auto-increment code doesn't create conflicting tags
158
+ ensure_git_fetch
159
+
160
+ tag = calculate_new_tag
161
+
162
+ commit_msg = @__git_what || "cap git:tag: #{tag}"
163
+
164
+ self.guard_confirm_tag(tag)
165
+
166
+ # tag 'working_branch', means :branch if set, otherwise
167
+ # current working directory checkout.
168
+ local_sh "git tag -a -m '#{commit_msg}' #{tag} #{self.working_branch}"
169
+
170
+ # Push new tag back to origin
171
+ local_sh "git push -q #{upstream_remote} #{tag}"
172
+
173
+ # set :branch to tag, so cap will continue on to deploy the tag we just created!
174
+ set(:branch, tag)
175
+ end
176
+
177
+ desc <<-DESC
178
+ Takes an already existing tag, and retags it and deploys that tag.
179
+
180
+ Will push the new tag to upstream repo, and set the new tag as cap
181
+ :branch so cap willd deploy it.
182
+
183
+ Usually used in git multistage for moving from staging to production,
184
+ for instance in your production.rb:
185
+
186
+ before "deploy", "git:retag"
187
+
188
+ Or use with the guard tasks:
189
+ before "deploy", "git:guard_committed", "git:guard_upstream", "git:retag"
190
+
191
+ `set :confirm_tag, true` in the config file to force an interactive
192
+ prompt and confirmation before continuing.
193
+
194
+ What tag will be used as source tag?
195
+
196
+ * Normally the most recent tag beginning "staging-"
197
+ * Or set cap :tag_prefix in config file or command line
198
+ to use a different prefix.
199
+ * Or set :tag_from in config file or on command line
200
+ to specify a specific tag. `cap deploy -s tag_from=staging_something`
201
+
202
+ What will the newly created tag look like? Same rules as for
203
+ git:tag.
204
+
205
+ * By default in a production stage it's going to look
206
+ like `production-yyyy-mm-dd-hhmm`, but there are several
207
+ of cap variables you can set in a config file to change this,
208
+ including :tag_prefix and :tag_template
209
+ DESC
210
+ task :retag do
211
+ from_tag = self.from_tag
212
+
213
+ to_tag = calculate_new_tag
214
+
215
+ self.guard_confirm_tag(from_tag)
216
+
217
+ say_formatted("git:retag taking #{from_tag} and retagging as #{to_tag}")
218
+
219
+ local_sh "git tag -a -m 'tagging #{from_tag} for deployment as #{to_tag}' #{to_tag} #{from_tag}"
220
+
221
+ # Push new tag back to origin
222
+ local_sh "git push -q #{upstream_remote} #{to_tag}"
223
+
224
+ set(:branch, to_tag)
225
+ end
226
+
227
+ desc <<-DESC
228
+ Show 5 most recent tags set by git:tag or git:retag
229
+
230
+ Can be used to see what you've deployed recently.
231
+
232
+ cap git:show_tags
233
+ or for multi-stage:
234
+ cap staging git:show_tags
235
+ cap production git:show_tags
236
+
237
+ Looks for tags matching the prefix that the tag or retag task
238
+ would use to tag. Ie, 'deploy-', or 'stagename-' in multi-stage,
239
+ or according to :tag_prefix setting.
240
+
241
+ Will also output date of tag, commit message, and account doing the commit.
242
+ DESC
243
+ task :show_tags do
244
+ # in newer versions of git you could prob do this with a git-log instead with
245
+ # certain arguments, but my local git is too old to support --tags arg properly.
246
+ system "git for-each-ref --count=4 --sort='-taggerdate' --format='\n* %(refname:short)\n Tagger: %(taggeremail)\n Date: %(taggerdate)\n\n %(subject)' 'refs/tags/#{tag_prefix}-*' "
247
+ end
248
+
249
+
250
+ desc <<-DESC
251
+ Show log between most tagged deploy and what would be deployed now.
252
+
253
+ Requires you to be using git:tag or git:retag to make any sense,
254
+ so we can find the 'last deployed' tag to compare.
255
+
256
+ You can run this manually:
257
+ cap git:commit_log
258
+ Or for multi-stage, perhaps:
259
+ cap staging git:commit_log
260
+ cap production git:commit_log
261
+ Or you can use cap callbacks to ensure this is shown before
262
+ a deploy, for multi-stage for instance add to your production.rb:
263
+ before "git:retag", "git:commit_log"
264
+ # and force an interactive confirmation after they've seen it
265
+ set :confirm_retag, true
266
+
267
+ Ordinarily shows commit log between current git working copy
268
+ (forced to current head of :branch if cap :branch is set), and
269
+ last deployed tag, by default tag beginning "deploy-", or
270
+ tag beginning :stage if you are cap multi-stage, or beginning
271
+ with :tag_prefix if that is set.
272
+
273
+ Hard-coded to do something special if you are using multistage
274
+ cap, and are in stage 'production' -- in that case it will
275
+ show you the commits between the most recent production-* tag,
276
+ and the most recent staging-* tag. (Cap :tag_prefix and :from_prefix
277
+ can change those tag prefixes).
278
+ DESC
279
+ task :commit_log do
280
+ from, to = nil, nil
281
+
282
+ if exists?("stage") && stage.to_s == "production"
283
+ # production stage in multi-stage
284
+ from = fetch_last_tag # last deploy-* tag, or last :tag_prefix tag
285
+ to = from_tag # last staging-* tag, or last :from_prefix tag
286
+ else
287
+ # 'staging' stage in multi-stage, or else any old
288
+ # non-multistage.
289
+ from = fetch_last_tag # last deploy-* tag, or last :tag_prefix tag
290
+ to = local_sha.slice(0,8) # current git working copy, or local branch head.
291
+ end
292
+
293
+ show_commit_log(from, to)
294
+ end
295
+
296
+
297
+
298
+ end
299
+
300
+
301
+ end
@@ -0,0 +1,3 @@
1
+ module CapGitTools
2
+ VERSION = "0.8.0"
3
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cap_git_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonathan Rochkind
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ description:
31
+ email:
32
+ - jonathan@dnil.net
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - README.md
40
+ - Rakefile
41
+ - cap_git_tools.gemspec
42
+ - lib/cap_git_tools.rb
43
+ - lib/cap_git_tools/task_helpers.rb
44
+ - lib/cap_git_tools/tasks.rb
45
+ - lib/cap_git_tools/version.rb
46
+ homepage: ''
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project: cap_git_tools
66
+ rubygems_version: 1.8.24
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: re-usable, composable Capistrano tasks for git tagging and other work with
70
+ a git repo
71
+ test_files: []