git-pivotal-tracker-integration 1.1.0 → 1.2.0
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.
- checksums.yaml +4 -4
- data/README.md +34 -1
- data/bin/git-finish +16 -2
- data/bin/git-release +19 -0
- data/bin/git-start +16 -2
- data/lib/git-pivotal-tracker-integration/command/base.rb +47 -0
- data/lib/git-pivotal-tracker-integration/{base.rb → command/command.rb} +3 -14
- data/lib/git-pivotal-tracker-integration/command/configuration.rb +92 -0
- data/lib/git-pivotal-tracker-integration/command/finish.rb +36 -0
- data/lib/git-pivotal-tracker-integration/command/prepare-commit-msg.sh +26 -0
- data/lib/git-pivotal-tracker-integration/command/release.rb +56 -0
- data/lib/git-pivotal-tracker-integration/command/start.rb +64 -0
- data/lib/git-pivotal-tracker-integration/util/git.rb +242 -0
- data/lib/git-pivotal-tracker-integration/util/shell.rb +36 -0
- data/lib/git-pivotal-tracker-integration/util/story.rb +128 -0
- data/lib/git-pivotal-tracker-integration/util/util.rb +20 -0
- data/lib/git-pivotal-tracker-integration/version-update/gradle.rb +64 -0
- data/lib/git-pivotal-tracker-integration/version-update/version_update.rb +20 -0
- data/lib/git_pivotal_tracker_integration.rb +18 -0
- data/spec/git-pivotal-tracker-integration/command/base_spec.rb +38 -0
- data/spec/git-pivotal-tracker-integration/command/configuration_spec.rb +91 -0
- data/spec/git-pivotal-tracker-integration/command/finish_spec.rb +45 -0
- data/spec/git-pivotal-tracker-integration/command/release_spec.rb +57 -0
- data/spec/git-pivotal-tracker-integration/command/start_spec.rb +50 -0
- data/spec/git-pivotal-tracker-integration/util/git_spec.rb +239 -0
- data/spec/git-pivotal-tracker-integration/util/shell_spec.rb +52 -0
- data/spec/git-pivotal-tracker-integration/util/story_spec.rb +137 -0
- data/spec/git-pivotal-tracker-integration/version-update/gradle_spec.rb +74 -0
- metadata +104 -21
- data/lib/git-pivotal-tracker-integration/finish.rb +0 -106
- data/lib/git-pivotal-tracker-integration/pivotal_configuration.rb +0 -90
- data/lib/git-pivotal-tracker-integration/prepare-commit-msg.sh +0 -12
- data/lib/git-pivotal-tracker-integration/start.rb +0 -167
@@ -0,0 +1,242 @@
|
|
1
|
+
# Git Pivotal Tracker Integration
|
2
|
+
# Copyright (c) 2013 the original author or authors.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "git-pivotal-tracker-integration/util/shell"
|
17
|
+
require "git-pivotal-tracker-integration/util/util"
|
18
|
+
|
19
|
+
# Utilities for dealing with Git
|
20
|
+
class GitPivotalTrackerIntegration::Util::Git
|
21
|
+
|
22
|
+
# Adds a Git hook to the current repository
|
23
|
+
#
|
24
|
+
# @param [String] name the name of the hook to add
|
25
|
+
# @param [String] source the file to use as the source for the created hook
|
26
|
+
# @param [Boolean] overwrite whether to overwrite the hook if it already exists
|
27
|
+
# @return [void]
|
28
|
+
def self.add_hook(name, source, overwrite = false)
|
29
|
+
hooks_directory = File.join repository_root, ".git", "hooks"
|
30
|
+
hook = File.join hooks_directory, name
|
31
|
+
|
32
|
+
if overwrite || !File.exist?(hook)
|
33
|
+
print "Creating Git hook #{name}... "
|
34
|
+
|
35
|
+
FileUtils.mkdir_p hooks_directory
|
36
|
+
File.open(source, "r") do |input|
|
37
|
+
File.open(hook, "w") do |output|
|
38
|
+
output.write(input.read)
|
39
|
+
output.chmod(0755)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
puts "OK"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the name of the currently checked out branch
|
48
|
+
#
|
49
|
+
# @return [String] the name of the currently checked out branch
|
50
|
+
def self.branch_name
|
51
|
+
GitPivotalTrackerIntegration::Util::Shell.exec("git branch").scan(/\* (.*)/)[0][0]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates a branch with a given +name+. First pulls the current branch to
|
55
|
+
# ensure that it is up to date and then creates and checks out the new
|
56
|
+
# branch. If specified, sets branch-specific properties that are passed in.
|
57
|
+
#
|
58
|
+
# @param [String] name the name of the branch to create
|
59
|
+
# @param [Boolean] print_messages whether to print messages
|
60
|
+
# @return [void]
|
61
|
+
def self.create_branch(name, print_messages = true)
|
62
|
+
root_branch = branch_name
|
63
|
+
root_remote = get_config @@KEY_REMOTE, :branch
|
64
|
+
|
65
|
+
if print_messages; print "Pulling #{root_branch}... " end
|
66
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git pull --quiet --ff-only"
|
67
|
+
if print_messages; puts "OK" end
|
68
|
+
|
69
|
+
if print_messages; print "Creating and checking out #{name}... " end
|
70
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git checkout --quiet -b #{name}"
|
71
|
+
set_config @@KEY_ROOT_BRANCH, root_branch, :branch
|
72
|
+
set_config @@KEY_ROOT_REMOTE, root_remote, :branch
|
73
|
+
if print_messages; puts "OK" end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Creates a commit with a given message. The commit includes all change
|
77
|
+
# files.
|
78
|
+
#
|
79
|
+
# @param [String] message The commit message, which will be appended with
|
80
|
+
# +[#<story-id]+
|
81
|
+
# @param [PivotalTracker::Story] story the story associated with the current
|
82
|
+
# commit
|
83
|
+
# @return [void]
|
84
|
+
def self.create_commit(message, story)
|
85
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git commit --quiet --all --allow-empty --message \"#{message}\n\n[##{story.id}]\""
|
86
|
+
end
|
87
|
+
|
88
|
+
# Creates a tag with the given name. Before creating the tag, commits all
|
89
|
+
# outstanding changes with a commit message that reflects that these changes
|
90
|
+
# are for a release.
|
91
|
+
#
|
92
|
+
# @param [String] name the name of the tag to create
|
93
|
+
# @param [PivotalTracker::Story] story the story associated with the current
|
94
|
+
# tag
|
95
|
+
# @return [void]
|
96
|
+
def self.create_release_tag(name, story)
|
97
|
+
root_branch = branch_name
|
98
|
+
|
99
|
+
print "Creating tag v#{name}... "
|
100
|
+
|
101
|
+
create_branch @@RELEASE_BRANCH_NAME, false
|
102
|
+
create_commit "#{name} Release", story
|
103
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git tag v#{name}"
|
104
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git checkout --quiet #{root_branch}"
|
105
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git branch --quiet -D #{@@RELEASE_BRANCH_NAME}"
|
106
|
+
|
107
|
+
puts "OK"
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns a Git configuration value. This value is read using the +git
|
111
|
+
# config+ command. The scope of the value to read can be controlled with the
|
112
|
+
# +scope+ parameter.
|
113
|
+
#
|
114
|
+
# @param [String] key the key of the configuration to retrieve
|
115
|
+
# @param [:branch, :inherited] scope the scope to read the configuration from
|
116
|
+
# * +:branch+: equivalent to calling +git config branch.branch-name.key+
|
117
|
+
# * +:inherited+: equivalent to calling +git config key+
|
118
|
+
# @return [String] the value of the configuration
|
119
|
+
# @raise if the specified scope is not +:branch+ or +:inherited+
|
120
|
+
def self.get_config(key, scope = :inherited)
|
121
|
+
if :branch == scope
|
122
|
+
GitPivotalTrackerIntegration::Util::Shell.exec("git config branch.#{branch_name}.#{key}", false).strip
|
123
|
+
elsif :inherited == scope
|
124
|
+
GitPivotalTrackerIntegration::Util::Shell.exec("git config #{key}", false).strip
|
125
|
+
else
|
126
|
+
raise "Unable to get Git configuration for scope '#{scope}'"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Merges the current branch to its root branch and deletes the current branch
|
131
|
+
#
|
132
|
+
# @param [PivotalTracker::Story] story the story associated with the current
|
133
|
+
# branch
|
134
|
+
# @return [void]
|
135
|
+
def self.merge(story)
|
136
|
+
development_branch = branch_name
|
137
|
+
root_branch = get_config @@KEY_ROOT_BRANCH, :branch
|
138
|
+
|
139
|
+
print "Merging #{development_branch} to #{root_branch}... "
|
140
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git checkout --quiet #{root_branch}"
|
141
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git merge --quiet --no-ff -m \"Merge #{development_branch} to #{root_branch}\n\n[Completes ##{story.id}]\" #{development_branch}"
|
142
|
+
puts "OK"
|
143
|
+
|
144
|
+
print "Deleting #{development_branch}... "
|
145
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git branch --quiet -D #{development_branch}"
|
146
|
+
puts "OK"
|
147
|
+
end
|
148
|
+
|
149
|
+
# Push changes to the remote of the current branch
|
150
|
+
#
|
151
|
+
# @param [String] refs the explicit references to push
|
152
|
+
# @return [void]
|
153
|
+
def self.push(*refs)
|
154
|
+
remote = get_config @@KEY_REMOTE, :branch
|
155
|
+
|
156
|
+
print "Pushing to #{remote}... "
|
157
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git push --quiet #{remote} " + refs.join(" ")
|
158
|
+
puts "OK"
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the root path of the current Git repository. The root is
|
162
|
+
# determined by ascending the path hierarcy, starting with the current
|
163
|
+
# working directory (+Dir#pwd+), until a directory is found that contains a
|
164
|
+
# +.git/+ sub directory.
|
165
|
+
#
|
166
|
+
# @return [String] the root path of the Git repository
|
167
|
+
# @raise if the current working directory is not in a Git repository
|
168
|
+
def self.repository_root
|
169
|
+
repository_root = Dir.pwd
|
170
|
+
|
171
|
+
until Dir.entries(repository_root).any? { |child| File.directory?(child) && (child =~ /^.git$/) }
|
172
|
+
next_repository_root = File.expand_path("..", repository_root)
|
173
|
+
abort("Current working directory is not in a Git repository") unless repository_root != next_repository_root
|
174
|
+
repository_root = next_repository_root
|
175
|
+
end
|
176
|
+
|
177
|
+
repository_root
|
178
|
+
end
|
179
|
+
|
180
|
+
# Sets a Git configuration value. This value is set using the +git config+
|
181
|
+
# command. The scope of the set value can be controlled with the +scope+
|
182
|
+
# parameter.
|
183
|
+
#
|
184
|
+
# @param [String] key the key of configuration to store
|
185
|
+
# @param [String] value the value of the configuration to store
|
186
|
+
# @param [:branch, :global, :local] scope the scope to store the configuration value in.
|
187
|
+
# * +:branch+: equivalent to calling +git config --local branch.branch-name.key value+
|
188
|
+
# * +:global+: equivalent to calling +git config --global key value+
|
189
|
+
# * +:local+: equivalent to calling +git config --local key value+
|
190
|
+
# @return [void]
|
191
|
+
# @raise if the specified scope is not +:branch+, +:global+, or +:local+
|
192
|
+
def self.set_config(key, value, scope = :local)
|
193
|
+
if :branch == scope
|
194
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git config --local branch.#{branch_name}.#{key} #{value}"
|
195
|
+
elsif :global == scope
|
196
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git config --global #{key} #{value}"
|
197
|
+
elsif :local == scope
|
198
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git config --local #{key} #{value}"
|
199
|
+
else
|
200
|
+
raise "Unable to set Git configuration for scope '#{scope}'"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Checks whether merging the current branch back to its root branch would be
|
205
|
+
# a trivial merge. A trivial merge is defined as one where the net change
|
206
|
+
# of the merge would be the same as the net change of the branch being
|
207
|
+
# merged. The easiest way to ensure that a merge is trivial is to rebase a
|
208
|
+
# development branch onto the tip of its root branch.
|
209
|
+
#
|
210
|
+
# @return [void]
|
211
|
+
def self.trivial_merge?
|
212
|
+
development_branch = branch_name
|
213
|
+
root_branch = get_config @@KEY_ROOT_BRANCH, :branch
|
214
|
+
root_remote = get_config @@KEY_ROOT_REMOTE, :branch
|
215
|
+
|
216
|
+
print "Checking for trivial merge from #{development_branch} to #{root_branch}... "
|
217
|
+
|
218
|
+
GitPivotalTrackerIntegration::Util::Shell.exec "git fetch #{root_remote}"
|
219
|
+
|
220
|
+
remote_tip = GitPivotalTrackerIntegration::Util::Shell.exec "git rev-parse #{root_remote}/#{root_branch}"
|
221
|
+
local_tip = GitPivotalTrackerIntegration::Util::Shell.exec "git rev-parse #{root_branch}"
|
222
|
+
common_ancestor = GitPivotalTrackerIntegration::Util::Shell.exec "git merge-base #{root_branch} #{development_branch}"
|
223
|
+
|
224
|
+
if remote_tip != local_tip || local_tip != common_ancestor
|
225
|
+
abort "FAIL"
|
226
|
+
end
|
227
|
+
|
228
|
+
puts "OK"
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
@@KEY_REMOTE = "remote"
|
234
|
+
|
235
|
+
@@KEY_ROOT_BRANCH = "root-branch"
|
236
|
+
|
237
|
+
@@KEY_ROOT_REMOTE = "root-remote"
|
238
|
+
|
239
|
+
@@RELEASE_BRANCH_NAME = "pivotal-tracker-release"
|
240
|
+
|
241
|
+
end
|
242
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Git Pivotal Tracker Integration
|
2
|
+
# Copyright (c) 2013 the original author or authors.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "git-pivotal-tracker-integration/util/util"
|
17
|
+
|
18
|
+
# Utilties for dealing with the shell
|
19
|
+
class GitPivotalTrackerIntegration::Util::Shell
|
20
|
+
|
21
|
+
# Executes a command
|
22
|
+
#
|
23
|
+
# @param [String] command the command to execute
|
24
|
+
# @param [Boolean] abort_on_failure whether to +Kernel#abort+ with +FAIL+ as
|
25
|
+
# the message when the command's +Status#existstatus+ is not +0+
|
26
|
+
# @return [String] the result of the command
|
27
|
+
def self.exec(command, abort_on_failure = true)
|
28
|
+
result = `#{command}`
|
29
|
+
if $?.exitstatus != 0 && abort_on_failure
|
30
|
+
abort "FAIL"
|
31
|
+
end
|
32
|
+
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Git Pivotal Tracker Integration
|
2
|
+
# Copyright (c) 2013 the original author or authors.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "git-pivotal-tracker-integration/util/util"
|
17
|
+
require "highline/import"
|
18
|
+
require "pivotal-tracker"
|
19
|
+
|
20
|
+
# Utilties for dealing with +PivotalTracker::Story+s
|
21
|
+
class GitPivotalTrackerIntegration::Util::Story
|
22
|
+
|
23
|
+
# Print a human readable version of a story. This pretty prints the title,
|
24
|
+
# description, and notes for the story.
|
25
|
+
#
|
26
|
+
# @param [PivotalTracker::Story] story the story to pretty print
|
27
|
+
# @return [void]
|
28
|
+
def self.pretty_print(story)
|
29
|
+
print_label @@LABEL_TITLE
|
30
|
+
print_value story.name
|
31
|
+
|
32
|
+
description = story.description
|
33
|
+
if !description.nil? && !description.empty?
|
34
|
+
print_label "Description"
|
35
|
+
print_value description
|
36
|
+
end
|
37
|
+
|
38
|
+
PivotalTracker::Note.all(story).sort_by { |note| note.noted_at }.each_with_index do |note, index|
|
39
|
+
print_label "Note #{index + 1}"
|
40
|
+
print_value note.text
|
41
|
+
end
|
42
|
+
|
43
|
+
puts
|
44
|
+
end
|
45
|
+
|
46
|
+
# Selects a Pivotal Tracker story by doing the following steps:
|
47
|
+
#
|
48
|
+
# @param [PivotalTracker::Project] project the project to select stories from
|
49
|
+
# @param [String, nil] filter a filter for selecting the story to start. This
|
50
|
+
# filter can be either:
|
51
|
+
# * a story id: selects the story represented by the id
|
52
|
+
# * a story type (feature, bug, chore): offers the user a selection of stories of the given type
|
53
|
+
# * +nil+: offers the user a selection of stories of all types
|
54
|
+
# @param [Fixnum] limit The number maximum number of stories the user can choose from
|
55
|
+
# @return [PivotalTracker::Story] The Pivotal Tracker story selected by the user
|
56
|
+
def self.select_story(project, filter = nil, limit = 5)
|
57
|
+
story = nil
|
58
|
+
|
59
|
+
if filter =~ /[[:digit:]]/
|
60
|
+
story = project.stories.find filter.to_i
|
61
|
+
else
|
62
|
+
story = find_story project, filter, limit
|
63
|
+
end
|
64
|
+
|
65
|
+
story
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
@@CANDIDATE_STATES = ["rejected", "unstarted", "unscheduled"]
|
71
|
+
|
72
|
+
@@LABEL_DESCRIPTION = "Description"
|
73
|
+
|
74
|
+
@@LABEL_TITLE = "Title"
|
75
|
+
|
76
|
+
@@LABEL_WIDTH = @@LABEL_DESCRIPTION.length + 2
|
77
|
+
|
78
|
+
@@CONTENT_WIDTH = HighLine.new.output_cols - @@LABEL_WIDTH
|
79
|
+
|
80
|
+
def self.print_label(label)
|
81
|
+
print "%#{@@LABEL_WIDTH}s" % ["#{label}: "]
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.print_value(value)
|
85
|
+
if value.nil? || value.empty?
|
86
|
+
puts ""
|
87
|
+
else
|
88
|
+
value.scan(/\S.{0,#{@@CONTENT_WIDTH - 2}}\S(?=\s|$)|\S+/).each_with_index do |line, index|
|
89
|
+
if index == 0
|
90
|
+
puts line
|
91
|
+
else
|
92
|
+
puts "%#{@@LABEL_WIDTH}s%s" % ["", line]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.find_story(project, type, limit)
|
99
|
+
story = nil
|
100
|
+
|
101
|
+
criteria = {
|
102
|
+
:current_state => @@CANDIDATE_STATES,
|
103
|
+
:limit => limit
|
104
|
+
}
|
105
|
+
if type
|
106
|
+
criteria[:story_type] = type
|
107
|
+
end
|
108
|
+
|
109
|
+
candidates = project.stories.all criteria
|
110
|
+
if candidates.length == 1
|
111
|
+
story = candidates[0]
|
112
|
+
else
|
113
|
+
story = choose do |menu|
|
114
|
+
menu.prompt = "Choose story to start: "
|
115
|
+
|
116
|
+
candidates.each do |story|
|
117
|
+
name = type ? story.name : "%-7s %s" % [story.story_type.upcase, story.name]
|
118
|
+
menu.choice(name) { story }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
puts
|
123
|
+
end
|
124
|
+
|
125
|
+
story
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Git Pivotal Tracker Integration
|
2
|
+
# Copyright (c) 2013 the original author or authors.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "git_pivotal_tracker_integration"
|
17
|
+
|
18
|
+
# A module encapsulating utilities for the project
|
19
|
+
module GitPivotalTrackerIntegration::Util
|
20
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Git Pivotal Tracker Integration
|
2
|
+
# Copyright (c) 2013 the original author or authors.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "git-pivotal-tracker-integration/version-update/version_update"
|
17
|
+
|
18
|
+
# A version updater for dealing with _typical_ Gradle projects. This updater
|
19
|
+
# assumes that the version of the current project is stored within a
|
20
|
+
# +gradle.properties+ file in the root of the repository. This properties
|
21
|
+
# file should have an entry with a key of +version+ and version number as the key.
|
22
|
+
class GitPivotalTrackerIntegration::VersionUpdate::Gradle
|
23
|
+
|
24
|
+
# Creates an instance of this updater
|
25
|
+
#
|
26
|
+
# @param [String] root The root of the repository
|
27
|
+
def initialize(root)
|
28
|
+
@gradle_properties = File.expand_path "gradle.properties", root
|
29
|
+
|
30
|
+
if File.exist? @gradle_properties
|
31
|
+
groups = nil
|
32
|
+
File.open(@gradle_properties, "r") do |file|
|
33
|
+
groups = file.read().scan(/version[=:](.*)/)
|
34
|
+
end
|
35
|
+
@version = groups[0] ? groups[0][0]: nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Whether this updater supports updating this project
|
40
|
+
#
|
41
|
+
# @return [Boolean] +true+ if a valid version number was found on
|
42
|
+
# initiialization, +false+ otherwise
|
43
|
+
def supports?
|
44
|
+
!@version.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
# The current version of the project
|
48
|
+
#
|
49
|
+
# @return [String] the current version of the project
|
50
|
+
def current_version
|
51
|
+
@version
|
52
|
+
end
|
53
|
+
|
54
|
+
# Update the version of the project
|
55
|
+
#
|
56
|
+
# @param [String] new_version the version to update the project to
|
57
|
+
# @return [void]
|
58
|
+
def update_version(new_version)
|
59
|
+
contents = File.read(@gradle_properties)
|
60
|
+
contents = contents.gsub(/(version[=:])#{@version}/, "\\1#{new_version}")
|
61
|
+
File.open(@gradle_properties, "w") { |file| file.write(contents) }
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|