atlassian_app_versions 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: adf2ac0abf92f4d86b0639d92003fece5c53d041
4
+ data.tar.gz: c78319e42020b8e8ebb00cbf3a2000b7d950a352
5
+ SHA512:
6
+ metadata.gz: 514cb6322b96b3e64850bb4e96a9370396e99badc115831272a54c2ececca96701d4b795b328c5218a785e1bd8a1b3c4ca03f4c3bf3934a52b359d0a35f5564d
7
+ data.tar.gz: 075ec3e2a2e3f1dc8bb1deda238caa5620c003f654d8c347e4b8a275532e53a40b1025b2396c5f8bbab8efcd7833d4f72aaa6642f7abddbfa28f0051a458648d
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in atlassian_app_versions.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,42 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ guard :minitest do
19
+ # with Minitest::Unit
20
+ watch(%r{^test/(.*)\/?test_(.*)\.rb$})
21
+ watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
22
+ watch(%r{^test/test_helper\.rb$}) { 'test' }
23
+
24
+ # with Minitest::Spec
25
+ # watch(%r{^spec/(.*)_spec\.rb$})
26
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
27
+ # watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
28
+
29
+ # Rails 4
30
+ # watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
31
+ # watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
32
+ # watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
33
+ # watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
34
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
35
+ # watch(%r{^test/.+_test\.rb$})
36
+ # watch(%r{^test/test_helper\.rb$}) { 'test' }
37
+
38
+ # Rails < 4
39
+ # watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
40
+ # watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
41
+ # watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
42
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jeff Turner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # AtlassianAppVersions
2
+
3
+ This Gem obtains info about Atlassian product and plugin releases from the https://marketplace.atlassian.com and https://my.atlassian.com REST APIs.
4
+
5
+ See also the `atlassian_app_upgradereport` gem which uses this info to produce Confluence reports.
6
+
7
+ ## Usage
8
+
9
+ There are two top-level classes, `App` instantiated with a product name, and `Plugin` instantiated with a plugin key (key names are from https://marketplace.atlassian.com). `App` and `Plugin` behave similarly, in that they expose a bunch of properties (call the `.keys` method to see what's available), have `version` and `versions` methods to list their versions, and a set of methods (
10
+
11
+ Sample API use:
12
+
13
+ ```ruby
14
+ require 'atlassian_app_versions'
15
+ include AtlassianAppVersions
16
+
17
+ # Info about an Atlassian product
18
+
19
+ conf = App.new("confluence")
20
+ conf.latest # #<AtlassianAppVersions::LatestAppVersion:70118429916620 5.9.10>
21
+ conf.version("5.9.10") # => #<AtlassianAppVersions::LatestAppVersion:70271671608160 5.9.10>
22
+ conf.version("5.9.10").version # => => "5.9.10"
23
+ conf.version("5.9.10").releaseDate # => #<DateTime: 2016-05-05T00:00:00+00:00 ((2457514j,0s,0n),+0s,2299161j)>
24
+ conf.version("5.9.10").relNotes # => "http://confluence.atlassian.com/display/DOC/Confluence+5.9.10+Release+Notes"
25
+
26
+
27
+ conf.versions("5.9.1", "5.9.5") # => [#<AtlassianAppVersions::ArchivedAppVersion:70118438447880 5.9.5>,
28
+ #<AtlassianAppVersions::ArchivedAppVersion:70118438447860 5.9.4>,
29
+ #<AtlassianAppVersions::ArchivedAppVersion:70118438447840 5.9.3>,
30
+ #<AtlassianAppVersions::ArchivedAppVersion:70118438447820 5.9.2>]
31
+ conf.latest.relNotes # => "http://confluence.atlassian.com/display/DOC/Confluence+5.9.10+Release+Notes"
32
+ conf.latest.keys # => ["description", "zipUrl", "tarUrl", "md5", "size", "released", ...]
33
+ conf.latest.zipUrl # => "https://www.atlassian.com/software/confluence/downloads/binary/atlassian-confluence-5.9.10.tar.gz"
34
+
35
+
36
+ # JQL for bugs fixed in the latest release
37
+ conf.bugsJQL(conf.versions[1], conf.versions[0]) # => "issuetype=Bug AND project=CONF AND fixVersion in (5.9.10) AND status in (Resolved, Closed, Soaking) ORDER BY votes DESC, priority DESC, key DESC"
38
+
39
+
40
+ # Info about an Atlassian plugin
41
+
42
+ plugin = Plugin.new("de.scandio.confluence.plugins.pocketquery")
43
+ plugin.name # => "PocketQuery"
44
+ # Available info on the plugin
45
+ plugin.keys # => ["downloadCount", "name", "deployment", "deployable", "lastModified", "description",..]
46
+
47
+ # Available info a specific release
48
+ plugin.latest.keys # => ["supportType", "releaseDate", "deployment", "deployable", "marketplaceType", "compatibilities", "screenshots", "releasedBy", "license", "version", "links", "status", "marketplaceAgreementAccepted", "pluginSystemVersion", "instructions", "autoUpdateAllowed", "compatibleApplications", "stable", "buildNumber", "summary", "addOnType"]
49
+
50
+ plugin.latest.version # => "2.0.7"
51
+
52
+ ```
53
+
54
+
55
+ ## Installation
56
+
57
+ - Install Ruby 2.3.1 or above (I use [ruby-install](https://github.com/postmodern/ruby-install) + [chruby](https://github.com/postmodern/chruby)). Then:
58
+ ```bash
59
+ gem install bundler
60
+ git clone https://redradish@bitbucket.org/redradish/atlassian_app_versions.git
61
+ cd atlassian_app_versions
62
+ bundle install # Install this gem's deps
63
+ bundle exec rake install # Install this gem
64
+ bundle exec rake test # Ensure it's all happy
65
+ ```
66
+ Then try the sample code above in `irb` or `pry`.
67
+
68
+ ## Development
69
+
70
+ In the finest tradition of Ruby gems, this gem is a hasty hack thrown together. The code would make experienced Rubyists cry. There is no guarantee of API stability.
71
+
72
+ ## License
73
+
74
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
75
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'atlassian_app_versions'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "atlassian_app_versions"
8
+ spec.version = AtlassianAppVersions::VERSION
9
+ spec.authors = ["Jeff Turner"]
10
+ spec.email = ["jeff@redradishtech.com"]
11
+
12
+ spec.summary = %q{Obtain info about Atlassian JIRA and other product releases.}
13
+ spec.description = %q{Wraps the marketplace.atlassian.com and my.atlassian.com REST APIs to obtain info about JIRA releases. See commented-out code near end for examples.}
14
+ #
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ #if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ #else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ #end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.11"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "minitest", "~> 5.0"
33
+ spec.add_development_dependency "minitest-reporters", "~> 1.1"
34
+ spec.add_development_dependency "guard"
35
+ spec.add_development_dependency "guard-minitest"
36
+ end
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "atlassian_app_versions"
5
+ include AtlassianAppVersions
6
+
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+
11
+ # (If you use this, don't forget to add pry to your Gemfile!)
12
+ # require "pry"
13
+ # Pry.start
14
+
15
+ require "irb"
16
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,386 @@
1
+ #######
2
+ # Wraps the marketplace.atlassian.com and my.atlassian.com REST APIs to obtain info about JIRA releases. See commented-out code near end for examples.
3
+ #
4
+ # marketplace.atlassian.com data returns simple version data for plugins and apps.
5
+ # my.atlassian.com data returns release notes and download locations, but only for apps.
6
+ #
7
+ # We maintain the facade of having Version objects. Versions get their data by requesting either MPAC or MAC JSON from their @parent, which caches the JSON.
8
+ #
9
+ require 'open-uri'
10
+ require 'json'
11
+ require 'cgi'
12
+
13
+ module AtlassianAppVersions
14
+
15
+ VERSION = "0.1.4"
16
+
17
+ # A Plugin or App. This class assumes the MPAC API will have info about the product.
18
+ class AbstractProduct
19
+
20
+ JAC_URL="https://jira.atlassian.com"
21
+
22
+ attr_accessor :key
23
+ # Initialize with a MPAC key (e.g. "jira" or "com.pyxis.greenhopper.jira")
24
+ def initialize(key)
25
+ @key=key
26
+ end
27
+
28
+ # JQL for all issues resolved after +fromVer+ up to and including +toVer+.
29
+ def allissuesJQL(fromVer=nil, toVer=nil)
30
+ templateJQL(fromVer, toVer)
31
+ end
32
+
33
+ # JQL for all Bugs resolved after +fromVer+ up to and including +toVer+.
34
+ def bugsJQL(fromVer=nil, toVer=nil)
35
+ "issuetype=Bug AND " + templateJQL(fromVer, toVer)
36
+ end
37
+
38
+ # JQL for all features resolved after +fromVer+ up to and including +toVer+.
39
+ def featuresJQL(fromVer=nil, toVer=nil)
40
+ "issuetype!=Bug AND " + templateJQL(fromVer, toVer)
41
+ end
42
+
43
+ # JQL for all new, unresolved Bugs _introduced_ in the (up to) 3 versions before +toVer+, but after +fromVer+. This means bugs reported against a version in the range, but not reported against an earlier version (up to +pastVersionsToIgnore+ old versions are considered, since some really old versions are missing from JAC and break the query).
44
+ def recentbugsJQL(fromVer, toVer=nil, includedVersionCount=3, pastVersionsToIgnore=50)
45
+ new = versions(fromVer, toVer).first(includedVersionCount)
46
+ old = versions.select { |v| v < new.last }.first(pastVersionsToIgnore)
47
+
48
+ projectJQL(fromVer) + " AND issuetype=Bug AND affectedVersion in (#{versionsListJQL(new)}) AND affectedVersion not in (#{versionsListJQL(old)}) AND resolution is empty ORDER BY votes DESC, priority DESC, key DESC"
49
+ end
50
+
51
+ # URL for all issues resolved after +fromVer+ up to and including +toVer+.
52
+ def allissuesURL(fromVer=nil, toVer=nil)
53
+ JAC_URL + "/issues/?jql=#{CGI::escape(allissuesJQL(fromVer, toVer))}"
54
+ end
55
+
56
+ # URL for all Bugs resolved after +fromVer+ up to and including +toVer+.
57
+ def bugsURL(fromVer=nil, toVer=nil)
58
+ JAC_URL + "/issues/?jql=#{CGI::escape(bugsJQL(fromVer, toVer))}"
59
+ end
60
+
61
+ # URL for all features resolved after +fromVer+ up to and including +toVer+.
62
+ def featuresURL(fromVer=nil, toVer=nil)
63
+ JAC_URL + "/issues/?jql=#{CGI::escape(featuresJQL(fromVer, toVer))}"
64
+ end
65
+
66
+ # URL for all new, unresolved Bugs _introduced_ after +fromVer+ up to and including +toVer+. This means bugs reported against a version in the range, but not reported against an earlier version.
67
+ def recentbugsURL(fromVer=nil, toVer=nil)
68
+ JAC_URL + "/issues/?jql=#{CGI::escape(recentbugsJQL(fromVer, toVer))}"
69
+ end
70
+
71
+ def marketplaceJSON
72
+ if !@marketplaceJSON then
73
+ mpacKey = case key
74
+ when "jira-core", "jira-software" then
75
+ # mpac still only knows about 'jira'
76
+ "jira"
77
+ when "stash" then "bitbucket" # MPAC actually redirects stash to bitbucket, but be nice and do it here.
78
+ else
79
+ key
80
+ end
81
+ url = "https://marketplace.atlassian.com/rest/1.0/#{product_type}/#{mpacKey}"
82
+ begin
83
+ jsonStr = open(url).read
84
+ rescue OpenURI::HTTPError => error
85
+ if error.io.status[0] == "404" then
86
+ raise "No plugin with key '#{key}' found"
87
+ else
88
+ raise error
89
+ end
90
+ end
91
+ @marketplaceJSON = JSON.parse( jsonStr )
92
+ end
93
+ @marketplaceJSON
94
+ end
95
+
96
+ ## Find versions in a range, from +fromVer+ (exclusive) to +toVer+ (inclusive). If +toVer+ is omitted, all versions up to the latest are found. If +fromVer+ and +toVer+ are omitted, all versions are returned.
97
+ def versions(fromVer=nil, toVer=nil) # fromVer and toVer may be a string or a *Version
98
+ if (!fromVer && !toVer) then
99
+ allVersions
100
+ else
101
+ # allVersions is ordered most to least recent
102
+ # If 'fromVer' was unspecified, count from the end (allVersions.size = last = oldest)
103
+ fromIdx = fromVer ? allVersions.find_index { |v| v.version == fromVer.to_s } || ( raise "Couldn't find #{@key} fromVer #{fromVer}" ) : allVersions.size
104
+ # If toVer was unspecified, count from the beginning (0 = newest)
105
+ toIdx = toVer ? allVersions.find_index{ |v| v.version == toVer.to_s } || ( raise "Couldn't find #{@key} toVer #{toVer}" ) : 0
106
+ # fromIdx may be greater than toIdx, which the slice doesn't like, so get the max/min here
107
+ from = [fromIdx, toIdx].min
108
+ to = [fromIdx, toIdx].max
109
+ allVersions.slice(from, (to - from))
110
+ end
111
+ end
112
+
113
+ ## Find a specific version
114
+ def version(ver)
115
+ allVersions.find { |v| v.version == ver }
116
+ end
117
+
118
+
119
+ def allVersions
120
+ raise "Override me!"
121
+ end
122
+ def latest
123
+ allVersions.first
124
+ end
125
+
126
+ # Display all 'properties' of the app/plugin. These can be used as methods, e.g. 'jira.name' or 'plugin.summary'
127
+ def keys
128
+ marketplaceJSON.keys
129
+ end
130
+
131
+ def method_missing(name, *args, &block)
132
+ if keys and keys.member? name.to_s then
133
+ marketplaceJSON[name.to_s]
134
+ else
135
+ super
136
+ end
137
+ end
138
+
139
+ def respond_to_missing?(name, include_private = false)
140
+ keys.member? name.to_s || super
141
+ end
142
+
143
+ private
144
+
145
+ def jacKey
146
+ case @key
147
+ when "jira-core" then "JRA"
148
+ when "jira-software" then ["JRA", "JSW"]
149
+ when "confluence" then ["CONF", "CRA"]
150
+ when "gh" then"GHS"
151
+ when "stash" then "BSERV"
152
+ when "bitbucket" then "BSERV"
153
+ when "fisheye" then "FE"
154
+ when "com.pyxis.greenhopper.jira" then "JSW"
155
+ end
156
+ end
157
+
158
+ # "plugins" or "applications"
159
+ def product_type
160
+ raise "Override me!"
161
+ end
162
+
163
+
164
+ # Return a 'project in (...)' JQL clause.
165
+ def projectJQL(fromVer=nil, toVer=nil)
166
+ (jacKey.respond_to?(:each) ? "project in (#{jacKey.join(',')})" : "project=#{jacKey}")
167
+ end
168
+
169
+ # Return a comma-separated list of JAC version strings, given an Array of versions
170
+ def versionsListJQL(versions)
171
+ # Atlassian started appending ' Server' to JIRA version names after 7.1.6
172
+ if @key=~/jira/ then
173
+ old, new = versions.partition { |v| v < "7.1.6"}
174
+ (new.map { |v| "'#{v} Server'" } + old).join(", ")
175
+ else
176
+ versions.join(", ")
177
+ end
178
+ end
179
+
180
+ # JQL common between bugs and features
181
+ def templateJQL(fromVer=nil, toVer=nil)
182
+ vers = versionsListJQL(versions(fromVer, toVer))
183
+ projectJQL(fromVer, toVer) +
184
+ " AND fixVersion in (#{vers}) AND status in (Resolved, Closed, Soaking, \"Released to Server\") ORDER BY votes DESC, priority DESC, key DESC"
185
+ end
186
+ end
187
+
188
+ ## Represents a plugin, with information taken from https://marketplace.atlassian.com
189
+ class Plugin < AbstractProduct
190
+
191
+ def versionsJSON
192
+ marketplaceJSON["versions"]["versions"]
193
+ end
194
+ def product_type
195
+ "plugins"
196
+ end
197
+
198
+ def allVersions
199
+ versionsJSON.collect { |v| PluginVersion.new(v["version"], self) }
200
+ end
201
+
202
+ # A few plugins are tracked on JAC, so if asked for JQL, return their issue-tracker link.
203
+ def allissueJQL(fromVer=nil, toVer=nil)
204
+ links = versionsJSON.first["links"]
205
+ if links then
206
+ tracker = links.find { |l| l["rel"] == "issue-tracker" }
207
+ if tracker then
208
+ if tracker["href"] =~ /jira\.atlassian\.com/ then
209
+ templateJQL(fromVer, toVer)
210
+ else
211
+ nil
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ ## Represents an application on jira.atlassian.com / my.atlassian.com
219
+ class App < AbstractProduct
220
+ VALID_PRODUCTS=["jira-core", "jira-software", "confluence", "bitbucket", "stash", "fisheye", "crowd"]
221
+ def initialize(key)
222
+ if !VALID_PRODUCTS.member? key then
223
+ raise "Unknown product: #{key}. Use one of #{VALID_PRODUCTS.join(", ")}"
224
+ end
225
+ if key=="stash" then key="bitbucket"; end
226
+ super
227
+ end
228
+
229
+ def getjson(url)
230
+ open(url).read.gsub(/^downloads\(/, '').gsub(/\)$/, '')
231
+ end
232
+
233
+ def latestReleaseJSON
234
+ if !@latestReleaseJSON then
235
+
236
+ macKey = @key == "bitbucket" ? "stash" : @key # MAC still thinks it's 'stash'
237
+ url="https://my.atlassian.com/download/feeds/current/#{macKey}.json"
238
+ jsonStr = getjson(url)
239
+ @latestReleaseJSON = JSON.parse(jsonStr)
240
+ end
241
+ @latestReleaseJSON
242
+ end
243
+
244
+ def archivedReleaseJSON
245
+ if !@archivedReleaseJSON then
246
+ macKey = @key == "bitbucket" ? "stash" : @key # MAC still thinks it's 'stash'
247
+ url="https://my.atlassian.com/download/feeds/archived/#{macKey}.json"
248
+ jsonStr = getjson(url)
249
+ @archivedReleaseJSON = JSON.parse( jsonStr )
250
+ end
251
+ @archivedReleaseJSON
252
+ end
253
+
254
+ def versionsJSON
255
+ marketplaceJSON["versions"]
256
+ end
257
+
258
+ def allVersions
259
+ first=true
260
+ versionsJSON.collect { |v|
261
+ if first then
262
+ first=false
263
+ LatestAppVersion.new(v["version"], self)
264
+ else
265
+ ArchivedAppVersion.new(v["version"], self)
266
+ end
267
+ }
268
+ end
269
+
270
+ def product_type
271
+ "applications"
272
+ end
273
+ end
274
+
275
+ ## A plugin or app version
276
+ class AbstractVersion
277
+ include Comparable
278
+
279
+ attr_accessor :version
280
+ def initialize(versionName, parent)
281
+ @version = versionName
282
+ @parent = parent
283
+ end
284
+
285
+ def versionJSON
286
+ @parent.versionsJSON.find { |v| v["version"] == @version }
287
+ end
288
+
289
+ def releaseDate
290
+ DateTime.strptime(versionJSON["releaseDate"], '%Y-%m-%dT%H:%M:%S.%L%z') if versionJSON
291
+ end
292
+
293
+ def inspect
294
+ "#<#{self.class.name}:#{self.object_id} #{to_s}>"
295
+ end
296
+
297
+ def to_s
298
+ @version
299
+ end
300
+
301
+ def <=>(other_version)
302
+ # Confluence has a version with underscores (3.0.0_01) which Gem::Version doesn't like, so strip it
303
+ v1 = @version.gsub('_', '.')
304
+ v2 = other_version.to_s.gsub('_', '.')
305
+ begin
306
+ Gem::Version.new(v1) <=> Gem::Version.new(v2)
307
+ rescue ArgumentError => e
308
+ $stderr.puts e.message
309
+ end
310
+
311
+ end
312
+
313
+ def keys
314
+ versionJSON.keys
315
+ end
316
+
317
+ def method_missing(name, *args, &block)
318
+ if versionJSON and versionJSON.keys.member? name.to_s then
319
+ versionJSON[name.to_s]
320
+ else
321
+ super
322
+ end
323
+ end
324
+
325
+ def respond_to_missing?(name, include_private = false)
326
+ keys.member? name.to_s || super
327
+ end
328
+ end
329
+
330
+ class PluginVersion < AbstractVersion
331
+ # Some plugin release don't have release notes, in which case return nil
332
+ def relNotes
333
+ if versionJSON["releaseNotes"] then
334
+ versionJSON["releaseNotes"].scan(/(?<=href=")[^"]+elease\+[nN]otes/)&.first&.strip
335
+ end
336
+ end
337
+ end
338
+
339
+ class AppVersion < AbstractVersion
340
+ def releaseJSON
341
+ raise "Override me"
342
+ end
343
+
344
+ def relNotes
345
+ # RC releases don't have release notes, in which case return nil
346
+ if releaseJSON
347
+ releaseJSON["releaseNotes"]&.strip
348
+ end
349
+ end
350
+
351
+ def keys
352
+ # Combine versionJSON keys with releaseJSON keys. Note that Confluence 5.6 and earlier doesn't have releaseJSON.
353
+ releaseJSON ? releaseJSON.keys + super : super
354
+ end
355
+
356
+ def method_missing(name, *args, &block)
357
+ if releaseJSON and releaseJSON.keys.member? name.to_s then
358
+ releaseJSON[name.to_s]
359
+ else
360
+ super
361
+ end
362
+ end
363
+
364
+ def respond_to_missing?(name, include_private = false)
365
+ keys.member? name.to_s || super
366
+ end
367
+ end
368
+
369
+ class LatestAppVersion < AppVersion
370
+ def releaseJSON
371
+ @parent.latestReleaseJSON.select {|e|
372
+ url=e["zipUrl"]
373
+ @parent.key=="fisheye" ||
374
+ url =~ /.tar.gz$/ && url !~ /(war|cluster).tar.gz$/
375
+ }[0]
376
+ end
377
+ end
378
+ class ArchivedAppVersion < AppVersion
379
+ # Note: returns nil if that version wasn't available in the archive
380
+ def releaseJSON
381
+ @parent.archivedReleaseJSON.find { |v| v["version"] == @version }
382
+ end
383
+ end
384
+
385
+ end
386
+ # vim: set smartindent sw=4:
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: atlassian_app_versions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Jeff Turner
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Wraps the marketplace.atlassian.com and my.atlassian.com REST APIs to
98
+ obtain info about JIRA releases. See commented-out code near end for examples.
99
+ email:
100
+ - jeff@redradishtech.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - Guardfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - atlassian_app_versions.gemspec
113
+ - bin/console
114
+ - bin/setup
115
+ - lib/atlassian_app_versions.rb
116
+ homepage:
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.5.1
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Obtain info about Atlassian JIRA and other product releases.
140
+ test_files: []