factorylabs-auto_tagger 0.1.1

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.
@@ -0,0 +1,29 @@
1
+ Feature: Deployment
2
+ In order to get auto-tagging goodness
3
+ As a ruby and git ninja
4
+ I want cap to do all the work for me
5
+
6
+ Scenario: user deploys with single file deploy.rb with 3 stages
7
+ Given a three-stage app using single deploy file
8
+ And a ci tag
9
+ When I deploy to staging
10
+ Then a tag should be added to git
11
+
12
+ Scenario: user deploys with single file deploy.rb with no stages
13
+ Given a one-stage app using single deploy file with the following environments:
14
+ |production |
15
+ When I deploy
16
+ Then a "production" tag should be added to git
17
+
18
+ Scenario: user deploys with single file deploy.rb stages with dashes in the name
19
+ Given a one-stage app using single deploy file with the following environments:
20
+ |staging |
21
+ |secret-production |
22
+ When I deploy to secret-production
23
+ Then a "secret-production" tag should be added to git
24
+
25
+ Scenario: user deploys with cap-ext multistage
26
+ Given a three-stage app using cap-multistage
27
+ And a ci tag
28
+ When I deploy to staging
29
+ Then a tag should be added to git
@@ -0,0 +1,41 @@
1
+ Given /^a repo$/ do
2
+ puts
3
+ helpers = StepHelpers.new
4
+ helpers.create_git_repo
5
+ helpers.create_app
6
+ @tags = helpers.tags
7
+ puts
8
+ end
9
+
10
+ When /^I run autotag with no arguments$/ do
11
+ puts
12
+ helpers = StepHelpers.new
13
+ @output = helpers.run_autotag
14
+ @tags = helpers.tags
15
+ puts
16
+ end
17
+
18
+ When /^I run autotag with "([^\"]*)"$/ do |args|
19
+ puts
20
+ helpers = StepHelpers.new
21
+ @output = helpers.run_autotag(args)
22
+ @tags = helpers.tags
23
+ puts
24
+ end
25
+
26
+ Then /^I should see "([^\"]*)"$/ do |text|
27
+ @output.should =~ /#{Regexp.escape(text)}/
28
+ end
29
+
30
+ Then /^no tags should be created$/ do
31
+ @tags.strip.should == ""
32
+ end
33
+
34
+ Then /^a "([^\"]*)" tag should be added to git$/ do |stage|
35
+ helpers = StepHelpers.new
36
+ helpers.tags.starts_with?(stage).should be_true
37
+ end
38
+
39
+ Then /^a "([^\"]*)" tag should be created$/ do |prefix|
40
+ @tags.strip.split("\n").any?{|tag| tag.starts_with?("demo")}.should be_true
41
+ end
@@ -0,0 +1,53 @@
1
+ Given /^a three-stage app using single deploy file$/ do
2
+ puts
3
+ helpers = StepHelpers.new
4
+ helpers.create_app_with_single_deploy_file([:ci, :staging, :production])
5
+ puts
6
+ @tags = helpers.tags
7
+ end
8
+
9
+ Given /^a one\-stage app using single deploy file with the following environments:$/ do |table|
10
+ puts
11
+ helpers = StepHelpers.new
12
+ helpers.create_app_with_single_deploy_file table.raw.map(&:first)
13
+ puts
14
+ @tags = helpers.tags
15
+ end
16
+
17
+ Given /^a three-stage app using cap-multistage$/ do
18
+ puts
19
+ helpers = StepHelpers.new
20
+ helpers.create_app_with_cap_ext_multistage
21
+ puts
22
+ @tags = helpers.tags
23
+ end
24
+
25
+ Given /^a ci tag$/ do
26
+ puts
27
+ helpers = StepHelpers.new
28
+ helpers.autotag("ci")
29
+ @tags = helpers.tags
30
+ puts
31
+ end
32
+
33
+ When /^I deploy to (.*)$/ do |environment|
34
+ puts
35
+ helpers = StepHelpers.new
36
+ helpers.deploy(environment)
37
+ puts
38
+ end
39
+
40
+ When /^I deploy$/ do
41
+ puts
42
+ helpers = StepHelpers.new
43
+ helpers.deploy
44
+ puts
45
+ end
46
+
47
+ Then /^a tag should be added to git$/ do
48
+ puts
49
+ helpers = StepHelpers.new
50
+ new_tags = helpers.tags
51
+ @tags.length.should < new_tags.length
52
+ puts
53
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec'
2
+ require 'erb'
3
+ require 'etc'
4
+ require 'activesupport'
5
+
6
+ Before do
7
+ StepHelpers.new.reset
8
+ end
@@ -0,0 +1,136 @@
1
+ class StepHelpers
2
+
3
+ attr_reader :test_files_dir, :app_dir, :repo_dir
4
+
5
+ def initialize
6
+ @test_files_dir = File.join(Dir.pwd, "test_files")
7
+ @app_dir = File.join(test_files_dir, "app")
8
+ @repo_dir = File.join(test_files_dir, "repo")
9
+ end
10
+
11
+ def reset
12
+ FileUtils.rm_r(test_files_dir) if File.exists?(test_files_dir)
13
+ FileUtils.mkdir_p(test_files_dir)
14
+ end
15
+
16
+ def create_git_repo
17
+ FileUtils.mkdir_p repo_dir
18
+ `cd #{repo_dir} && git --bare init`
19
+ end
20
+
21
+ def create_app_with_single_deploy_file(environments)
22
+ create_git_repo
23
+ create_app
24
+ capify_app
25
+ create_single_deploy_file(environments)
26
+ end
27
+
28
+ def run_autotag(args = nil)
29
+ cmd = "cd #{app_dir} && ../../bin/autotag"
30
+ cmd += " #{args}" if args
31
+ `#{cmd}`
32
+ end
33
+
34
+ def create_app_with_cap_ext_multistage
35
+ create_git_repo
36
+ create_app
37
+ capify_app
38
+ create_cap_ext_multistage_deploy_files
39
+ end
40
+
41
+ def deploy(stage = nil)
42
+ deploy_command = "cap "
43
+ deploy_command += "#{stage} " if stage
44
+ deploy_command += "deploy"
45
+
46
+ run_commands [
47
+ "cd #{app_dir}",
48
+ "cap deploy:setup",
49
+ deploy_command
50
+ ]
51
+ end
52
+
53
+ def autotag(stage)
54
+ system "cd #{app_dir} && git tag #{stage}/#{Time.now.utc.strftime('%Y%m%d%H%M%S')} && git push origin --tags"
55
+ end
56
+
57
+ def tags
58
+ system "cd #{app_dir} && git fetch origin --tags"
59
+ tags = `cd #{app_dir} && git tag`
60
+ puts tags
61
+ tags
62
+ end
63
+
64
+ def create_app
65
+ FileUtils.mkdir_p app_dir
66
+ run_commands [
67
+ "cd #{app_dir}",
68
+ "touch README",
69
+ "git init",
70
+ "git add .",
71
+ %Q{git commit -m "first commit"},
72
+ "git remote add origin file://#{repo_dir}",
73
+ "git push origin master"
74
+ ]
75
+ end
76
+
77
+ private
78
+
79
+ def capify_app
80
+ run_commands [
81
+ "cd #{app_dir}",
82
+ "mkdir config",
83
+ "capify ."
84
+ ]
85
+ end
86
+
87
+ def create_single_deploy_file(environments)
88
+ repository = repo_dir
89
+ deploy_to = File.join(test_files_dir, "deployed")
90
+ git_location = `which git`.strip
91
+ user = Etc.getlogin
92
+
93
+ path = File.expand_path(File.join(__FILE__, "..", "..", "templates", "deploy.erb"))
94
+ #puts "TRACE %s:%s" % [__FILE__, __LINE__]
95
+ #puts path
96
+ #puts File.exists?(path)
97
+
98
+ template = ERB.new File.read(path)
99
+ output = template.result(binding)
100
+ File.open(File.join(app_dir, "config", "deploy.rb"), 'w') {|f| f.write(output) }
101
+ end
102
+
103
+ def create_cap_ext_multistage_deploy_files
104
+ repository = repo_dir
105
+ deploy_to = File.join(test_files_dir, "deployed")
106
+ git_location = `which git`.strip
107
+ user = Etc.getlogin
108
+ environments = [:ci, :staging, :production]
109
+
110
+ path = File.expand_path(File.join(__FILE__, "..", "..", "templates", "cap_ext_deploy.erb"))
111
+
112
+ template = ERB.new File.read(path)
113
+ output = template.result(binding)
114
+ File.open(File.join(app_dir, "config", "deploy.rb"), 'w') {|f| f.write(output) }
115
+
116
+ %w(staging production).each do |stage|
117
+ create_cap_ext_multistage_deploy_stage_file(stage)
118
+ end
119
+ end
120
+
121
+ def create_cap_ext_multistage_deploy_stage_file(stage)
122
+ deploy_subdir = File.join(app_dir, "config", "deploy")
123
+ FileUtils.mkdir_p deploy_subdir
124
+
125
+ template_path = File.expand_path(File.join(__FILE__, "..", "..", "templates", "stage.erb"))
126
+ template = ERB.new File.read(template_path)
127
+ output = template.result(binding)
128
+
129
+ File.open(File.join(deploy_subdir, "#{stage}.rb"), 'w') {|f| f.write(output) }
130
+ end
131
+
132
+ def run_commands(commands)
133
+ puts `#{commands.join(" && ")}`
134
+ end
135
+
136
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "recipes", "release_tagger"))
2
+
3
+ set :autotagger_stages, [:ci, :staging, :production]
4
+ set :stages, [:staging, :production]
5
+ set :default_stage, :staging
6
+
7
+ require 'capistrano/ext/multistage'
8
+
9
+ set :application, "deployed"
10
+ set :user, "<%= user %>"
11
+ set :repository, "file://<%= repository %>"
12
+ set :scm, :git
13
+ set :scm_command, "<%= git_location %>"
14
+
15
+ set :deploy_to, "<%= deploy_to %>"
16
+
17
+ set :run_method, :run
18
+ set :ssh_options, { :forward_agent => true }
19
+ default_run_options[:pty] = true
20
+
21
+ role :app, "localhost" # => this must be mapped
22
+
23
+ namespace :deploy do
24
+ task :restart do
25
+ puts "restarting..."
26
+ end
27
+ end
28
+
29
+ before "deploy:update_code", "release_tagger:set_branch"
30
+ after "deploy", "release_tagger:create_tag"
31
+ after "deploy", "release_tagger:write_tag_to_shared"
32
+ after "deploy", "release_tagger:print_latest_tags"
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "recipes", "release_tagger"))
2
+
3
+ set :autotagger_stages, ["<%= environments.join('", "') %>"]
4
+
5
+ set :application, "deployed"
6
+ set :user, "<%= user %>"
7
+ set :repository, "file://<%= repository %>"
8
+ set :deploy_to, "<%= deploy_to %>"
9
+ set :scm, :git
10
+ set :scm_command, "<%= git_location %>"
11
+
12
+ set :run_method, :run
13
+ set :ssh_options, { :forward_agent => true }
14
+ default_run_options[:pty] = true
15
+
16
+ role :app, "localhost" # => this must be mapped
17
+
18
+
19
+ namespace :deploy do
20
+ task :restart do
21
+ puts "restarting..."
22
+ end
23
+ end
24
+
25
+ <% environments.each do |environment| %>
26
+ task "<%= environment %>" do
27
+ set :stage, "<%= environment %>"
28
+ end
29
+ <% end %>
30
+
31
+ before "deploy:update_code", "release_tagger:set_branch"
32
+ after "deploy", "release_tagger:create_tag"
33
+ after "deploy", "release_tagger:write_tag_to_shared"
34
+ after "deploy", "release_tagger:print_latest_tags"
@@ -0,0 +1 @@
1
+ # nothing to see here...
@@ -0,0 +1,7 @@
1
+ gems:
2
+ - name: capistrano
3
+ version: '>= 2.5.3'
4
+ - name: capistrano-ext
5
+ version: '>= 1.2.1'
6
+ - name: activesupport
7
+ version: '>= 2.3.2'
@@ -0,0 +1,10 @@
1
+ [
2
+ 'commander',
3
+ 'repository',
4
+ 'tag',
5
+ 'auto_tagger',
6
+ 'stage_manager',
7
+ 'capistrano_helper'
8
+ ].each do |file|
9
+ require File.expand_path(File.join(File.dirname(__FILE__), "auto_tagger", file))
10
+ end
@@ -0,0 +1,26 @@
1
+ class AutoTagger
2
+
3
+ class EnvironmentCannotBeBlankError < StandardError; end
4
+
5
+ attr_reader :stage, :repository, :working_directory
6
+
7
+ def initialize(stage, path = nil)
8
+ raise EnvironmentCannotBeBlankError if stage.to_s.strip == ""
9
+ @working_directory = File.expand_path(path ||= Dir.pwd)
10
+ @repository = Repository.new(@working_directory)
11
+ @stage = stage
12
+ end
13
+
14
+ def create_tag(commit = nil)
15
+ repository.tags.fetch
16
+ new_tag = repository.tags.create(stage, commit)
17
+ repository.tags.push
18
+ new_tag
19
+ end
20
+
21
+ def latest_tag
22
+ repository.tags.fetch
23
+ repository.tags.latest_from(stage)
24
+ end
25
+
26
+ end
@@ -0,0 +1,39 @@
1
+ class CapistranoHelper
2
+
3
+ attr_reader :variables, :stage, :working_directory
4
+
5
+ def initialize(variables)
6
+ @stage_manager = StageManager.new(variables[:autotagger_stages])
7
+ @variables = variables
8
+ @stage = variables[:stage]
9
+ @working_directory = variables[:working_directory] || Dir.pwd
10
+ end
11
+
12
+ def previous_stage
13
+ @stage_manager.previous_stage(stage)
14
+ end
15
+
16
+ def branch
17
+ if variables.has_key?(:head)
18
+ variables[:branch]
19
+ elsif variables.has_key?(:tag)
20
+ variables[:tag]
21
+ elsif previous_stage && (latest = AutoTagger.new(previous_stage, working_directory).latest_tag)
22
+ latest
23
+ else
24
+ variables[:branch]
25
+ end
26
+ end
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
+
39
+ end
@@ -0,0 +1,15 @@
1
+ class Commander
2
+ class << self
3
+ def execute(path, cmd)
4
+ `#{command_in_context(path, cmd)}`
5
+ end
6
+
7
+ def execute!(path, cmd)
8
+ system command_in_context(path, cmd)
9
+ end
10
+
11
+ def command_in_context(path, cmd)
12
+ "cd #{path} && #{cmd}"
13
+ end
14
+ end
15
+ end