git-version-bump 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/README.md +82 -0
- data/Rakefile +21 -0
- data/git-version-bump.gemspec +21 -0
- data/lib/git-version-bump.rb +138 -0
- data/lib/git-version-bump/rake-tasks.rb +26 -0
- metadata +106 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
Maintain your program versions entirely within git. No local files
|
2
|
+
required!
|
3
|
+
|
4
|
+
This gem contains a set of Rake tasks and associated code to manage the
|
5
|
+
versioning of your code via git tags. No in-repo file is required to store
|
6
|
+
your version, which reduces unnecessary duplication of information.
|
7
|
+
|
8
|
+
|
9
|
+
# Usage
|
10
|
+
|
11
|
+
In your `Rakefile`, add the following line:
|
12
|
+
|
13
|
+
require 'git-version-bump/rake-tasks'
|
14
|
+
|
15
|
+
You will now have the following rake tasks available:
|
16
|
+
|
17
|
+
rake version:bump:major # bump major version (x.y.z -> x+1.0.0)
|
18
|
+
rake version:bump:minor # bump minor version (x.y.z -> x.y+1.0)
|
19
|
+
rake version:bump:patch # bump patch version (x.y.z -> x.y.z+1)
|
20
|
+
|
21
|
+
By running any of those, a new tag will be created representing the newly
|
22
|
+
incremented version number at the current commit. If no tags currently
|
23
|
+
exist, the previous version will be taken to be `0.0.0` and then incremented
|
24
|
+
accordingly.
|
25
|
+
|
26
|
+
To get access to this version information in your code (such as in your
|
27
|
+
`gemspec`, or the definition of a `::VERSION` constant), you can `require
|
28
|
+
'git-version-bump'` and use the following methods:
|
29
|
+
|
30
|
+
GVB.version # Return the entire version string
|
31
|
+
GVB.major_version # Return just the 'major' portion of the version
|
32
|
+
GVB.minor_version # Return just the 'minor' portion of the version
|
33
|
+
GVB.patch_version # Return just the 'patch' portion of the version
|
34
|
+
GVB.internal_revision # Return "internal revision" information, or nil
|
35
|
+
GVB.date # Return the date of the most recent commit, or
|
36
|
+
# today's date if the tree is dirty
|
37
|
+
|
38
|
+
The "internal revision" is set when the tree is dirty, or when the latest
|
39
|
+
git commit doesn't correspond with a tag. In that case, the internal
|
40
|
+
revision will describe, in the manner of `git describe`, the full details of
|
41
|
+
the version of the code in use. This information will be part of the
|
42
|
+
version string provided by `gvb_version`.
|
43
|
+
|
44
|
+
If any of these methods are called when there isn't a tag or other version
|
45
|
+
information available, the version will be assumed to be `0.0.0.1.ENOTAG`
|
46
|
+
with a date of `1970-01-01`.
|
47
|
+
|
48
|
+
|
49
|
+
## In your gemspec
|
50
|
+
|
51
|
+
Typically, you want to encode your version and commit date into your
|
52
|
+
gemspec, like this:
|
53
|
+
|
54
|
+
Gem::Specification.new do |s|
|
55
|
+
s.version = GVB.version
|
56
|
+
s.date = GVB.date
|
57
|
+
|
58
|
+
...
|
59
|
+
end
|
60
|
+
|
61
|
+
The beauty of this method is that whenever you run a `rake build`, you'll
|
62
|
+
get a gem which is *accurately* versioned for the current state of your
|
63
|
+
repository. No more wondering if the `foobar-1.2.3` gem installed on your
|
64
|
+
system was built from pristine sources, or with that experimental patch you
|
65
|
+
were trying out...
|
66
|
+
|
67
|
+
|
68
|
+
## In your gem
|
69
|
+
|
70
|
+
If, like me, you're one of those people who likes to be able to easily see
|
71
|
+
what version of a library I'm running, then you probably like to define a
|
72
|
+
`VERSION` constant somewhere in your gem's namespace. That, too, is simple
|
73
|
+
to do:
|
74
|
+
|
75
|
+
require 'git-version-bump'
|
76
|
+
|
77
|
+
class Foobar
|
78
|
+
VERSION = GVB.version
|
79
|
+
end
|
80
|
+
|
81
|
+
This will work correctly inside your git tree, and also in your installed
|
82
|
+
gem. Magical!
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require_relative 'lib/git-version-bump/rake-tasks'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
15
|
+
require 'rdoc/task'
|
16
|
+
|
17
|
+
Rake::RDocTask.new do |rd|
|
18
|
+
rd.main = "README.md"
|
19
|
+
rd.title = 'git-version-bump'
|
20
|
+
rd.rdoc_files.include("README.md", "lib/**/*.rb")
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('../lib/git-version-bump', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "git-version-bump"
|
5
|
+
|
6
|
+
s.version = GVB.version
|
7
|
+
s.date = GVB.date
|
8
|
+
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
|
11
|
+
s.homepage = "http://theshed.hezmatt.org/git-version-bump"
|
12
|
+
s.summary = "Manage your app version entirely via git tags"
|
13
|
+
s.authors = ["Matt Palmer"]
|
14
|
+
|
15
|
+
s.extra_rdoc_files = ["README.md"]
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
|
18
|
+
s.add_development_dependency 'rake'
|
19
|
+
s.add_development_dependency 'bundler'
|
20
|
+
s.add_development_dependency 'rdoc'
|
21
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module GitVersionBump
|
2
|
+
def self.version
|
3
|
+
git_ver = `git describe --dirty --match='v[0-9]*.[0-9]*.*[0-9]' 2>/dev/null`.
|
4
|
+
strip.
|
5
|
+
gsub(/^v/, '').
|
6
|
+
gsub('-', '.')
|
7
|
+
|
8
|
+
# If git returned success, then it gave us a described version.
|
9
|
+
# Success!
|
10
|
+
return git_ver if $? == 0
|
11
|
+
|
12
|
+
# git failed us; we're either not in a git repo or else we've never
|
13
|
+
# tagged anything before.
|
14
|
+
|
15
|
+
# Are we in a git repo with no tags? If so, dump out our
|
16
|
+
# super-special version and be done with it.
|
17
|
+
system("git status >/dev/null 2>&1")
|
18
|
+
return "0.0.0.1.ENOTAG" if $? == 0
|
19
|
+
|
20
|
+
# We're not in a git repo. This means that we need to get version
|
21
|
+
# information out of rubygems, given only the filename of who called
|
22
|
+
# us. This takes a little bit of effort.
|
23
|
+
|
24
|
+
if spec = GVB.caller_gemspec
|
25
|
+
return spec.version.to_s
|
26
|
+
else
|
27
|
+
# If we got here, something went *badly* wrong -- presumably, we
|
28
|
+
# weren't called from within a loaded gem, and so we've got *no*
|
29
|
+
# idea what's going on. Time to bail!
|
30
|
+
raise RuntimeError,
|
31
|
+
"GVB.version called from mysterious, non-gem location."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.major_version
|
36
|
+
ver = GVB.version
|
37
|
+
v = ver.split('.')[0]
|
38
|
+
|
39
|
+
unless v =~ /^[0-9]+$/
|
40
|
+
raise ArgumentError,
|
41
|
+
"#{v} (part of #{ver.inspect}) is not a numeric version component. Abandon ship!"
|
42
|
+
end
|
43
|
+
|
44
|
+
return v.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.minor_version
|
48
|
+
ver = GVB.version
|
49
|
+
v = ver.split('.')[1]
|
50
|
+
|
51
|
+
unless v =~ /^[0-9]+$/
|
52
|
+
raise ArgumentError,
|
53
|
+
"#{v} (part of #{ver.inspect}) is not a numeric version component. Abandon ship!"
|
54
|
+
end
|
55
|
+
|
56
|
+
return v.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.patch_version
|
60
|
+
ver = GVB.version
|
61
|
+
v = ver.split('.')[2]
|
62
|
+
|
63
|
+
unless v =~ /^[0-9]+$/
|
64
|
+
raise ArgumentError,
|
65
|
+
"#{v} (part of #{ver.inspect}) is not a numeric version component. Abandon ship!"
|
66
|
+
end
|
67
|
+
|
68
|
+
return v.to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.internal_revision
|
72
|
+
GVB.version.split('.', 4)[3].to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.date
|
76
|
+
# Are we in a git tree?
|
77
|
+
system("git status >/dev/null 2>&1")
|
78
|
+
if $? == 0
|
79
|
+
# Yes, we're in git.
|
80
|
+
|
81
|
+
if GVB.dirty_tree?
|
82
|
+
return Time.now.strftime("%F")
|
83
|
+
else
|
84
|
+
# Clean tree. Date of last commit is needed.
|
85
|
+
return `git show --format=format:%ad --date=short | head -n 1`.strip
|
86
|
+
end
|
87
|
+
else
|
88
|
+
# Not in git; time to hit the gemspecs
|
89
|
+
if spec = GVB.caller_gemspec
|
90
|
+
return spec.version.to_s
|
91
|
+
else
|
92
|
+
raise RuntimeError,
|
93
|
+
"GVB.date called from mysterious, non-gem location."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.tag_version(v)
|
99
|
+
if GVB.dirty_tree?
|
100
|
+
puts "You have uncommitted files. Refusing to tag a dirty tree."
|
101
|
+
else
|
102
|
+
puts "Tagging version #{v}..."
|
103
|
+
system("git tag -a -m 'Version v#{v}' v#{v}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.caller_gemspec
|
108
|
+
# First up, who called us? Because this method gets called from other
|
109
|
+
# methods within this file, we can't just look at Gem.location_of_caller,
|
110
|
+
# but instead we need to parse the whole caller stack ourselves.
|
111
|
+
caller_file = caller.
|
112
|
+
map { |l| l.split(':')[0] }.
|
113
|
+
find { |l| l != __FILE__ }
|
114
|
+
|
115
|
+
# Next we grovel through all the loaded gems to try and find the gem
|
116
|
+
# that contains the caller's file.
|
117
|
+
Gem.loaded_specs.values.each do |spec|
|
118
|
+
if Dir.
|
119
|
+
glob(spec.lib_dirs_glob).
|
120
|
+
find { |d| caller_file.index(d) == 0 }
|
121
|
+
# The caller_file is in this
|
122
|
+
# gem! Woohoo!
|
123
|
+
return spec
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.dirty_tree?
|
131
|
+
# Are we in a dirty, dirty tree?
|
132
|
+
system("! git diff --no-ext-diff --quiet --exit-code || ! git diff-index --cached --quiet HEAD")
|
133
|
+
|
134
|
+
$? == 0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
GVB = GitVersionBump
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../git-version-bump'
|
2
|
+
|
3
|
+
namespace :version do
|
4
|
+
namespace :bump do
|
5
|
+
desc "bump major version (x.y.z -> x+1.0.0)"
|
6
|
+
task :major do
|
7
|
+
GVB.tag_version "#{GVB.major_version + 1}.0.0"
|
8
|
+
|
9
|
+
puts "Version is now #{GVB.version}"
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "bump minor version (x.y.z -> x.y+1.0)"
|
13
|
+
task :minor do
|
14
|
+
GVB.tag_version "#{GVB.major_version}.#{GVB.minor_version+1}.0"
|
15
|
+
|
16
|
+
puts "Version is now #{GVB.version}"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "bump patch version (x.y.z -> x.y.z+1)"
|
20
|
+
task :patch do
|
21
|
+
GVB.tag_version "#{GVB.major_version}.#{GVB.minor_version}.#{GVB.patch_version+1}"
|
22
|
+
|
23
|
+
puts "Version is now #{GVB.version}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git-version-bump
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matt Palmer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-02-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rdoc
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description:
|
63
|
+
email:
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files:
|
67
|
+
- README.md
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- git-version-bump.gemspec
|
74
|
+
- lib/git-version-bump.rb
|
75
|
+
- lib/git-version-bump/rake-tasks.rb
|
76
|
+
homepage: http://theshed.hezmatt.org/git-version-bump
|
77
|
+
licenses: []
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
hash: 4544833629882770877
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
hash: 4544833629882770877
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.23
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Manage your app version entirely via git tags
|
106
|
+
test_files: []
|