zilkey-auto_tagger 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AutoTagger
2
2
 
3
- AutoTagger allows you to create a date-stamped tag for each stage of your deployment, and deploy from the last tag from the previous environment.
3
+ AutoTagger is a gem that helps you automatically create a date-stamped tag for each stage of your deployment, and deploy from the last tag from the previous environment.
4
4
 
5
5
  Let's say you have the following workflow:
6
6
 
@@ -10,9 +10,38 @@ Let's say you have the following workflow:
10
10
 
11
11
  You can use the `autotag` command to tag releases on your CI box, then use the capistrano tasks to auto-tag each release.
12
12
 
13
+ ## Installation
14
+
15
+ gem sources -a http://gems.github.com
16
+ sudo gem install zilkey-auto_tagger
17
+
18
+ ## Contribute
19
+
20
+ * [Tracker Project](http://www.pivotaltracker.com/projects/11988)
21
+ * [GitHub Repository](http://github.com/zilkey/auto_tagger/tree/master)
22
+
23
+ ## The autotag executable
24
+
25
+ Installing the gem creates an executable file named autotag, which takes two arguments: the stage, and optionally the path to the git repo:
26
+
27
+ $ autotag demo # => creates a tag like demo/200804041234 in the current directory
28
+ $ autotag demo . # => same as above
29
+ $ autotag demo /Users/me/foo # => cd's to /Users/me/foo before creating the tag
30
+
31
+ Running autotag does the following:
32
+
33
+ $ git fetch origin --tags
34
+ $ git tag <stage>/<timestamp>
35
+ $ git push origin --tags
36
+
13
37
  ## Capistrano Integration
14
38
 
15
- Example deploy file:
39
+ AutoTagger comes with 2 capistrano tasks:
40
+
41
+ * `release_tagger:set_branch` tries to set the branch to the last tag from the previous environment.
42
+ * `release_tagger:create_tag` runs autotag for the current stage
43
+
44
+ Example `config/deploy.rb` file:
16
45
 
17
46
  require 'release_tagger'
18
47
 
@@ -35,7 +64,7 @@ Example deploy file:
35
64
 
36
65
  # You need to add the before/ater callbacks yourself
37
66
  before "deploy:update_code", "release_tagger:set_branch"
38
- after "deploy:update_code", "release_tagger:create_tag"
67
+ after "deploy", "release_tagger:create_tag"
39
68
 
40
69
  Assume you have the following tags in your git repository:
41
70
 
@@ -45,32 +74,13 @@ Assume you have the following tags in your git repository:
45
74
 
46
75
  The deployments would look like this:
47
76
 
48
- cap staging deploy # => ci/01
49
- cap production deploy # => staging/01
77
+ cap staging deploy # => sets branch to ci/01
78
+ cap production deploy # => sets branch to staging/01
50
79
 
51
80
  You can override with with the -Shead and -Stag options
52
81
 
53
- cap staging deploy -Shead=true # => master
54
- cap staging deploy -Stag=staging/01 # => staging/01
55
-
56
- ## The autotag executable
57
-
58
- autotag -h
59
- autotag demo
60
- autotag demo .
61
- autotag demo /Users/me/foo
62
-
63
- ## Known Issues
64
-
65
- * DOES NOT work with capistrano ext multi-stage
66
- * It will accept invalid tag names (if you specify a tag name with a space, it will blow up when you try to create the tag)
67
-
68
- ## Things that might be useful
69
-
70
- * Make it possible to define a different remote other than "origin"
71
- * Make it possible to define a different default branch other than "master"
72
- * Make it work with either cap-ext multistage or single-file deploy.rb files
73
- * Make it possible to provide your own tag naming convention (like the PaperClip string interpolation), instead of relying on <prefix>/<timestamp>
82
+ cap staging deploy -Shead=true # => sets branch to master
83
+ cap staging deploy -Stag=staging/01 # => sets branch to staging/01
74
84
 
75
85
  ## Links
76
86
 
@@ -11,9 +11,9 @@ class AutoTagger
11
11
  @stage = stage
12
12
  end
13
13
 
14
- def create_tag
14
+ def create_tag(commit = nil)
15
15
  repository.tags.fetch
16
- new_tag = repository.tags.create(stage)
16
+ new_tag = repository.tags.create(stage, commit)
17
17
  repository.tags.push
18
18
  new_tag
19
19
  end
@@ -1,26 +1,16 @@
1
1
  class CapistranoHelper
2
2
 
3
- class NoStagesSpecifiedError < StandardError
4
- def message
5
- "You must set the :stages variable to an array, like set :stages, [:ci, :demo]"
6
- end
7
- end
8
-
9
- attr_reader :variables, :stages, :current_stage, :working_directory
3
+ attr_reader :variables, :current_stage, :working_directory
10
4
 
11
5
  def initialize(variables)
12
- raise NoStagesSpecifiedError unless variables[:stages]
6
+ @stage_manager = StageManager.new(variables[:stages])
13
7
  @variables = variables
14
- @stages = variables[:stages]
15
8
  @current_stage = variables[:current_stage]
16
9
  @working_directory = variables[:working_directory] || Dir.pwd
17
10
  end
18
11
 
19
12
  def previous_stage
20
- if current_stage
21
- index = stages.index(current_stage) - 1
22
- stages[index] if index > -1
23
- end
13
+ @stage_manager.previous_stage(current_stage)
24
14
  end
25
15
 
26
16
  def branch
@@ -35,4 +25,15 @@ class CapistranoHelper
35
25
  end
36
26
  end
37
27
 
28
+ def release_tag_entries
29
+ entries = []
30
+ @stage_manager.stages.each do |stage|
31
+ tagger = AutoTagger.new(stage, working_directory)
32
+ tag = tagger.latest_tag
33
+ commit = tagger.repository.commit_for(tag)
34
+ entries << "#{stage.to_s.ljust(10, " ")} #{tag.to_s.ljust(30, " ")} #{commit.to_s}"
35
+ end
36
+ entries
37
+ end
38
+
38
39
  end
@@ -27,6 +27,10 @@ class Repository
27
27
  @tags ||= Tag.new(self)
28
28
  end
29
29
 
30
+ def commit_for(tag)
31
+ Commander.execute(path, "git --no-pager log #{tag} --pretty=oneline -1")
32
+ end
33
+
30
34
  def run(cmd)
31
35
  Commander.execute(path, cmd)
32
36
  end
@@ -0,0 +1,23 @@
1
+ class StageManager
2
+
3
+ class NoStagesSpecifiedError < StandardError
4
+ def message
5
+ "You must set the :stages variable to an array, like set :stages, [:ci, :demo]"
6
+ end
7
+ end
8
+
9
+ attr_reader :stages
10
+
11
+ def initialize(stages)
12
+ raise NoStagesSpecifiedError unless stages && stages.is_a?(Array)
13
+ @stages = stages
14
+ end
15
+
16
+ def previous_stage(current_stage)
17
+ if current_stage
18
+ index = stages.index(current_stage) - 1
19
+ stages[index] if index > -1
20
+ end
21
+ end
22
+
23
+ end
@@ -1,3 +1,5 @@
1
+ # git --no-pager log --pretty=oneline -1
2
+ # git tag -a -m 'Successful continuous integration build on #{timestamp}' #{tag_name}"
1
3
  class Tag
2
4
 
3
5
  attr_reader :repository
@@ -22,10 +24,11 @@ class Tag
22
24
  repository.run! "git push origin --tags"
23
25
  end
24
26
 
25
- def create(stage)
26
- # git tag -a -m 'Successful continuous integration build on #{timestamp}' #{tag_name}"
27
+ def create(stage, commit = nil)
27
28
  tag_name = name_for(stage)
28
- repository.run! "git tag #{tag_name}"
29
+ cmd = "git tag #{tag_name}"
30
+ cmd += " #{commit}" if commit
31
+ repository.run! cmd
29
32
  tag_name
30
33
  end
31
34
 
data/lib/auto_tagger.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  'repository',
4
4
  'tag',
5
5
  'auto_tagger',
6
+ 'stage_manager',
6
7
  'capistrano_helper'
7
8
  ].each do |file|
8
9
  require File.expand_path(File.join(File.dirname(__FILE__), "auto_tagger", file))
@@ -11,15 +11,41 @@ Capistrano::Configuration.instance(:must_exist).load do
11
11
  set :branch, branch_name
12
12
  logger.info "setting branch to #{branch_name}"
13
13
  else
14
- logger.info "AUTO TAGGER WARNING: skipping auto-assignment of branch. Branch will remain the default.}"
14
+ logger.info "AUTO TAGGER: skipping auto-assignment of branch. Branch will remain the default.}"
15
+ end
16
+ end
17
+
18
+ desc %Q{Prints the most current tags from all stages}
19
+ task :print_latest_tags, :roles => :app do
20
+ logger.info "AUTO TAGGER: release tag history is:"
21
+ entries = CapistranoHelper.new(variables).release_tag_entries
22
+ entries.each do |entry|
23
+ logger.info entry
24
+ end
25
+ end
26
+
27
+ desc %Q{Reads the text file with the latest tag from the shared directory}
28
+ task :read_tag_from_shared, :roles => :app do
29
+ logger.info "AUTO TAGGER: latest tag deployed to this environment was:"
30
+ run "cat #{shared_path}/released_git_tag.txt"
31
+ end
32
+
33
+ desc %Q{Writes the tag name to a file in the shared directory}
34
+ task :write_tag_to_shared, :roles => :app do
35
+ if exists?(:branch)
36
+ logger.info "AUTO TAGGER: writing tag to shared text file on remote server"
37
+ run "echo '#{branch}' > #{shared_path}/released_git_tag.txt"
38
+ else
39
+ logger.info "AUTO TAGGER: no branch available. Text file was not written to server"
15
40
  end
16
41
  end
17
42
 
18
43
  desc %Q{Creates a tag using the current_stage variable}
19
- task :create_tag do
44
+ task :create_tag, :roles => :app do
20
45
  if variables[:current_stage]
21
- tag_name = AutoTagger.new(variables[:current_stage], variables[:working_directory]).create_tag
22
- logger.info "created and pushed tag #{tag_name}"
46
+ previous_tag = AutoTagger.new(StageManager.new(stages).previous_stage(current_stage), Dir.pwd).latest_tag
47
+ tag_name = AutoTagger.new(variables[:current_stage], variables[:working_directory]).create_tag(previous_tag)
48
+ logger.info "AUTO TAGGER created tag #{tag_name} from #{previous_tag.inspect}"
23
49
  else
24
50
  logger.info "AUTO TAGGER WARNING: skipping auto-creation of tag. Please specify :current_stage to enable auto-creation of tags (like set :current_stage, :ci)."
25
51
  end
@@ -43,6 +43,19 @@ describe AutoTagger do
43
43
 
44
44
  AutoTagger.new("ci", "/foo").create_tag
45
45
  end
46
+
47
+ it "allows you to base it off an existing tag or commit" do
48
+ time = Time.local(2001,1,1)
49
+ mock(Time).now.once {time}
50
+ timestamp = time.utc.strftime('%Y%m%d%H%M%S')
51
+ mock(File).exists?(anything).twice { true }
52
+
53
+ mock(Commander).execute!("/foo", "git fetch origin --tags") {true}
54
+ mock(Commander).execute!("/foo", "git tag ci/#{timestamp} guid") {true}
55
+ mock(Commander).execute!("/foo", "git push origin --tags") {true}
56
+
57
+ AutoTagger.new("ci", "/foo").create_tag("guid")
58
+ end
46
59
 
47
60
  it "returns the tag that was created" do
48
61
  time = Time.local(2001,1,1)
@@ -6,7 +6,7 @@ describe CapistranoHelper do
6
6
  it "blows up if there are no stages" do
7
7
  proc do
8
8
  CapistranoHelper.new({})
9
- end.should raise_error(CapistranoHelper::NoStagesSpecifiedError)
9
+ end.should raise_error(StageManager::NoStagesSpecifiedError)
10
10
  end
11
11
  end
12
12
 
@@ -16,12 +16,6 @@ describe CapistranoHelper do
16
16
  end
17
17
  end
18
18
 
19
- describe "#stages" do
20
- it "returns the hashes' stages value" do
21
- CapistranoHelper.new({:stages => [:bar]}).stages.should == [:bar]
22
- end
23
- end
24
-
25
19
  describe "#working_directory" do
26
20
  it "returns the hashes' working directory value" do
27
21
  CapistranoHelper.new({:stages => [:bar], :working_directory => "/foo"}).working_directory.should == "/foo"
@@ -40,17 +34,24 @@ describe CapistranoHelper do
40
34
  end
41
35
  end
42
36
 
43
- describe "#previous_stage" do
44
- it "returns the previous stage if there is more than one stage, and there is a current stage" do
45
- CapistranoHelper.new({:stages => [:foo, :bar], :current_stage => :bar}).previous_stage.should == :foo
46
- end
47
-
48
- it "returns nil if there is no previous stage" do
49
- CapistranoHelper.new({:stages => [:bar], :current_stage => :bar}).previous_stage.should be_nil
50
- end
51
-
52
- it "returns nil if there is no current stage" do
53
- CapistranoHelper.new({:stages => [:bar]}).previous_stage.should be_nil
37
+ describe "#release_tag_entries" do
38
+ it "returns a column-justifed version of all the commits" do
39
+ mock(Commander).execute("/foo", "git tag").times(any_times) { "ci_01\nstaging_01\nproduction_01" }
40
+ mock(Commander).execute("/foo", "git --no-pager log ci_01 --pretty=oneline -1") { "guid1" }
41
+ mock(Commander).execute("/foo", "git --no-pager log staging_01 --pretty=oneline -1") { "guid2" }
42
+ mock(Commander).execute("/foo", "git --no-pager log production_01 --pretty=oneline -1") { "guid3" }
43
+ mock(Commander).execute!("/foo", "git fetch origin --tags").times(any_times) { true }
44
+ mock(File).exists?(anything).times(any_times) {true}
45
+
46
+ variables = {
47
+ :working_directory => "/foo",
48
+ :stages => [:ci, :staging, :production]
49
+ }
50
+ histories = CapistranoHelper.new(variables).release_tag_entries
51
+ histories.length.should == 3
52
+ histories[0].should include("ci_01", "guid1")
53
+ histories[1].should include("staging_01", "guid2")
54
+ histories[2].should include("production_01", "guid3")
54
55
  end
55
56
  end
56
57
 
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe StageManager do
4
+
5
+ describe ".new" do
6
+ [nil, ""].each do |value|
7
+ it "blows up if there are stages == #{value.inspect}" do
8
+ proc do
9
+ StageManager.new(value)
10
+ end.should raise_error(StageManager::NoStagesSpecifiedError)
11
+ end
12
+ end
13
+ end
14
+
15
+ describe "#previous_stage" do
16
+ it "returns the previous stage if there is more than one stage, and there is a current stage" do
17
+ StageManager.new([:foo, :bar]).previous_stage(:bar).should == :foo
18
+ end
19
+
20
+ it "returns nil if there is no previous stage" do
21
+ StageManager.new([:bar]).previous_stage(:bar).should be_nil
22
+ end
23
+
24
+ it "returns nil if there is no current stage" do
25
+ StageManager.new([:bar]).previous_stage(nil).should be_nil
26
+ end
27
+ end
28
+
29
+
30
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zilkey-auto_tagger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dean
@@ -36,6 +36,7 @@ files:
36
36
  - lib/auto_tagger/capistrano_helper.rb
37
37
  - lib/auto_tagger/commander.rb
38
38
  - lib/auto_tagger/repository.rb
39
+ - lib/auto_tagger/stage_manager.rb
39
40
  - lib/auto_tagger/tag.rb
40
41
  - lib/auto_tagger.rb
41
42
  - recipes/release_tagger.rb
@@ -45,6 +46,7 @@ files:
45
46
  - spec/auto_tagger/capistrano_helper_spec.rb
46
47
  - spec/auto_tagger/commander_spec.rb
47
48
  - spec/auto_tagger/repository_spec.rb
49
+ - spec/auto_tagger/stage_manager_spec.rb
48
50
  - spec/auto_tagger/tag_spec.rb
49
51
  - spec/spec_helper.rb
50
52
  - MIT-LICENSE