plus2_git_tagger 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Rakefile +11 -0
- data/lib/plus2_git_tagger.rb +7 -0
- data/lib/plus2_git_tagger/git.rb +58 -0
- data/lib/plus2_git_tagger/tags.rb +141 -0
- data/lib/plus2_git_tagger/task.rb +124 -0
- data/lib/plus2_git_tagger/version.rb +3 -0
- data/plus2_git_tagger.gemspec +20 -0
- metadata +76 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class GemHelper
|
5
|
+
def rubygem_push(path)
|
6
|
+
out, _ = sh("gem inabox '#{path}'")
|
7
|
+
raise "Gem push failed due to lack of RubyGems.org credentials." if out[/Enter your RubyGems.org credentials/]
|
8
|
+
Bundler.ui.confirm "Pushed #{name} #{version} to local gems"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Plus2GitTagger
|
2
|
+
class Git < Struct.new( :repo )
|
3
|
+
def initialize(*)
|
4
|
+
super
|
5
|
+
self.repo = Pathname( repo ).expand_path
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
# Queries git for HEAD's subject.
|
10
|
+
#
|
11
|
+
# Returns a string containing HEAD's subject.
|
12
|
+
def current_subject
|
13
|
+
git_s('log --pretty="format:%s" -1').chomp
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Naive: remove quotes.
|
18
|
+
def escaped_current_subject
|
19
|
+
current_subject.gsub(/["']/, '')
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# Try to commit, but don't worry if it doesn't work because it wasn't needed.
|
24
|
+
def commit_if_required(subject)
|
25
|
+
result = git_s("commit -uno -m '#{ subject }' 2>&1")
|
26
|
+
|
27
|
+
unless $?.success? || result[/nothing to commit/i] || result[/no changes added to commit/i]
|
28
|
+
abort result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Returns a list of all tags for this repo.
|
34
|
+
def tags
|
35
|
+
git_s('show-ref --tags --abbrev=1').split("\n").map {|line| line.split(/\s/).last.chomp.sub(%r[^refs/tags/],'')}
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Run git.
|
40
|
+
def git( cmd )
|
41
|
+
Dir.chdir( repo ) do
|
42
|
+
system "git #{cmd}"
|
43
|
+
|
44
|
+
abort("'git #{cmd}' failed") unless $?.success?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias_method :run, :git
|
48
|
+
|
49
|
+
|
50
|
+
# Run git, capture stdout.
|
51
|
+
def git_s( cmd )
|
52
|
+
Dir.chdir( repo ) do
|
53
|
+
`git #{cmd}`
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Plus2GitTagger
|
2
|
+
class Tags < Struct.new( :git_helper, :tag_prefix )
|
3
|
+
|
4
|
+
|
5
|
+
def make!
|
6
|
+
if last_tag = todays_tags.sort.last
|
7
|
+
tag = next_tag(last_tag)
|
8
|
+
else
|
9
|
+
tag = base_tag
|
10
|
+
end
|
11
|
+
|
12
|
+
luser = git_s("config user.name").chomp
|
13
|
+
|
14
|
+
git "tag -m'auto-tagged by #{luser}' #{tag}"
|
15
|
+
|
16
|
+
|
17
|
+
banner "Behold a tag! #{ tag }"
|
18
|
+
|
19
|
+
git "push origin --tags"
|
20
|
+
|
21
|
+
banner "Your tag has been pushed automatically.", "Please don't forget to push your current branch too!"
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def banner(*msgs)
|
26
|
+
width = msgs.map {|m| m.size}.max
|
27
|
+
|
28
|
+
banner = "*" * (width + 6)
|
29
|
+
|
30
|
+
puts
|
31
|
+
puts banner
|
32
|
+
|
33
|
+
msgs.each do |m|
|
34
|
+
print "* #{m}"
|
35
|
+
print " " * (width - m.size + 2)
|
36
|
+
puts "*"
|
37
|
+
end
|
38
|
+
|
39
|
+
puts banner
|
40
|
+
puts
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Given a tag, using all the rules, find the next tag.
|
45
|
+
def next_tag(tag)
|
46
|
+
last_index = extensions.index( tag_ext(tag) ) || -1
|
47
|
+
next_ext = extensions[last_index+1]
|
48
|
+
|
49
|
+
"#{base_tag}-#{next_ext}"
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
# Returns a regex which matches tags in the required format, and starting with `tag_prefix`.
|
56
|
+
def tag_regex
|
57
|
+
@tag_regex ||= %r{^#{ Regexp.quote tag_prefix }-\d{4}-\d{2}-\d{2}}
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Returns tags matching `tag_regex` for this repo.
|
62
|
+
def tags_with_pattern
|
63
|
+
git_helper.tags.grep(tag_regex)
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Lists all tags matching the patten
|
68
|
+
def list
|
69
|
+
tags_with_pattern.sort.each do |tag|
|
70
|
+
puts tag
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# List all tags made this month
|
76
|
+
def month_list
|
77
|
+
this_months_tags.sort.each do |tag|
|
78
|
+
puts tag
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Returns the base tag for today's date.
|
84
|
+
#
|
85
|
+
# Example:
|
86
|
+
#
|
87
|
+
# di/rel-2011-07-07
|
88
|
+
def base_tag
|
89
|
+
Time.now.strftime("#{ tag_prefix }-%Y-%m-%d")
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# Returns a list matching the `tag_prefix`, on today's date.
|
94
|
+
def todays_tags
|
95
|
+
tags_with_pattern.grep(%r{^#{ base_tag }})
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# Returns a pattern we can use to determine all tags for the month
|
100
|
+
def month_pattern
|
101
|
+
Time.now.strftime("#{ tag_prefix }-%Y-%m")
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Returns all tags for the month
|
106
|
+
def this_months_tags
|
107
|
+
tags_with_pattern.grep(%r{^#{ month_pattern }})
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# Returns a sorted list of possible extensions.
|
112
|
+
def extensions
|
113
|
+
('1'..'9').to_a + ('a'..'z').to_a
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Extracts the extension from a tag
|
118
|
+
#
|
119
|
+
# Returns either the extension, or a blank string.
|
120
|
+
def tag_ext(tag)
|
121
|
+
ext = tag.sub(tag_regex, '')
|
122
|
+
if ext[0] == ?-
|
123
|
+
ext[1].chr
|
124
|
+
else
|
125
|
+
''
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
# delegate to git helper
|
132
|
+
def git(cmd)
|
133
|
+
git_helper.git( cmd )
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def git_s(cmd)
|
138
|
+
git_helper.git_s( cmd )
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Plus2GitTagger
|
2
|
+
class Task < ::Rake::TaskLib
|
3
|
+
|
4
|
+
attr_reader :name, :git
|
5
|
+
|
6
|
+
def initialize(name, &blk)
|
7
|
+
@name = name
|
8
|
+
@git = Plus2GitTagger::Git.new( Dir.pwd )
|
9
|
+
|
10
|
+
@prereqs = %w{preflight commit_preflight}.map {|p| "#{ name }:#{ p }"}
|
11
|
+
@taggers = []
|
12
|
+
|
13
|
+
@reporters = []
|
14
|
+
@monthlys = []
|
15
|
+
|
16
|
+
instance_eval(&blk)
|
17
|
+
|
18
|
+
add_global_reporters
|
19
|
+
|
20
|
+
desc "Preflight (asset compilation, packing etc)"
|
21
|
+
task "#{ name }:preflight" , &@preflight_block if @preflight_block
|
22
|
+
|
23
|
+
desc "Commit compiled assets"
|
24
|
+
task "#{ name }:commit_preflight", &@commit_preflight_block if @commit_preflight_block
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# API: set the preflight block
|
29
|
+
def preflight(&blk)
|
30
|
+
@preflight_block = blk
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# API: set the preflight commit block
|
35
|
+
def commit_preflight(&blk)
|
36
|
+
@commit_preflight_block = blk
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# API: define the default tagger
|
41
|
+
def default_tagger( *prefix )
|
42
|
+
@taggers << tagger(nil, *prefix)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# API: define a tagger
|
47
|
+
def tagger( name, *prefix )
|
48
|
+
name = nil if name && name.strip == ''
|
49
|
+
|
50
|
+
task_name = if name
|
51
|
+
"#{ @name }:#{ name }"
|
52
|
+
else
|
53
|
+
@name
|
54
|
+
end
|
55
|
+
|
56
|
+
string_prefix = [ prefix ].flatten.compact.join("/")
|
57
|
+
|
58
|
+
tagger = Tags.new( @git, string_prefix )
|
59
|
+
|
60
|
+
@taggers << tagger
|
61
|
+
|
62
|
+
desc "Tag a #{name || 'default'} release"
|
63
|
+
task task_name => @prereqs do
|
64
|
+
tagger.make!
|
65
|
+
end
|
66
|
+
|
67
|
+
add_reporters(tagger, task_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Adds two reporting tasks for this tagger
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
#
|
75
|
+
# tag:hotfix:list
|
76
|
+
# tag:hotfix:list:month
|
77
|
+
def add_reporters(tagger, task_name)
|
78
|
+
|
79
|
+
@reporters << (report_all_name = "#{task_name}:list")
|
80
|
+
|
81
|
+
desc "List all #{basename(task_name)} tags"
|
82
|
+
task report_all_name do
|
83
|
+
tagger.list
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
@monthlys << (report_month_name = "#{task_name}:list:month")
|
88
|
+
|
89
|
+
desc "List all #{basename(task_name)} tags for the month"
|
90
|
+
task report_month_name do
|
91
|
+
tagger.month_list
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# Adds tasks that will list all tags for this project, or all tags for the project for the month
|
97
|
+
def add_global_reporters
|
98
|
+
desc 'List all tags'
|
99
|
+
task 'tags:list:all' => @reporters
|
100
|
+
|
101
|
+
desc 'List all tags for the month'
|
102
|
+
task 'tags:list:month' => @monthlys
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Delegate to git interface.
|
107
|
+
|
108
|
+
# Runs a git command.
|
109
|
+
def git_c(cmd)
|
110
|
+
@git.git(cmd)
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Runs a git command, returning its standard out.
|
115
|
+
def git_s(cmd)
|
116
|
+
@git.git_s(cmd)
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def basename(taskname)
|
121
|
+
taskname == @name ? 'default' : taskname.gsub("#{@name}:", "")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "plus2_git_tagger/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "plus2_git_tagger"
|
7
|
+
s.version = Plus2GitTagger::VERSION
|
8
|
+
s.authors = ["Lachie Cox", "Ben Askins"]
|
9
|
+
s.email = ["lachiec@gmail.com", "ben.askins@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Plus2 + Davidson style git tagger}
|
12
|
+
s.description = %q{Plus2 + Davidson style git tagger, for Davidson + Plus2}
|
13
|
+
|
14
|
+
s.rubyforge_project = "plus2_git_tagger"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: plus2_git_tagger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Lachie Cox
|
14
|
+
- Ben Askins
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-09-06 00:00:00 Z
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Plus2 + Davidson style git tagger, for Davidson + Plus2
|
23
|
+
email:
|
24
|
+
- lachiec@gmail.com
|
25
|
+
- ben.askins@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- Gemfile
|
35
|
+
- Rakefile
|
36
|
+
- lib/plus2_git_tagger.rb
|
37
|
+
- lib/plus2_git_tagger/git.rb
|
38
|
+
- lib/plus2_git_tagger/tags.rb
|
39
|
+
- lib/plus2_git_tagger/task.rb
|
40
|
+
- lib/plus2_git_tagger/version.rb
|
41
|
+
- plus2_git_tagger.gemspec
|
42
|
+
homepage: ""
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project: plus2_git_tagger
|
71
|
+
rubygems_version: 1.8.5
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Plus2 + Davidson style git tagger
|
75
|
+
test_files: []
|
76
|
+
|