overview 0.0.3.61 → 0.0.4.12
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 +8 -8
- data/.gitignore +21 -0
- data/.travis.yml +3 -3
- data/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/bin/overview +52 -17
- data/lib/{appversion/appversion.rb → appversion.rb} +11 -6
- data/lib/changelog.rb +455 -0
- data/lib/{appversion → helpers}/ci.rb +4 -2
- data/lib/helpers/git.rb +67 -0
- data/lib/helpers/github.rb +81 -0
- data/lib/{appversion → helpers}/string.rb +0 -0
- data/lib/overview/version.rb +1 -1
- data/lib/overview.rb +5 -5
- data/overview.gemspec +8 -3
- data/spec/appversion_spec.rb +17 -48
- data/spec/changelog_spec.rb +12 -0
- data/spec/helpers_spec.rb +196 -0
- metadata +95 -7
- data/lib/appversion/git.rb +0 -41
data/lib/changelog.rb
ADDED
@@ -0,0 +1,455 @@
|
|
1
|
+
module Changelog
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'json'
|
5
|
+
require 'octokit'
|
6
|
+
require 'formatador'
|
7
|
+
require 'pp'
|
8
|
+
require 'yaml'
|
9
|
+
require 'logging'
|
10
|
+
require_relative 'helpers/ci'
|
11
|
+
require_relative 'helpers/git'
|
12
|
+
require_relative 'helpers/github'
|
13
|
+
require 'api_cache'
|
14
|
+
require 'moneta'
|
15
|
+
require 'faraday-http-cache'
|
16
|
+
=begin
|
17
|
+
TODO:
|
18
|
+
|
19
|
+
More than I can comprehend...
|
20
|
+
Keep all incoming data in original format, so that it can be reproccessed. e.g. Make calls. Store Data. Retrieve data. Process data. Display data. Deploy.
|
21
|
+
Mark sprint.ly items as deployed if complete. This will eventually be in a separate script.
|
22
|
+
Sprint.ly status
|
23
|
+
Compelete refactor into a modern ruby CLI app.
|
24
|
+
More info output
|
25
|
+
Color output for terminal
|
26
|
+
HTML output with embedded links
|
27
|
+
Logic to be improved for push and pull rquests
|
28
|
+
Deployment logic to work differently for feature branches... I think
|
29
|
+
=end
|
30
|
+
|
31
|
+
class Base
|
32
|
+
def initialize
|
33
|
+
@logger = Logging.logger[self]
|
34
|
+
@logger.add_appenders \
|
35
|
+
Logging.appenders.stdout,
|
36
|
+
Logging.appenders.file('overview.log')
|
37
|
+
@logger.level = :info
|
38
|
+
|
39
|
+
APICache.store = Moneta.new(:YAML, :file => "#{self.class.name}_cache")
|
40
|
+
APICache.logger.level = Logger::DEBUG
|
41
|
+
|
42
|
+
#Caching for octokit
|
43
|
+
#store = Moneta.new(:YAML, :file => 'changelog_octokit.cache')
|
44
|
+
stack = Faraday::RackBuilder.new do |builder|
|
45
|
+
builder.use Faraday::HttpCache
|
46
|
+
builder.use Octokit::Response::RaiseError
|
47
|
+
#builder.use :store => store
|
48
|
+
builder.adapter Faraday.default_adapter
|
49
|
+
end
|
50
|
+
|
51
|
+
Octokit.middleware = stack
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Release < Base
|
56
|
+
def initialize(name, description, sha, date, status=nil, items=nil)
|
57
|
+
super()
|
58
|
+
status ||= "NA"
|
59
|
+
@name = name.delete("\n")
|
60
|
+
|
61
|
+
@description = description
|
62
|
+
@sha = sha
|
63
|
+
@date = date
|
64
|
+
@status = status
|
65
|
+
@items = items
|
66
|
+
end
|
67
|
+
|
68
|
+
def commits
|
69
|
+
end
|
70
|
+
|
71
|
+
def items
|
72
|
+
@items
|
73
|
+
end
|
74
|
+
|
75
|
+
def inspect
|
76
|
+
str = "<#{@name} at #{@date.strftime("%x")} (#{@items.length} items)>"
|
77
|
+
@items.each { |i| str.concat("<#{i.inspect}>") }
|
78
|
+
return str
|
79
|
+
end
|
80
|
+
|
81
|
+
def name
|
82
|
+
return @name
|
83
|
+
end
|
84
|
+
|
85
|
+
def date
|
86
|
+
return @date
|
87
|
+
end
|
88
|
+
|
89
|
+
def status
|
90
|
+
return @status
|
91
|
+
end
|
92
|
+
|
93
|
+
def released?
|
94
|
+
return self.status == "RELEASED"
|
95
|
+
end
|
96
|
+
|
97
|
+
def display
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Item
|
103
|
+
def initialize(title, id, description, sha, date, source, type=nil, status=nil, author=nil, environments=nil)
|
104
|
+
type ||="NA"
|
105
|
+
status ||="UNKNOWN"
|
106
|
+
author ||="UNKNOWN"
|
107
|
+
environments ||= []
|
108
|
+
@title = title.delete("\n")
|
109
|
+
@description = description
|
110
|
+
@sha = sha
|
111
|
+
@date = date
|
112
|
+
@id = id
|
113
|
+
@source = source
|
114
|
+
@type = type
|
115
|
+
@status = status
|
116
|
+
@author = author
|
117
|
+
@environments = environments
|
118
|
+
end
|
119
|
+
|
120
|
+
def inspect
|
121
|
+
"<#{@source} #{@type.upcase} ##{@id} : #{self.status} : #{@title}>"
|
122
|
+
end
|
123
|
+
|
124
|
+
def title
|
125
|
+
return @title
|
126
|
+
end
|
127
|
+
|
128
|
+
def date
|
129
|
+
return @date
|
130
|
+
end
|
131
|
+
|
132
|
+
def type
|
133
|
+
return @type
|
134
|
+
end
|
135
|
+
|
136
|
+
def author
|
137
|
+
return @author
|
138
|
+
end
|
139
|
+
|
140
|
+
def environments
|
141
|
+
return @environments.any? ? @environments : nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def sha
|
145
|
+
return @sha
|
146
|
+
end
|
147
|
+
|
148
|
+
def id
|
149
|
+
return @id
|
150
|
+
end
|
151
|
+
|
152
|
+
def status
|
153
|
+
return @status.nil? ? "NA" : @status.upcase
|
154
|
+
end
|
155
|
+
|
156
|
+
def source
|
157
|
+
return @source
|
158
|
+
end
|
159
|
+
|
160
|
+
def sprintly?
|
161
|
+
return self.source.upcase == "SPRINT.LY"
|
162
|
+
end
|
163
|
+
|
164
|
+
def complete?
|
165
|
+
return %w(COMPLETED ACCEPTED).include?(self.status)
|
166
|
+
end
|
167
|
+
|
168
|
+
def built?
|
169
|
+
return self.environments.join.scan(/#(\d+)/).any? unless self.environments.nil?
|
170
|
+
end
|
171
|
+
|
172
|
+
def released?
|
173
|
+
return self.environments.join.scan(/v(\d+)/).any? unless self.environments.nil?
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class Log < Base
|
178
|
+
def githubReleaseStatus(release=nil)
|
179
|
+
case
|
180
|
+
when release.nil?
|
181
|
+
status = "NA"
|
182
|
+
when release.draft
|
183
|
+
status = "DRAFT"
|
184
|
+
when release.prerelease
|
185
|
+
status = "PRE-RELEASE"
|
186
|
+
else
|
187
|
+
status = "RELEASED"
|
188
|
+
end
|
189
|
+
return status
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
def displayEnvironments(environments)
|
194
|
+
case
|
195
|
+
when environments.nil?
|
196
|
+
environments = ""
|
197
|
+
when environments.compact.length > 0
|
198
|
+
environments = " [" + environments.compact.join(", ") + "]"
|
199
|
+
else
|
200
|
+
environments = ""
|
201
|
+
end
|
202
|
+
return environments
|
203
|
+
end
|
204
|
+
|
205
|
+
def deploy(releases)
|
206
|
+
buildItems = []
|
207
|
+
allReleasedItems = []
|
208
|
+
releases.each { |r|
|
209
|
+
releaseItems = []
|
210
|
+
r.items.each { |i|
|
211
|
+
buildItems << i.id unless (i.built? || !i.complete?) #potential write each build for incomplete tasks or stories...not sure
|
212
|
+
releaseItems << i.id unless (i.released? || !i.complete? || !r.released? || allReleasedItems.include?(i.id))
|
213
|
+
}
|
214
|
+
allReleasedItems.concat(releaseItems)
|
215
|
+
releaseEnvironment = "Release #{r.name}"
|
216
|
+
sprintlyDeploy(releaseItems.uniq, releaseEnvironment) unless (releaseEnvironment.nil? || !releaseItems.any?)
|
217
|
+
}
|
218
|
+
buildEnvironment = "Build ##{ENV['TRAVIS_BUILD_NUMBER']}"
|
219
|
+
sprintlyDeploy(buildItems.uniq, buildEnvironment) unless (buildEnvironment.nil? || !buildItems.any?)
|
220
|
+
end
|
221
|
+
|
222
|
+
#refactor to keep source data separate, and update environments on sprint.ly ticket so future checks return the new environemnt
|
223
|
+
#deployments should also be batched, with one api call for all items of the build or release
|
224
|
+
#@iterations = 0
|
225
|
+
def sprintlyDeploy(ids, environment)
|
226
|
+
#@iterations += 1
|
227
|
+
data = {:environment => environment, :numbers => ids.join(",")}
|
228
|
+
url = "https://sprint.ly/api/products/#{@product_id}/deploys.json"
|
229
|
+
response = HTTParty.post(url, {:basic_auth => @auth, :body => data})
|
230
|
+
item = JSON.parse(response.body)
|
231
|
+
#pp item
|
232
|
+
#exit unless @iterations < 2
|
233
|
+
#curl -u jono@overllc.com:WXKp2h3F38VUm2CmzxpqBYMDZBFvw84f --data "environment=test&numbers=22,8" https://sprint.ly/api/products/20064/deploys.json
|
234
|
+
end
|
235
|
+
|
236
|
+
def displayReleases(releases)
|
237
|
+
f = Formatador.new
|
238
|
+
types = releases.flat_map { |r|
|
239
|
+
r.items.flat_map { |i|
|
240
|
+
i.type
|
241
|
+
}
|
242
|
+
}.uniq
|
243
|
+
environments = releases.flat_map { |r|
|
244
|
+
r.items.flat_map { |i|
|
245
|
+
i.environments.flatten unless i.environments.nil?
|
246
|
+
}
|
247
|
+
}.uniq.compact
|
248
|
+
#puts environments.inspect
|
249
|
+
releases.each { |r|
|
250
|
+
f.display_line("#{r.name} (#{r.status.upcase}, #{displayDate(r.date)})")
|
251
|
+
f.indent {
|
252
|
+
|
253
|
+
types.each { |t|
|
254
|
+
items = r.items.select { |i| i.type == t }
|
255
|
+
f.display_line("#{t.upcase}") if items.length > 0
|
256
|
+
f.indent {
|
257
|
+
items.each { |i|
|
258
|
+
# i.sha[0..6]
|
259
|
+
#TODO fix this
|
260
|
+
bullet = ENV['TRAVIS_COMMIT'] == i.sha[0..6] ? "+" : "•"
|
261
|
+
f.display_line("#{bullet} ##{i.id}: #{i.title} (#{i.status.upcase}; #{i.author}; #{displayDate(i.date)})#{displayEnvironments(i.environments)}")
|
262
|
+
|
263
|
+
}
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
def idsFromCommitMessage(message)
|
272
|
+
commands = %w(close closed closes finish finished finishes fix fixed fixes breaks unfixes reopen reopens re-open re-opens addresses re ref references refs start starts see).collect { |x| "\\b#{x}\\b" }.join("|")
|
273
|
+
prefixes = %w(task issue defect bug item ticket).collect { |x| "\\b#{x}:\\b" }.join("|") + "|#"
|
274
|
+
re = Regexp.new(/(?:#{commands})\s(?:#{prefixes})(\d+)/)
|
275
|
+
#working re = Regexp.new(/(?:#{commands})\s(?:#{prefixes})(\d+)/)
|
276
|
+
#working re = Regexp.new(/(?:\bcloses\b|\bfixes\b)..(\d+)/)
|
277
|
+
#puts re.source
|
278
|
+
|
279
|
+
sprintlyIds = message.scan(re).flatten.compact
|
280
|
+
crashlyticsIds = message.scan(/(c|C):(?<crashlytics>\d+)/).flatten.compact
|
281
|
+
return sprintlyIds, crashlyticsIds
|
282
|
+
end
|
283
|
+
|
284
|
+
def crashlyticsItem(title, id, sha, date, author)
|
285
|
+
#puts " " + item["type"].capitalize + " " + item["number"].to_s + ": " + item["title"]
|
286
|
+
return Item.new(title, id, "NA", sha, date, "Crashlytics", "crash", nil, author)
|
287
|
+
end
|
288
|
+
|
289
|
+
#TODO - consider returning sprint.ly story rather than task
|
290
|
+
#TODO - cache raw response, not item
|
291
|
+
def sprintlyItem(id, sha, date, author)
|
292
|
+
url = "https://sprint.ly/api/products/" + @product_id + "/items/" + id + ".json"
|
293
|
+
APICache.get(url, :timeout => 30, :fail => []) do
|
294
|
+
response = HTTParty.get(url, :basic_auth => @auth)
|
295
|
+
item = JSON.parse(response.body)
|
296
|
+
Item.new(item["title"], item["number"], item["description"], sha, date, "Sprint.ly", item["type"], item["status"], author, item["deployed_to"])
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def commitItem(commit)
|
301
|
+
APICache.get(commit.sha, :fail => []) do
|
302
|
+
Item.new(commit.commit.message.lines.first, commit.sha[0..6], commit.commit.message, commit.sha, commit.commit.author.date, "Github", "commit", "NA", commit.commit.author.name)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
|
308
|
+
def itemsFromCommit(commit)
|
309
|
+
#pp commit
|
310
|
+
items = []
|
311
|
+
sprintlyIds, crashlyticsIds = idsFromCommitMessage(commit.commit.message)
|
312
|
+
#puts sprintlyIds.class
|
313
|
+
#puts commit.commit.message
|
314
|
+
unless (sprintlyIds.nil? || !sprintlyIds.any?) then
|
315
|
+
sprintlyIds.each { |id| items << sprintlyItem(id, commit.sha, commit.commit.author.date, commit.commit.author.name) }
|
316
|
+
end
|
317
|
+
unless (crashlyticsIds.nil? || !crashlyticsIds.any?) then
|
318
|
+
crashlyticsIds.each { |id| items << crashlyticsItem(commit.commit.message.lines.first, id, commit.sha, commit.commit.author.date, commit.commit.author.name) }
|
319
|
+
end
|
320
|
+
items << commitItem(commit) unless (!items.nil? && items.any?)
|
321
|
+
return items
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
def displayDate(date)
|
326
|
+
return date.strftime("%-d-%b-%Y")
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
#*****
|
331
|
+
#deploy items parsed from travis commit sha (as I can't check what was previosuly undeployed)
|
332
|
+
#awaiting improvements from sprint.ly - due 19 Feb
|
333
|
+
#*****
|
334
|
+
|
335
|
+
#TRAVIS_COMMIT_RANGE
|
336
|
+
|
337
|
+
def getReleasesFromServices
|
338
|
+
|
339
|
+
|
340
|
+
#user = @github.client.user
|
341
|
+
#user.login
|
342
|
+
|
343
|
+
|
344
|
+
result = []
|
345
|
+
|
346
|
+
all_releases = @github.releases
|
347
|
+
#p all_releases.inspect
|
348
|
+
r = all_releases.first
|
349
|
+
#p r
|
350
|
+
p r.tag_name
|
351
|
+
ref = @github.ref(r.tag_name)
|
352
|
+
sha = ref.object.sha
|
353
|
+
commit = @github.commit(sha).commit
|
354
|
+
since = commit.author.date
|
355
|
+
|
356
|
+
commits = @github.commits_since(since)
|
357
|
+
commits.pop #remove commit from last release - not sure why this in necessary and recon that it is not accurate either
|
358
|
+
|
359
|
+
items = []
|
360
|
+
commits.each { |c| items.concat(itemsFromCommit(c)) }
|
361
|
+
|
362
|
+
release = Release.new("Next Version", "NA", sha, since, "NA", items)
|
363
|
+
|
364
|
+
result << release
|
365
|
+
|
366
|
+
releases = all_releases.take(ENV['NO_OF_RELEASES'].to_i)
|
367
|
+
|
368
|
+
releases.each_with_index { |r, index|
|
369
|
+
|
370
|
+
next_r = all_releases[index+1] unless index == all_releases.size - 1 #note we use all_releases for this
|
371
|
+
ref = @github.ref(r.tag_name)
|
372
|
+
sha = ref.object.sha
|
373
|
+
commit = @github.commit(sha).commit
|
374
|
+
|
375
|
+
to = commit.author.date
|
376
|
+
|
377
|
+
if next_r
|
378
|
+
next_ref = @github.ref(next_r.tag_name)
|
379
|
+
next_sha = next_ref.object.sha
|
380
|
+
next_commit = @github.commit(next_sha).commit
|
381
|
+
from = next_commit.author.date
|
382
|
+
commits = @github.client.commits_between(ENV['TRAVIS_REPO_SLUG'], from, to, ENV['TRAVIS_BRANCH'])
|
383
|
+
else
|
384
|
+
commits = @github.client.commits_before(ENV['TRAVIS_REPO_SLUG'], to, ENV['TRAVIS_BRANCH'])
|
385
|
+
end
|
386
|
+
|
387
|
+
items = []
|
388
|
+
commits.each { |c| items.concat(itemsFromCommit(c)) }
|
389
|
+
|
390
|
+
release = Release.new(r.tag_name, r.name, sha, to, githubReleaseStatus(r), items)
|
391
|
+
|
392
|
+
result << release
|
393
|
+
}
|
394
|
+
return result
|
395
|
+
end
|
396
|
+
|
397
|
+
def getReleasesFromYAML
|
398
|
+
return YAML.load_file(Dir.pwd + ENV['YAML_BACKUP']) if File.file?(Dir.pwd + ENV['YAML_BACKUP'])
|
399
|
+
end
|
400
|
+
|
401
|
+
def saveReleasesToYAML(releases)
|
402
|
+
File.open(Dir.pwd + ENV['YAML_BACKUP'], 'w') { |file| file.write(releases.to_yaml) }
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
def initialize
|
407
|
+
|
408
|
+
super
|
409
|
+
@commit = CI.commit || Git.commit_sha
|
410
|
+
@repo = CI.repo || Git.repo
|
411
|
+
@build_no = CI.build_no
|
412
|
+
@branch = CI.branch || Git.branch
|
413
|
+
|
414
|
+
warning = 'Unable to determine repo branch' if @branch.nil?
|
415
|
+
warning = 'Unable to determine SHA1' if @commit.nil?
|
416
|
+
warning = 'Unable to determine repo' if @repo.nil?
|
417
|
+
warning = 'Unable to determine GITHUB_TOKEN' if ENV['GITHUB_TOKEN'].nil?
|
418
|
+
warning = 'Unable to determine TRAVIS_TOKEN' if ENV['TRAVIS_TOKEN'].nil?
|
419
|
+
warning = 'Unable to determine SPRINTLY_USER' if ENV['SPRINTLY_USER'].nil?
|
420
|
+
warning = 'Unable to determine SPRINTLY_API_KEY' if ENV['SPRINTLY_API_KEY'].nil?
|
421
|
+
|
422
|
+
@logger.error warning if warning
|
423
|
+
|
424
|
+
ENV['NO_OF_RELEASES'] = '2'
|
425
|
+
ENV['YAML_BACKUP'] = '/releases.yml'
|
426
|
+
ENV['TRAVIS_COMMIT_RANGE'] = nil if ENV['TRAVIS_COMMIT_RANGE'].nil?
|
427
|
+
|
428
|
+
@auth = {:username => ENV['SPRINTLY_USER'], :password => ENV['SPRINTLY_API_KEY']}
|
429
|
+
|
430
|
+
@repo = CI.repo || Git.repo
|
431
|
+
@branch = CI.branch || Git.branch
|
432
|
+
#TODO abstract Github via CI class
|
433
|
+
@github = Github.new(@repo, @branch)
|
434
|
+
|
435
|
+
@product_id = @github.sprintly_product_id
|
436
|
+
if !@product_id
|
437
|
+
@logger.error "Unable to retrieve Sprint.ly product_id for #{repo}"
|
438
|
+
exit 1
|
439
|
+
end
|
440
|
+
|
441
|
+
|
442
|
+
#@releases = getReleasesFromYAML
|
443
|
+
@releases = getReleasesFromServices if @releases.nil?
|
444
|
+
#saveReleasesToYAML @releases unless @releases.nil?
|
445
|
+
end
|
446
|
+
|
447
|
+
def display(audience='production')
|
448
|
+
displayReleases @releases unless @releases.nil?
|
449
|
+
end
|
450
|
+
|
451
|
+
def commit
|
452
|
+
@commit
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
data/lib/helpers/git.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative 'string.rb'
|
2
|
+
|
3
|
+
class Git
|
4
|
+
def self.remote
|
5
|
+
begin
|
6
|
+
`git remote -v show`.lines.first.strip.match(/github\.com[\/|:](.+)\.git/)[1]
|
7
|
+
rescue
|
8
|
+
$stderr.puts 'Unable to retrieve slug from >> git remote -v show'
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def self.repo
|
13
|
+
remote
|
14
|
+
end
|
15
|
+
def self.branch
|
16
|
+
`git rev-parse --abbrev-ref HEAD`.strip
|
17
|
+
end
|
18
|
+
def self.tag
|
19
|
+
(`git describe --tags --match 'v*' --abbrev=0 2>/dev/null` || 'HEAD').strip
|
20
|
+
end
|
21
|
+
def self.clean_tag(tag=self.tag)
|
22
|
+
tag.strip.sub('v','').split(/[\.,-]/).select { |e| e.is_number?}.first(3).join('.')
|
23
|
+
end
|
24
|
+
def self.commit_count
|
25
|
+
`git rev-list --count HEAD`.to_i
|
26
|
+
end
|
27
|
+
def self.commit_count_since_tag(tag)
|
28
|
+
`git rev-list --count ${tag}.. 2>/dev/null`.to_i
|
29
|
+
end
|
30
|
+
def self.installed?
|
31
|
+
system 'git --version >>/dev/null 2>&1'
|
32
|
+
end
|
33
|
+
def self.parse_deploy(commitMessage)
|
34
|
+
commands = %w(deploy DEPLOY force_deploy FORCE_DEPLOY).collect{ |x| "\\b#{x}\\b" }.join("|")
|
35
|
+
re = Regexp.new(/<(#{commands}):?\s*(.*?)(?:>)/)
|
36
|
+
deploy = commitMessage.scan(re).flatten.compact
|
37
|
+
return !deploy[0].nil? && !deploy[0].empty?, deploy[1] || ''
|
38
|
+
end
|
39
|
+
def self.parse_crashlytics(commitMessage)
|
40
|
+
return commitMessage.scan(/(c|C):(?<crashlytics>\d+)/).flatten.collect { |x| x.to_i }.uniq
|
41
|
+
end
|
42
|
+
def self.parse_sprintly(commitMessage)
|
43
|
+
commands = %w(close closed closes finish finished finishes fix fixed fixes breaks unfixes reopen reopens re-open re-opens addresses re ref references refs start starts see).collect{ |x| "\\b#{x}\\b" }.join("|")
|
44
|
+
prefixes = %w(task issue defect bug item ticket).collect{ |x| "\\b#{x}:\\b" }.join("|") + "|#"
|
45
|
+
re = Regexp.new(/(?:#{commands})\s(?:#{prefixes})(\d+)/)
|
46
|
+
return commitMessage.downcase.scan(re).flatten.collect{ |x| x.to_i }.uniq
|
47
|
+
end
|
48
|
+
def self.parse_commit_message(commitMessage)
|
49
|
+
h = Hash.new
|
50
|
+
deploy, message = self.parse_deploy(commitMessage)
|
51
|
+
sprintly_tickets = self.parse_sprintly(commitMessage)
|
52
|
+
crashlytics_ids = self.parse_crashlytics(commitMessage)
|
53
|
+
h["deploy?"] = deploy
|
54
|
+
h["message"] = message
|
55
|
+
h["sprintly"] = sprintly_tickets
|
56
|
+
h["crashlytics"] = crashlytics_ids
|
57
|
+
return h
|
58
|
+
end
|
59
|
+
def self.commit_sha
|
60
|
+
`git rev-parse HEAD`.strip
|
61
|
+
end
|
62
|
+
def self.commit_short_sha
|
63
|
+
`git rev-parse --short HEAD`.strip
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'api_cache'
|
2
|
+
require 'moneta'
|
3
|
+
require 'octokit'
|
4
|
+
#TODO - this is actually a github class
|
5
|
+
class Github
|
6
|
+
#TODO make this a singleton
|
7
|
+
#TODO add repo, and branch to cache keys
|
8
|
+
def initialize(repo, branch, github_token=ENV['GITHUB_TOKEN'])
|
9
|
+
#TODO: inherit from base class
|
10
|
+
@github_token = github_token
|
11
|
+
@repo = repo
|
12
|
+
@branch = branch
|
13
|
+
@logger = Logging.logger[self]
|
14
|
+
@logger.add_appenders \
|
15
|
+
Logging.appenders.stdout,
|
16
|
+
Logging.appenders.file('overview.log')
|
17
|
+
@logger.level = :info
|
18
|
+
|
19
|
+
APICache.store = Moneta.new(:YAML, :file => "#{self.class.name}_cache")
|
20
|
+
APICache.logger.level = Logger::INFO
|
21
|
+
#APICache.store = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def client
|
25
|
+
if !@client
|
26
|
+
@client = Octokit::Client.new(:access_token => @github_token)
|
27
|
+
@client.auto_paginate = true
|
28
|
+
@client.default_media_type = "application/vnd.github.moondragon+json"
|
29
|
+
@logger.info "Connected to Github" if @client
|
30
|
+
end
|
31
|
+
@client
|
32
|
+
end
|
33
|
+
|
34
|
+
def hooks
|
35
|
+
@hooks = client.hooks(@repo) unless @hooks
|
36
|
+
@logger.info "Retrieved hooks for #{@repo}" if @hooks
|
37
|
+
@hooks
|
38
|
+
end
|
39
|
+
|
40
|
+
def releases
|
41
|
+
#APICache.get("releases") do
|
42
|
+
client.releases(@repo)
|
43
|
+
#end
|
44
|
+
end
|
45
|
+
|
46
|
+
def sprintly_product_id
|
47
|
+
#TODO this could also return a CLI flag or env variable
|
48
|
+
APICache.get("sprintly_product_id_#{@repo}", :fail => [], :timeout => 30) do
|
49
|
+
@logger.info "Not using cache"
|
50
|
+
product_id = hooks.map { |h| h.config.product_id }.compact.first
|
51
|
+
@logger.info "Sprint.ly product_id = #{product_id}" if product_id
|
52
|
+
product_id
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def ref(tag)
|
57
|
+
#APICache.get("ref_#{tag}") do
|
58
|
+
client.ref(@repo, "tags/" + tag)
|
59
|
+
#end
|
60
|
+
end
|
61
|
+
|
62
|
+
def commit(sha)
|
63
|
+
#APICache.get("commit_#{sha}") do
|
64
|
+
client.commit(@repo, sha)
|
65
|
+
#end
|
66
|
+
end
|
67
|
+
|
68
|
+
def commits_since(since)
|
69
|
+
#APICache.get("commit_since_#{since}") do
|
70
|
+
client.commits_since(@repo, since, @branch)
|
71
|
+
#end
|
72
|
+
end
|
73
|
+
|
74
|
+
def commits_between(from,to)
|
75
|
+
|
76
|
+
end
|
77
|
+
def commits_before(to)
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
File without changes
|
data/lib/overview/version.rb
CHANGED
data/lib/overview.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require_relative 'overview/version.rb'
|
2
|
-
require_relative '
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative 'appversion
|
6
|
-
|
2
|
+
require_relative 'helpers/git.rb'
|
3
|
+
require_relative 'helpers/ci.rb'
|
4
|
+
require_relative 'helpers/string.rb'
|
5
|
+
require_relative 'appversion.rb'
|
6
|
+
require_relative 'changelog.rb'
|
7
7
|
|
8
8
|
# Add requires for other files you add to your project here, so
|
9
9
|
# you just need to require this one file in your bin file
|
data/overview.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Ensure we require the local version and not one we might have installed already
|
2
|
-
require File.join([File.dirname(__FILE__),'lib
|
2
|
+
require File.join([File.dirname(__FILE__),'lib/overview','version.rb'])
|
3
3
|
|
4
4
|
spec = Gem::Specification.new do |s|
|
5
5
|
s.name = 'overview'
|
@@ -8,7 +8,7 @@ spec = Gem::Specification.new do |s|
|
|
8
8
|
s.email = 'jono@overllc.com'
|
9
9
|
s.homepage = 'http://www.overllc.com'
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
|
-
s.summary = "Over's custom CI / CD toolchain, integrating Sprint.ly, Github,
|
11
|
+
s.summary = "Over's custom CI / CD toolchain, integrating Sprint.ly, Github, Github and ITC"
|
12
12
|
s.files = `git ls-files`.split("
|
13
13
|
")
|
14
14
|
s.require_paths << 'lib'
|
@@ -26,5 +26,10 @@ spec = Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency('gem-release')
|
27
27
|
s.add_runtime_dependency('gli','2.13.0')
|
28
28
|
s.add_runtime_dependency('octokit','3.8.0')
|
29
|
-
|
29
|
+
s.add_runtime_dependency('httparty')
|
30
|
+
s.add_runtime_dependency('formatador')
|
31
|
+
s.add_runtime_dependency('moneta')
|
32
|
+
s.add_runtime_dependency('api_cache')
|
33
|
+
s.add_runtime_dependency('logging')
|
34
|
+
s.add_runtime_dependency('faraday-http-cache')
|
30
35
|
end
|