factorylabs-auto_tagger 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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