git-lite-version-bump 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +3 -0
- data/LICENCE +674 -0
- data/README.md +157 -0
- data/Rakefile +17 -0
- data/bin/git-version-bump +55 -0
- data/git-version-bump.gemspec +26 -0
- data/lib/git-version-bump.rb +324 -0
- data/lib/git-version-bump/rake-tasks.rb +49 -0
- data/lib/git-version-bump/version.rb +8 -0
- metadata +109 -0
data/README.md
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
Maintain your program versions entirely within git. No local files
|
2
|
+
required! All versioning information is stored using git tags.
|
3
|
+
|
4
|
+
This gem contains a command-line tool and set of Rake tasks to increment
|
5
|
+
and display your version numbers via git tags, and some associated Ruby code to use
|
6
|
+
inside a gemspec or your program to retrieve the current version number, for
|
7
|
+
use in builds and at runtime.
|
8
|
+
|
9
|
+
|
10
|
+
# Usage
|
11
|
+
|
12
|
+
Most of your day-to-day usage of `git-version-bump` will be via the command
|
13
|
+
line. When you bump a version, a new tag will be created representing the newly
|
14
|
+
incremented version number at the current commit. If no tags currently
|
15
|
+
exist, the previous version will be taken to be `0.0.0` and then incremented
|
16
|
+
accordingly.
|
17
|
+
|
18
|
+
|
19
|
+
## On the command line
|
20
|
+
|
21
|
+
Pretty damned trivial:
|
22
|
+
|
23
|
+
git version-bump <major|minor|patch|show>
|
24
|
+
|
25
|
+
You can also shorten the specifier to any unique substring:
|
26
|
+
|
27
|
+
git version-bump ma
|
28
|
+
git version-bump mi
|
29
|
+
git version-bump p
|
30
|
+
git version-bump s
|
31
|
+
|
32
|
+
I recommend adding an alias to your `~/.gitconfig` file, for less typing:
|
33
|
+
|
34
|
+
[alias]
|
35
|
+
vb = version-bump
|
36
|
+
|
37
|
+
You can also add your own release notes to your release tags, by using the
|
38
|
+
`-n` (or `--notes`, if you like typing) option:
|
39
|
+
|
40
|
+
git version-bump -n minor
|
41
|
+
|
42
|
+
This will open an editor, containing a list of the commits since the last
|
43
|
+
release tag, in which you can type your release notes. If you follow
|
44
|
+
standard git commit style (a "heading" line, then a blank line, followed by
|
45
|
+
free-form text) you're perfectly positioned to use
|
46
|
+
[github-release](http://theshed.hezmatt.org/github-release) to make
|
47
|
+
gorgeous-looking release announcements to Github.
|
48
|
+
|
49
|
+
|
50
|
+
## In your `Rakefile`
|
51
|
+
|
52
|
+
If you'd like to have access to the version-bumping goodness via `rake`, add
|
53
|
+
the following line to your `Rakefile`:
|
54
|
+
|
55
|
+
require 'git-version-bump/rake-tasks'
|
56
|
+
|
57
|
+
You will now have the following rake tasks available:
|
58
|
+
|
59
|
+
rake version:bump:major # bump major version (x.y.z -> x+1.0.0)
|
60
|
+
rake version:bump:minor # bump minor version (x.y.z -> x.y+1.0)
|
61
|
+
rake version:bump:patch # bump patch version (x.y.z -> x.y.z+1)
|
62
|
+
rake version:bump:show # Print current version number
|
63
|
+
|
64
|
+
(Since `version:bump:major` is a lot of typing, there are also shortcuts:
|
65
|
+
`v:b:major`, `v:b:maj`, `v:b:minor`, `v:b:min`, `v:b:patch`, `v:b:pat`, and
|
66
|
+
`v:b:p`)
|
67
|
+
|
68
|
+
|
69
|
+
## In your Ruby code
|
70
|
+
|
71
|
+
To get access to this version information in your code (such as in your
|
72
|
+
`gemspec`, or the definition of a `::VERSION` constant), you can `require
|
73
|
+
'git-version-bump'` and use the following methods:
|
74
|
+
|
75
|
+
GVB.version # Return the entire version string
|
76
|
+
GVB.major_version # Return just the 'major' portion of the version
|
77
|
+
GVB.minor_version # Return just the 'minor' portion of the version
|
78
|
+
GVB.patch_version # Return just the 'patch' portion of the version
|
79
|
+
GVB.internal_revision # Return "internal revision" information, or nil
|
80
|
+
GVB.date # Return the date of the most recent commit, or
|
81
|
+
# today's date if the tree is dirty
|
82
|
+
|
83
|
+
The "internal revision" is set when the tree is dirty, or when the latest
|
84
|
+
git commit doesn't correspond with a tag. In that case, the internal
|
85
|
+
revision will describe, in the manner of `git describe`, the full details of
|
86
|
+
the version of the code in use. This information will be part of the
|
87
|
+
version string provided by `gvb_version`.
|
88
|
+
|
89
|
+
If any of these methods are called when there isn't a tag or other version
|
90
|
+
information available, the version will be assumed to be `0.0.0.1.ENOTAG`
|
91
|
+
with a date of `1970-01-01`.
|
92
|
+
|
93
|
+
|
94
|
+
### In your gemspec
|
95
|
+
|
96
|
+
Typically, you want to encode your version and commit date into your
|
97
|
+
gemspec, like this:
|
98
|
+
|
99
|
+
Gem::Specification.new do |s|
|
100
|
+
s.version = GVB.version
|
101
|
+
s.date = GVB.date
|
102
|
+
|
103
|
+
...
|
104
|
+
end
|
105
|
+
|
106
|
+
The beauty of this method is that whenever you run a `rake build`, you'll
|
107
|
+
get a gem which is *accurately* versioned for the current state of your
|
108
|
+
repository. No more wondering if the `foobar-1.2.3` gem installed on your
|
109
|
+
system was built from pristine sources, or with that experimental patch you
|
110
|
+
were trying out...
|
111
|
+
|
112
|
+
|
113
|
+
### In your gem
|
114
|
+
|
115
|
+
If, like me, you're one of those people who likes to be able to easily see
|
116
|
+
what version of a library you're running, then you probably like to define a
|
117
|
+
`VERSION` constant somewhere in your gem's namespace. That, too, is simple
|
118
|
+
to do:
|
119
|
+
|
120
|
+
require 'git-version-bump'
|
121
|
+
|
122
|
+
class Foobar
|
123
|
+
VERSION = GVB.version
|
124
|
+
end
|
125
|
+
|
126
|
+
This will work correctly inside your git tree, and also in your installed
|
127
|
+
gem. Magical!
|
128
|
+
|
129
|
+
#### For projects using lite tags
|
130
|
+
|
131
|
+
If you are using GitHub releases for your project or some other method that
|
132
|
+
involves light tags (tags with no annotations), you might notice that these
|
133
|
+
tags are not detected by git-version-bump by default. If you want these
|
134
|
+
commits to be detected then use the following configuration:
|
135
|
+
|
136
|
+
require 'git-version-bump'
|
137
|
+
|
138
|
+
class Foobar
|
139
|
+
# First parameter is use_local_git, second is include_lite_tags
|
140
|
+
VERSION = GVB.version(false, true)
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# Contributing
|
145
|
+
|
146
|
+
Send your pull requests to the [Github
|
147
|
+
repo](https://github.com/mpalmer/git-version-bump), or send patches to
|
148
|
+
`theshed+git-version-bump@hezmatt.org`. Bug reports can be sent to the same
|
149
|
+
place, although I greatly prefer patches.
|
150
|
+
|
151
|
+
|
152
|
+
# Licence
|
153
|
+
|
154
|
+
Unless otherwise specified, all code in this repository is licenced under
|
155
|
+
the terms of the GNU Public Licence, version 3, as published by the Free
|
156
|
+
Software Foundation. The full terms of this licence can be found in the
|
157
|
+
file LICENCE.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
require 'rdoc/task'
|
7
|
+
|
8
|
+
Rake::RDocTask.new do |rd|
|
9
|
+
rd.main = "README.md"
|
10
|
+
rd.title = 'git-version-bump'
|
11
|
+
rd.rdoc_files.include("README.md", "lib/**/*.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
task :release do
|
15
|
+
sh "git push --follow-tags"
|
16
|
+
sh "git release"
|
17
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'git-version-bump'
|
4
|
+
|
5
|
+
if ARGV[0].nil? or
|
6
|
+
ARGV[0].empty? or
|
7
|
+
(ARGV.length == 1 && (ARGV[0] == "-d" || ARGV[0] == "--dry-run")) or
|
8
|
+
ARGV[0] == '-h' or
|
9
|
+
ARGV[0] == '--help'
|
10
|
+
$stderr.puts <<-EOF.gsub(/^\t\t/, '')
|
11
|
+
Usage: git version-bump [-n|--notes] [-d|--dry-run] <major|minor|patch|show>
|
12
|
+
|
13
|
+
'major': x.y.z -> x+1.0.0
|
14
|
+
'minor': x.y.z -> x.y+1.0
|
15
|
+
'patch': x.y.z -> x.y.z+1
|
16
|
+
|
17
|
+
'show': Display the current GVB version
|
18
|
+
|
19
|
+
-d, --dry-run: Calculate and return the bump value, but don't update git workspace or remote
|
20
|
+
-n, --notes: Prompt for "release notes" to add to the release tag
|
21
|
+
-l, --lite-tags: Include non-annotated git tags
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
|
25
|
+
release_notes = ARGV.delete('-n') || ARGV.delete('--notes')
|
26
|
+
dry_run = ARGV.delete('-d') || ARGV.delete('--dry-run')
|
27
|
+
lite_tags = ARGV.delete('-l') || ARGV.delete('--lite-tags')
|
28
|
+
|
29
|
+
if ARGV[0].nil? or ARGV[0].empty?
|
30
|
+
exit 1
|
31
|
+
elsif ARGV[0] == '-h' or ARGV[0] == '--help'
|
32
|
+
exit 0
|
33
|
+
end
|
34
|
+
|
35
|
+
result = case ARGV[0].downcase
|
36
|
+
when /^maj?o?r?$/
|
37
|
+
"#{GVB.major_version(true) + 1}.0.0"
|
38
|
+
when /^min?o?r?$/
|
39
|
+
"#{GVB.major_version(true)}.#{GVB.minor_version(true)+1}.0"
|
40
|
+
when /^pa?t?c?h?$/
|
41
|
+
"#{GVB.major_version(true)}.#{GVB.minor_version(true)}.#{GVB.patch_version(true)+1}"
|
42
|
+
when /^sh?o?w?$/
|
43
|
+
puts GVB.version(true)
|
44
|
+
exit 0
|
45
|
+
else
|
46
|
+
$stderr.puts "Unknown argument: #{ARGV[0]}. Try --help."
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
|
50
|
+
if dry_run
|
51
|
+
puts result
|
52
|
+
else
|
53
|
+
GVB.tag_version result, release_notes, lite_tags
|
54
|
+
puts "Version is now #{GVB.version(true)}."
|
55
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'git-version-bump'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "git-lite-version-bump"
|
7
|
+
|
8
|
+
s.version = GVB.version
|
9
|
+
s.date = GVB.date
|
10
|
+
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.required_ruby_version = ">= 1.8.7"
|
13
|
+
|
14
|
+
s.homepage = "http://github.com/rbclark/git-version-bump"
|
15
|
+
s.summary = "Manage your app version entirely via git tags (even lite tags)"
|
16
|
+
s.authors = ["Matt Palmer"]
|
17
|
+
|
18
|
+
s.extra_rdoc_files = ["README.md"]
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.executables = ["git-version-bump"]
|
21
|
+
|
22
|
+
s.add_development_dependency 'github-release'
|
23
|
+
s.add_development_dependency 'rake'
|
24
|
+
s.add_development_dependency 'bundler'
|
25
|
+
s.add_development_dependency 'rdoc'
|
26
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module GitVersionBump
|
6
|
+
class VersionUnobtainable < StandardError; end
|
7
|
+
|
8
|
+
DEVNULL = Gem.win_platform? ? "NUL" : "/dev/null"
|
9
|
+
|
10
|
+
def self.version(use_local_git=false, include_lite_tags=false)
|
11
|
+
if use_local_git
|
12
|
+
unless git_available?
|
13
|
+
raise RuntimeError,
|
14
|
+
"GVB.version(use_local_git=true) called, but git isn't installed"
|
15
|
+
end
|
16
|
+
|
17
|
+
sq_git_dir = shell_quoted_string(Dir.pwd)
|
18
|
+
else
|
19
|
+
sq_git_dir = shell_quoted_string((File.dirname(caller_file) rescue nil || Dir.pwd))
|
20
|
+
end
|
21
|
+
|
22
|
+
git_cmd = "git -C #{sq_git_dir} describe --dirty='.1.dirty.#{Time.now.strftime("%Y%m%d.%H%M%S")}' --match='v[0-9]*.[0-9]*.*[0-9]'"
|
23
|
+
git_cmd << " --tags" if include_lite_tags
|
24
|
+
|
25
|
+
git_ver = `#{git_cmd} 2> #{DEVNULL}`.
|
26
|
+
strip.
|
27
|
+
gsub(/^v/, '').
|
28
|
+
gsub('-', '.')
|
29
|
+
|
30
|
+
# If git returned success, then it gave us a described version.
|
31
|
+
# Success!
|
32
|
+
return git_ver if $? == 0
|
33
|
+
|
34
|
+
# git failed us; we're either not in a git repo or else we've never
|
35
|
+
# tagged anything before.
|
36
|
+
|
37
|
+
# Are we in a git repo with no tags? If so, dump out our
|
38
|
+
# super-special version and be done with it, otherwise try to use the
|
39
|
+
# gem version.
|
40
|
+
system("git -C #{sq_git_dir} status > #{DEVNULL} 2>&1")
|
41
|
+
$? == 0 ? "0.0.0.1.ENOTAG" : gem_version(use_local_git)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.major_version(use_local_git=false, include_lite_tags=false)
|
45
|
+
ver = version(use_local_git, include_lite_tags)
|
46
|
+
v = ver.split('.')[0]
|
47
|
+
|
48
|
+
unless v =~ /^[0-9]+$/
|
49
|
+
raise ArgumentError,
|
50
|
+
"#{v} (part of #{ver.inspect}) is not a numeric version component. Abandon ship!"
|
51
|
+
end
|
52
|
+
|
53
|
+
return v.to_i
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.minor_version(use_local_git=false, include_lite_tags=false)
|
57
|
+
ver = version(use_local_git, include_lite_tags)
|
58
|
+
v = ver.split('.')[1]
|
59
|
+
|
60
|
+
unless v =~ /^[0-9]+$/
|
61
|
+
raise ArgumentError,
|
62
|
+
"#{v} (part of #{ver.inspect}) is not a numeric version component. Abandon ship!"
|
63
|
+
end
|
64
|
+
|
65
|
+
return v.to_i
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.patch_version(use_local_git=false, include_lite_tags=false)
|
69
|
+
ver = version(use_local_git, include_lite_tags)
|
70
|
+
v = ver.split('.')[2]
|
71
|
+
|
72
|
+
unless v =~ /^[0-9]+$/
|
73
|
+
raise ArgumentError,
|
74
|
+
"#{v} (part of #{ver.inspect}) is not a numeric version component. Abandon ship!"
|
75
|
+
end
|
76
|
+
|
77
|
+
return v.to_i
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.internal_revision(use_local_git=false, include_lite_tags=false)
|
81
|
+
version(use_local_git, include_lite_tags).split('.', 4)[3].to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.date(use_local_git=false)
|
85
|
+
if use_local_git
|
86
|
+
unless git_available?
|
87
|
+
raise RuntimeError,
|
88
|
+
"GVB.date(use_local_git=true), but git is not installed"
|
89
|
+
end
|
90
|
+
|
91
|
+
sq_git_dir = shell_quoted_string(Dir.pwd)
|
92
|
+
else
|
93
|
+
sq_git_dir = shell_quoted_string((File.dirname(caller_file) rescue nil || Dir.pwd))
|
94
|
+
end
|
95
|
+
|
96
|
+
# Are we in a git tree?
|
97
|
+
system("git -C #{sq_git_dir} status > #{DEVNULL} 2>&1")
|
98
|
+
if $? == 0
|
99
|
+
# Yes, we're in git.
|
100
|
+
|
101
|
+
if dirty_tree?
|
102
|
+
return Time.now.strftime("%F")
|
103
|
+
else
|
104
|
+
# Clean tree. Date of last commit is needed.
|
105
|
+
return `git -C #{sq_git_dir} show --no-show-signature --format=format:%cd --date=short`.lines.first.strip
|
106
|
+
end
|
107
|
+
else
|
108
|
+
if use_local_git
|
109
|
+
raise RuntimeError,
|
110
|
+
"GVB.date(use_local_git=true) called from non-git location"
|
111
|
+
end
|
112
|
+
|
113
|
+
# Not in git; time to hit the gemspecs
|
114
|
+
if spec = caller_gemspec
|
115
|
+
return spec.date.strftime("%F")
|
116
|
+
end
|
117
|
+
|
118
|
+
raise RuntimeError,
|
119
|
+
"GVB.date called from mysterious, non-gem location."
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.tag_version(v, release_notes = false, include_lite_tags=false)
|
124
|
+
if dirty_tree?
|
125
|
+
puts "You have uncommitted files. Refusing to tag a dirty tree."
|
126
|
+
else
|
127
|
+
if release_notes
|
128
|
+
# We need to find the tag before this one, so we can list all the commits
|
129
|
+
# between the two. This is not a trivial operation.
|
130
|
+
git_cmd = 'git describe --always'
|
131
|
+
git_cmd << ' --tags' if include_lite_tags
|
132
|
+
prev_tag = `#{git_cmd}`.strip.gsub(/-\d+-g[0-9a-f]+$/, '')
|
133
|
+
|
134
|
+
log_file = Tempfile.new('gvb')
|
135
|
+
|
136
|
+
log_file.puts <<-EOF.gsub(/^\t\t\t\t\t/, '')
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
# Write your release notes above. The first line should be the release name.
|
141
|
+
# To help you remember what's in here, the commits since your last release
|
142
|
+
# are listed below. This will become v#{v}
|
143
|
+
#
|
144
|
+
EOF
|
145
|
+
|
146
|
+
log_file.close
|
147
|
+
system("git log --no-show-signature --format='# %h %s' #{prev_tag}..HEAD >>#{log_file.path}")
|
148
|
+
|
149
|
+
pre_hash = Digest::SHA1.hexdigest(File.read(log_file.path))
|
150
|
+
system("git config -e -f #{log_file.path}")
|
151
|
+
if Digest::SHA1.hexdigest(File.read(log_file.path)) == pre_hash
|
152
|
+
puts "Release notes not edited; aborting"
|
153
|
+
log_file.unlink
|
154
|
+
return
|
155
|
+
end
|
156
|
+
|
157
|
+
puts "Tagging version #{v}..."
|
158
|
+
system("git tag -a -F #{log_file.path} v#{v}")
|
159
|
+
log_file.unlink
|
160
|
+
else
|
161
|
+
# Crikey this is a lot simpler
|
162
|
+
system("git tag -a -m 'Version v#{v}' v#{v}")
|
163
|
+
end
|
164
|
+
|
165
|
+
system("git push > #{DEVNULL} 2>&1")
|
166
|
+
system("git push --tags > #{DEVNULL} 2>&1")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Calculate a version number based on the date of the most recent git commit.
|
171
|
+
#
|
172
|
+
# Return a version format string of the form `"0.YYYYMMDD.N"`, where
|
173
|
+
# `YYYYMMDD` is the date of the "top-most" commit in the tree, and `N` is
|
174
|
+
# the number of other commits also made on that date.
|
175
|
+
#
|
176
|
+
# This version format is not recommented for general use. It has benefit
|
177
|
+
# only in situations where the principles of Semantic Versioning have no
|
178
|
+
# real meaning, such as packages where there is little or no concept of
|
179
|
+
# "backwards compatibility" (eg packages which only contain images and
|
180
|
+
# other assets), or where the package can, for reasons outside that of
|
181
|
+
# the package itself, never break backwards compatibility (definitions of
|
182
|
+
# binary-packed structures shared amongst multiple systems).
|
183
|
+
#
|
184
|
+
# The format of this commit-date-based version format allows for a strictly
|
185
|
+
# monotonically-increasing version number, aligned with the progression of the
|
186
|
+
# underlying git commit log.
|
187
|
+
#
|
188
|
+
# One limitation of the format is that it doesn't deal with the issue of
|
189
|
+
# package builds made from multiple divergent trees. Unlike
|
190
|
+
# `git-describe`-based output, there is no "commit hash" identity
|
191
|
+
# included in the version string. This is because of (ludicrous)
|
192
|
+
# limitations of the Rubygems format definition -- the moment there's a
|
193
|
+
# letter in the version number, the package is considered a "pre-release"
|
194
|
+
# version. Since hashes are hex, we're boned. Sorry about that. Don't
|
195
|
+
# make builds off a branch, basically.
|
196
|
+
#
|
197
|
+
def self.commit_date_version(use_local_git = false)
|
198
|
+
if use_local_git
|
199
|
+
unless git_available?
|
200
|
+
raise RuntimeError,
|
201
|
+
"GVB.commit_date_version(use_local_git=true) called, but git isn't installed"
|
202
|
+
end
|
203
|
+
|
204
|
+
sq_git_dir = shell_quoted_string(Dir.pwd)
|
205
|
+
else
|
206
|
+
sq_git_dir = shell_quoted_string((File.dirname(caller_file) rescue nil || Dir.pwd))
|
207
|
+
end
|
208
|
+
|
209
|
+
commit_dates = `git -C #{sq_git_dir} log --format=%at`.
|
210
|
+
split("\n").
|
211
|
+
map { |l| Time.at(Integer(l)).strftime("%Y%m%d") }
|
212
|
+
|
213
|
+
if $? == 0
|
214
|
+
# We got a log; calculate our version number and we're done.
|
215
|
+
version_date = commit_dates.first
|
216
|
+
commit_count = commit_dates.select { |d| d == version_date }.length - 1
|
217
|
+
dirty_suffix = if dirty_tree?
|
218
|
+
".dirty.#{Time.now.strftime("%Y%m%d.%H%M%S")}"
|
219
|
+
else
|
220
|
+
""
|
221
|
+
end
|
222
|
+
|
223
|
+
return "0.#{version_date}.#{commit_count}#{dirty_suffix}"
|
224
|
+
end
|
225
|
+
|
226
|
+
# git failed us; either we're not in a git repo or else it's a git
|
227
|
+
# repo that's not got any commits.
|
228
|
+
|
229
|
+
# Are we in a git repo with no tags? If so, dump out our
|
230
|
+
# super-special version and be done with it.
|
231
|
+
system("git -C #{sq_git_dir} status > #{DEVNULL} 2>&1")
|
232
|
+
$? == 0 ? "0.0.0.1.ENOCOMMITS" : gem_version(use_local_git)
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
def self.git_available?
|
238
|
+
system("git --version > #{DEVNULL} 2>&1")
|
239
|
+
|
240
|
+
$? == 0
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.dirty_tree?
|
244
|
+
# Are we in a dirty, dirty tree?
|
245
|
+
system("! git diff --no-ext-diff --quiet --exit-code 2> #{DEVNULL} || ! git diff-index --cached --quiet HEAD 2> #{DEVNULL}")
|
246
|
+
|
247
|
+
$? == 0
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.caller_file
|
251
|
+
# Who called us? Because this method gets called from other methods
|
252
|
+
# within this file, we can't just look at Gem.location_of_caller, but
|
253
|
+
# instead we need to parse the caller stack ourselves to find which
|
254
|
+
# gem we're trying to version all over.
|
255
|
+
Pathname(
|
256
|
+
caller.
|
257
|
+
map { |l| l.split(':')[0] }.
|
258
|
+
find { |l| l != __FILE__ }
|
259
|
+
).realpath.to_s rescue nil
|
260
|
+
end
|
261
|
+
|
262
|
+
def self.caller_gemspec
|
263
|
+
cf = caller_file or return nil
|
264
|
+
|
265
|
+
# Grovel through all the loaded gems to try and find the gem
|
266
|
+
# that contains the caller's file.
|
267
|
+
Gem.loaded_specs.values.each do |spec|
|
268
|
+
search_dirs = spec.require_paths.map { |d| "#{spec.full_gem_path}/#{d}" } +
|
269
|
+
[File.join(spec.full_gem_path, spec.bindir)]
|
270
|
+
search_dirs.map! do |d|
|
271
|
+
begin
|
272
|
+
Pathname(d).realpath.to_s
|
273
|
+
rescue Errno::ENOENT
|
274
|
+
nil
|
275
|
+
end
|
276
|
+
end.compact!
|
277
|
+
|
278
|
+
if search_dirs.find { |d| cf.index(d) == 0 }
|
279
|
+
return spec
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
raise VersionUnobtainable,
|
284
|
+
"Unable to find gemspec for caller file #{cf}"
|
285
|
+
end
|
286
|
+
|
287
|
+
def self.gem_version(use_local_git = false)
|
288
|
+
if use_local_git
|
289
|
+
raise VersionUnobtainable,
|
290
|
+
"Unable to determine version from local git repo. This should never happen."
|
291
|
+
end
|
292
|
+
|
293
|
+
if spec = caller_gemspec
|
294
|
+
return spec.version.to_s
|
295
|
+
else
|
296
|
+
# If we got here, something went *badly* wrong -- presumably, we
|
297
|
+
# weren't called from within a loaded gem, and so we've got *no*
|
298
|
+
# idea what's going on. Time to bail!
|
299
|
+
if git_available?
|
300
|
+
raise VersionUnobtainable,
|
301
|
+
"GVB.version(#{use_local_git.inspect}) failed, and I really don't know why."
|
302
|
+
else
|
303
|
+
raise VersionUnobtainable,
|
304
|
+
"GVB.version(#{use_local_git.inspect}) failed; perhaps you need to install git?"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def self.shell_quoted_string(dir_string)
|
310
|
+
if Gem.win_platform?
|
311
|
+
return "\"#{dir_string}\""
|
312
|
+
else
|
313
|
+
# Shell Quoted, for your convenience
|
314
|
+
return "'#{dir_string.gsub("'", "'\\''")}'"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
private_class_method :shell_quoted_string
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
GVB = GitVersionBump unless defined? GVB
|
323
|
+
|
324
|
+
require 'git-version-bump/version'
|