rake-xpi 0.0.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: 4fbcc44fc0cbe55a24febb2258bf4a48b90c9d0d
4
+ data.tar.gz: 07946ac497e0a0859530b73e2bf0b0d86b20b90e
5
+ SHA512:
6
+ metadata.gz: 8cbf3067a6e13c0d09f06da122ac17fbb090ee8997535f5e5218072057cb9289419351ded35d49fd30e1c205129a6b46dd504a3f24149339a86c9f10a8d02733
7
+ data.tar.gz: 13058ade3c32bb5d02ac5035162a5c2c49ee1e0f0542a95fbc8a2c2d86bce9fb406acf2d174db85fdfd994a0f946ae3c68ce319fb3f86eb7e06c114f612764d0
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ #ruby=2.2
2
+ #ruby-gemset=zotero
3
+
4
+ source 'https://rubygems.org'
5
+
6
+ # Specify your gem's dependencies in gemspec
7
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,81 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rake-xpi (0.0.4)
5
+ aws-sdk
6
+ github_api
7
+ jwt
8
+ multipart-post
9
+ nokogiri
10
+ rake
11
+ recursive-open-struct
12
+ rest-client
13
+ rubyzip (>= 1.0.0)
14
+ zip-zip
15
+
16
+ GEM
17
+ remote: https://rubygems.org/
18
+ specs:
19
+ addressable (2.4.0)
20
+ aws-sdk (2.2.30)
21
+ aws-sdk-resources (= 2.2.30)
22
+ aws-sdk-core (2.2.30)
23
+ jmespath (~> 1.0)
24
+ aws-sdk-resources (2.2.30)
25
+ aws-sdk-core (= 2.2.30)
26
+ descendants_tracker (0.0.4)
27
+ thread_safe (~> 0.3, >= 0.3.1)
28
+ domain_name (0.5.20160310)
29
+ unf (>= 0.0.5, < 1.0.0)
30
+ faraday (0.9.2)
31
+ multipart-post (>= 1.2, < 3)
32
+ github_api (0.13.1)
33
+ addressable (~> 2.4.0)
34
+ descendants_tracker (~> 0.0.4)
35
+ faraday (~> 0.8, < 0.10)
36
+ hashie (>= 3.4)
37
+ multi_json (>= 1.7.5, < 2.0)
38
+ oauth2
39
+ hashie (3.4.3)
40
+ http-cookie (1.0.2)
41
+ domain_name (~> 0.5)
42
+ jmespath (1.1.3)
43
+ jwt (1.5.1)
44
+ mime-types (2.99.1)
45
+ mini_portile2 (2.0.0)
46
+ multi_json (1.11.2)
47
+ multi_xml (0.5.5)
48
+ multipart-post (2.0.0)
49
+ netrc (0.11.0)
50
+ nokogiri (1.6.7.2)
51
+ mini_portile2 (~> 2.0.0.rc2)
52
+ oauth2 (1.1.0)
53
+ faraday (>= 0.8, < 0.10)
54
+ jwt (~> 1.0, < 1.5.2)
55
+ multi_json (~> 1.3)
56
+ multi_xml (~> 0.5)
57
+ rack (>= 1.2, < 3)
58
+ rack (1.6.4)
59
+ rake (11.1.2)
60
+ recursive-open-struct (1.0.1)
61
+ rest-client (1.8.0)
62
+ http-cookie (>= 1.0.2, < 2.0)
63
+ mime-types (>= 1.16, < 3.0)
64
+ netrc (~> 0.7)
65
+ rubyzip (1.2.0)
66
+ thread_safe (0.3.5)
67
+ unf (0.1.4)
68
+ unf_ext
69
+ unf_ext (0.0.7.2)
70
+ zip-zip (0.3)
71
+ rubyzip (>= 1.0.0)
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ bundler (~> 1.3)
78
+ rake-xpi!
79
+
80
+ BUNDLED WITH
81
+ 1.11.2
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'pp'
5
+
6
+ task :default => :build
7
+
8
+ task :bump do
9
+ gemspec = []
10
+ bumped = false
11
+ IO.readlines('rake-xpi.gemspec').each{|line|
12
+ if line =~ /spec.version *= *'([0-9\.]+)'/
13
+ bumped = true
14
+ old = $1
15
+ new = old.split('.').collect{|n| Integer(n)}
16
+ new[-1] += 1
17
+ new = new.collect{|n| n.to_s}.join('.')
18
+ line = line.sub(old, new)
19
+ end
20
+ gemspec << line
21
+ }
22
+ gemspec = gemspec.join('')
23
+
24
+ File.open('rake-xpi.gemspec', 'w'){|f| f.write(gemspec) }
25
+ puts `git add rake-xpi.gemspec Gemfile Gemfile.lock`
26
+ end
27
+
28
+ task :publish do
29
+ version = nil
30
+ IO.readlines('rake-xpi.gemspec').each{|line|
31
+ version = $1 if line =~ /spec.version *= *'([0-9\.]+)'/
32
+ }
33
+ raise "No version found" unless version
34
+ sh "git add ."
35
+ sh "git commit -m #{version}"
36
+ sh "git tag #{version}"
37
+ Dir['pkg/*.gem'].each{|f| File.unlink(f)}
38
+ Rake::Task["build"].invoke
39
+ sh "gem push #{Dir['pkg/*.gem'].join(' ')}"
40
+ sh "git push"
41
+ end
data/lib/rake/xpi.rb ADDED
@@ -0,0 +1,370 @@
1
+ require 'aws-sdk'
2
+ require 'fileutils'
3
+ require 'jwt'
4
+ require 'nokogiri'
5
+ require 'open-uri'
6
+ require 'ostruct'
7
+ require 'rake'
8
+ require 'recursive-open-struct'
9
+ require 'rest-client'
10
+ require 'securerandom'
11
+ require 'socket'
12
+ require 'tempfile'
13
+ require 'uri'
14
+ require 'yaml'
15
+ require 'zip'
16
+
17
+ module Rake
18
+ module XPI
19
+ class Config
20
+ include Rake::DSL
21
+
22
+ def initialize()
23
+ @config = RecursiveOpenStruct.new(YAML::load_file('xpi.yml'), recurse_over_arrays: true)
24
+ @timestamp = Time.now.to_i.to_s
25
+
26
+ @config.to_h.keys.each{|key|
27
+ self.class.send(:define_method, key) { @config[key] }
28
+ }
29
+ end
30
+ def versioned_xpi(v=nil)
31
+ return File.basename(self.xpi, File.extname(self.xpi)) + '-' + (v || self.version) + File.extname(self.xpi)
32
+ end
33
+
34
+ def bump(level=nil)
35
+ r = release.split('.').collect{|n| Integer(n)}
36
+ r = case (level || 'patch').intern
37
+ when :major then [r[0] + 1, 0, 0]
38
+ when :minor then [r[0], r[1] + 1, 0]
39
+ when :patch then [r[0], r[1], r[2] + 1]
40
+ else raise "Unexpected release increase #{level.inspect}"
41
+ end
42
+ self.release = r.collect{|n| n.to_s}.join('.')
43
+ end
44
+
45
+ def id
46
+ return Nokogiri::XML(File.open('install.rdf')).at('//em:id').inner_text
47
+ end
48
+ def release
49
+ return Nokogiri::XML(File.open('install.rdf')).at('//em:version').inner_text
50
+ end
51
+ def release=(rel)
52
+ doc = Nokogiri::XML(File.open('install.rdf'))
53
+ doc.at('//em:version').content = rel
54
+ open('install.rdf', 'w'){|f| f.write(doc.to_xml)}
55
+ end
56
+
57
+ def version
58
+ b = "-#{branch}"
59
+ b = '' if b == '-master'
60
+ if release_build?
61
+ return release
62
+ elsif ENV['TRAVIS_BUILD_NUMBER']
63
+ return release + "-travis#{b}-#{ENV['TRAVIS_BUILD_NUMBER']}"
64
+ elsif ENV['CIRCLE_BUILD_NUM']
65
+ return release + "-circle#{b}-#{ENV['CIRCLE_BUILD_NUM']}"
66
+ else
67
+ return release + "-#{Socket.gethostname}#{b}-#{@timestamp}"
68
+ end
69
+ end
70
+
71
+ def update_rdf(link)
72
+ _id = self.id
73
+ _release = self.release
74
+ _changelog = self.changelog
75
+
76
+ update = Nokogiri::XML::Builder.new { |xml|
77
+ xml.RDF('xmlns:RDF'=>'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'xmlns:em' =>
78
+ 'http://www.mozilla.org/2004/em-rdf#') {
79
+ xml.parent.namespace = xml.parent.namespace_definitions.find{|ns|ns.prefix=='RDF'}
80
+ xml['RDF'].Description(about: "urn:mozilla:extension:#{_id}") {
81
+ xml['em'].updates {
82
+ xml['RDF'].Seq {
83
+ xml['RDF'].li {
84
+ xml['RDF'].Description {
85
+ xml['em'].version { xml.text _release }
86
+
87
+ Nokogiri::XML(open('install.rdf')).xpath('//em:targetApplication/xmlns:Description').each{|target|
88
+ xml['em'].targetApplication {
89
+ xml['RDF'].Description {
90
+ xml['em'].id { xml.text target.at('./em:id').inner_text }
91
+ xml['em'].minVersion { xml.text target.at('./em:minVersion').inner_text }
92
+ xml['em'].maxVersion { xml.text target.at('./em:maxVersion').inner_text }
93
+ xml['em'].updateLink { xml.text link }
94
+ xml['em'].updateInfoURL { xml.text _changelog }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ Tempfile.create('update_rdf') do |tmp|
106
+ tmp.write(update.to_xml)
107
+ tmp.close
108
+ yield tmp.path
109
+ end
110
+ end
111
+
112
+ def download(url, file)
113
+ puts "Downloading #{url} to #{file}..."
114
+ sh "curl -L #{url.shellescape} -o #{file.shellescape}"
115
+ end
116
+
117
+ def release_message
118
+ return "release: #{self.xpi} #{self.release}"
119
+ end
120
+
121
+ def pull_request
122
+ return ENV['TRAVIS_PULL_REQUEST'] if (ENV['TRAVIS_PULL_REQUEST'] || 'false') != 'false'
123
+ return ENV['CI_PULL_REQUESTS'] if (ENV['CI_PULL_REQUESTS'] || '') != ''
124
+ return nil
125
+ end
126
+
127
+ def branch
128
+ if @branch.nil?
129
+ if pull_request
130
+ @branch = 'pull-request-' + pull_request
131
+ elsif ENV['TRAVIS_BRANCH']
132
+ @branch = ENV['TRAVIS_BRANCH']
133
+ elsif ENV['CIRCLE_BRANCH']
134
+ @branch = ENV['CIRCLE_BRANCH']
135
+ else
136
+ @branch = `git rev-parse --abbrev-ref HEAD`.strip
137
+ end
138
+ end
139
+ return @branch
140
+ end
141
+
142
+ def release_build?
143
+ if @release_build.nil?
144
+ commitmsg = `git log -n 1 --pretty=oneline`.strip
145
+ commit = %w{CIRCLE_SHA1 TRAVIS_COMMIT}.collect{|key| ENV[key]}.compact.first
146
+ commit ||= 'local'
147
+
148
+ releasemsg = "#{commit} #{release_message}"
149
+
150
+ STDERR.puts "#{self.release}"
151
+ STDERR.puts " committed = #{commitmsg}"
152
+ STDERR.puts " release = #{releasemsg}"
153
+ STDERR.puts " branch = #{branch}"
154
+
155
+ @release_build = (commitmsg == releasemsg && branch == 'master')
156
+ end
157
+
158
+ return @release_build
159
+ end
160
+
161
+ def sign
162
+ return if ENV['SIGN'] == 'false'
163
+ return unless @config.amo && @config.amo.issuer && @config.amo.secret
164
+ issuer = ENV[@config.amo.issuer]
165
+ secret = ENV[@config.amo.secret]
166
+ return unless issuer && secret
167
+
168
+ token = lambda {
169
+ payload = {
170
+ jti: SecureRandom.base64,
171
+ iss: issuer,
172
+ iat: Time.now.utc.to_i,
173
+ exp: Time.now.utc.to_i + 60,
174
+ }
175
+ return JWT.encode(payload, secret, 'HS256')
176
+ }
177
+
178
+ duration = lambda{|secs|
179
+ secs = secs.to_i
180
+ mins = secs / 60
181
+ hours = mins / 60
182
+ days = hours / 24
183
+
184
+ if days > 0
185
+ "#{days} days and #{hours % 24} hours"
186
+ elsif hours > 0
187
+ "#{hours} hours and #{mins % 60} minutes"
188
+ elsif mins > 0
189
+ "#{mins} minutes and #{secs % 60} seconds"
190
+ elsif secs >= 0
191
+ "#{secs} seconds"
192
+ end
193
+ }
194
+
195
+ url = "https://addons.mozilla.org/api/v3/addons/#{self.id}/versions/#{self.version}/"
196
+
197
+ wait = nil
198
+ begin
199
+ Dir.mktmpdir{|dir|
200
+ tmp = File.join(dir, self.versioned_xpi)
201
+ FileUtils.cp(self.xpi, tmp)
202
+ puts "Submit #{tmp} to #{url} for signing"
203
+ RestClient.put(url, {upload: File.new(tmp)}, { 'Authorization' => "JWT #{token.call}", 'Content-Type' => 'multipart/form-data' })
204
+ }
205
+ wait = Time.now.to_i
206
+ sleep 10
207
+ rescue RestClient::Conflict
208
+ puts "#{self.xpi} already signed"
209
+ wait = Time.now.to_i
210
+ end
211
+
212
+ status = {}
213
+ (1..100).each{|attempt|
214
+ status = JSON.parse(RestClient.get(url, { 'Authorization' => "JWT #{token.call}"} ).to_s)
215
+ files = (status['files'] || []).length
216
+ signed = (files > 0 ? status['files'][0]['signed'] : false)
217
+ puts "attempt #{attempt} after #{duration.call(Time.now.to_i - wait)}, #{files} files, signed: #{signed}"
218
+ break if signed
219
+ sleep 5
220
+ }
221
+
222
+ raise "Unexpected response: #{status['files'].inspect}" if !status['files'] || status['files'].length != 1 || !status['files'][0]['download_url']
223
+ raise "Not signed: #{status['files'][0].inspect}" unless status['files'][0]['signed']
224
+
225
+ puts "\ngetting signed XPI from #{status['files'][0]['download_url']}"
226
+ File.open(self.xpi, 'wb'){|f|
227
+ f.write(RestClient.get(status['files'][0]['download_url'], { 'Authorization' => "JWT #{token.call}"} ).body)
228
+ }
229
+ end
230
+
231
+ def getxpis
232
+ return if ENV['OFFLINE'].to_s.downcase == 'true'
233
+ return unless @config.test && @config.test.xpis && @config.test.xpis.install
234
+
235
+ dir = File.expand_path(@config.test.xpis.install)
236
+ FileUtils.mkdir_p(dir)
237
+ installed = Dir["#{dir}/*.xpi"].collect{|f| File.basename(f) }
238
+
239
+ sources = (@config.test.xpis.download || []).collect{|s| resolvexpi(s) }
240
+
241
+ (installed - sources.collect{|s| s.xpi}).each{|xpi|
242
+ STDERR.puts "Removing #{xpi}"
243
+ File.unlink("#{dir}/#{xpi}")
244
+ }
245
+ sources.reject{|s| installed.include?(s.xpi) && s.url !~ /^file:/ }.each{|s|
246
+ # https://github.com/zotero/zotero/zipball/master for zotero master
247
+ if s.xpi =~ /(.*)-master-.*.xpi$/
248
+ src = $1
249
+ tgt = "#{dir}/#{s.xpi}"
250
+ STDERR.puts "Zipping #{s.xpi} to #{tgt}"
251
+ Dir.chdir(src){|path|
252
+ Zip::File.open(tgt, 'w') do |zipfile|
253
+ Dir["**/*"].sort.each{|file|
254
+ zipfile.add(file, file)
255
+ }
256
+ end
257
+ }
258
+ else
259
+ STDERR.puts "Downloading #{s.xpi}"
260
+ download(s.url, "#{dir}/#{s.xpi}")
261
+ end
262
+ }
263
+ end
264
+
265
+ def resolvexpi(source)
266
+ STDERR.puts "Resolving #{source}"
267
+
268
+ xpi = nil
269
+
270
+ if source =~ /update\.rdf$/
271
+ update_rdf = Nokogiri::XML(open(source))
272
+ update_rdf.remove_namespaces!
273
+ url = update_rdf.at('//updateLink').inner_text
274
+ elsif source =~ /^https:\/\/addons\.mozilla\.org\//
275
+ page = open(source).read
276
+ page = Nokogiri::HTML(page)
277
+ url = page.at_css('p.install-button').at_css('a')['href']
278
+
279
+ url = URI.join(source, url ).to_s if url !~ /^http/
280
+
281
+ return resolvexpi(url) if url =~ /\/contribute\/roadblock\//
282
+
283
+ # AMO uses redirects, so I can't write the file to the final name just yet
284
+ final_uri = nil
285
+ open(url) do |h|
286
+ final_uri = h.base_uri
287
+ end
288
+ url = final_uri.to_s
289
+ elsif source =~ /^https:\/\/github\.com\/zotero\/([^\/]+)\/zipball\/master$/
290
+ url = source
291
+ src = $1
292
+ Dir.chdir(src) {
293
+ rev = `git log -n 1 --pretty=format:"%h"`
294
+ xpi = "#{src}-master-#{rev}.xpi"
295
+ }
296
+ elsif source =~ /^file:/ || source =~ /\.xpi(\?|$)/
297
+ url = source
298
+ else
299
+ throw "Unsupported XPI source #{source}"
300
+ end
301
+
302
+ xpi ||= url.sub(/.*\//, '').sub(/\?.*$/, '')
303
+ STDERR.puts "Resolved to #{url}"
304
+ return OpenStruct.new(url: url, xpi: xpi)
305
+ end
306
+
307
+ end
308
+ end
309
+ end
310
+
311
+ XPI = Rake::XPI::Config.new
312
+ NODEBIN="node_modules/.bin"
313
+
314
+ task :default => XPI.xpi do
315
+ end
316
+
317
+ file XPI.xpi => XPI.files do |t|
318
+ STDERR.puts "Building #{t.name}"
319
+ Dir["*.xpi"].each{|f| File.unlink(f) }
320
+
321
+ Zip::File.open(t.name, 'w') do |zipfile|
322
+ t.sources.sort.each{|src|
323
+ case File.basename(src)
324
+ when 'install.rdf'
325
+ install_rdf = Nokogiri::XML(File.open(src))
326
+ install_rdf.at('//em:version').content = XPI.version
327
+ zipfile.get_output_stream(src){|f| install_rdf.write_xml_to f }
328
+ else
329
+ zipfile.add(src, src)
330
+ end
331
+ }
332
+ end
333
+
334
+ begin
335
+ XPI.sign
336
+ rescue => e
337
+ FileUtils.rm_f(XPI.xpi)
338
+ raise e
339
+ end
340
+ end
341
+
342
+ rule '.js' => '.pegjs' do |t|
343
+ sh "#{NODEBIN}/pegjs -e #{File.basename(t.source, File.extname(t.source))} #{t.source.shellescape} #{t.name.shellescape}"
344
+ end
345
+
346
+ task :npm do
347
+ sh "npm install --save coffee-script coffeelint pegjs"
348
+ end
349
+
350
+ rule '.js' => '.coffee' do |t|
351
+ sh "#{NODEBIN}/coffeelint #{t.source.shellescape}"
352
+ sh "#{NODEBIN}/coffee -bc #{t.source.shellescape}"
353
+ end
354
+
355
+ task :bump, :level do |t, args|
356
+ modified = `git ls-files -m`.split(/\n/).reject{|f| f == 'www' || f == 'wiki'}
357
+ throw "#{modified.length} modified files not checked in" unless modified.length == 0
358
+ XPI.bump(args[:level])
359
+
360
+ sh "git add install.rdf"
361
+ sh "git commit -m #{XPI.release_message.shellescape}"
362
+ sh "git tag #{XPI.release.shellescape}"
363
+ end
364
+
365
+ task :publish => XPI.xpi do
366
+ if !XPI.pull_request
367
+ STDERR.puts "Publishing #{XPI.release_build? ? 'release' : 'debug'} build #{XPI.versioned_xpi}"
368
+ STDERR.puts "Published to " + XPI.publish
369
+ end
370
+ end
@@ -0,0 +1,57 @@
1
+ #require 'aws-sdk'
2
+ #require 'fileutils'
3
+ #require 'jwt'
4
+ #require 'nokogiri'
5
+ #require 'open-uri'
6
+ #require 'ostruct'
7
+ #require 'rake'
8
+ #require 'recursive-open-struct'
9
+ #require 'rest-client'
10
+ #require 'securerandom'
11
+ #require 'socket'
12
+ #require 'tempfile'
13
+ #require 'uri'
14
+ #require 'yaml'
15
+ #require 'zip'
16
+
17
+ module Rake
18
+ module XPI
19
+ class Config
20
+ def publish
21
+ raise "Bintray publishing not configured" unless @config.bintray && @config.bintray.secret
22
+ STDERR.puts "Publishing #{self.versioned_xpi} to Bintray"
23
+ #RestClient.log = 'stdout'
24
+
25
+ secret = ENV[@config.bintray.secret]
26
+
27
+ client = RestClient::Resource.new('https://api.bintray.com', @config.bintray.user, secret)
28
+ content = client['content'][@config.bintray.user][@config.bintray.repo]
29
+
30
+ begin
31
+ client['packages'][@config.bintray.user][@config.bintray.repo][@config.bintray.package]['versions']['latest'].delete
32
+ rescue RestClient::ResourceNotFound
33
+ # that's OK
34
+ end
35
+
36
+ content[@config.bintray.package][self.version][self.versioned_xpi].put(File.new(self.xpi), {
37
+ content_type: 'application/x-xpinstall',
38
+ x_bintray_package: @config.bintray.package,
39
+ x_bintray_version: self.version,
40
+ x_bintray_publish: '1'
41
+ })
42
+
43
+ if release_build?
44
+ update_rdf("https://bintray.com/artifact/download/#{@config.bintray.user}/#{@config.bintray.repo}/#{@config.bintray.package}/#{self.version}/#{self.versioned_xpi}"){|update|
45
+ content[@config.repo.package]['update.rdf'].put(File.new(update), {
46
+ content_type: 'application/rdf+xml',
47
+ x_bintray_package: @config.repo.package,
48
+ x_bintray_version: 'latest',
49
+ x_bintray_publish: '1',
50
+ x_bintray_override: '1'
51
+ })
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,81 @@
1
+ require 'github_api'
2
+ #require 'aws-sdk'
3
+ #require 'fileutils'
4
+ #require 'jwt'
5
+ #require 'nokogiri'
6
+ #require 'open-uri'
7
+ #require 'ostruct'
8
+ #require 'rake'
9
+ #require 'recursive-open-struct'
10
+ #require 'rest-client'
11
+ #require 'securerandom'
12
+ #require 'socket'
13
+ #require 'tempfile'
14
+ #require 'uri'
15
+ #require 'yaml'
16
+ #require 'zip'
17
+
18
+ module Rake
19
+ module XPI
20
+ class Config
21
+ def get_stable_release(tag, prerelease)
22
+ release = @releases.list(@config.github.user, @config.github.repo).detect{|rel| rel.tag_name == tag }
23
+ return release if release
24
+
25
+ sha = `git rev-list --max-parents=0 HEAD`.split(/\n/).collect{|sha| sha.strip}.first
26
+ release = @releases.create(@config.github.user, @config.github.repo, {
27
+ tag_name: tag,
28
+ target_commitish: sha,
29
+ name: tag,
30
+ body: tag,
31
+ prerelease: prerelease
32
+ })
33
+ end
34
+
35
+ def publish
36
+ raise "Github publishing not configured" unless @config.github && @config.github.user && @config.github.token
37
+ token = ENV[@config.github.token]
38
+ raise "Github publishing not configured" unless token
39
+
40
+ @github = Github.new({oauth_token: token})
41
+ @releases = @github.repos.releases
42
+
43
+ release = nil
44
+ if release_build?
45
+ # create release and upload assets
46
+ release = @releases.create(@config.github.user, @config.github.repo, {
47
+ tag_name: self.release,
48
+ name: self.release,
49
+ body: self.release
50
+ })
51
+ else
52
+ release = get_stable_release('builds', true)
53
+ end
54
+
55
+ @releases.assets.upload(@config.github.user, @config.github.repo, release.id, self.xpi, {
56
+ name: self.versioned_xpi,
57
+ content_type: 'application/x-xpinstall'
58
+ })
59
+
60
+ download = "https://github.com/#{@config.github.user}/#{@config.github.repo}/releases/download/#{release.name}/#{self.versioned_xpi}"
61
+ if release_build?
62
+ release = get_stable_release('update.rdf', false)
63
+ # Remove any existing assets
64
+ @github.repos.releases.assets.list(@config.github.user, @config.github.repo, release.id){ |asset|
65
+ @github.repos.releases.assets.delete(@config.github.user, @config.github.repo, asset.id)
66
+ }
67
+
68
+ update_rdf(download){|update|
69
+ @releases.assets.upload(@config.github.user, @config.github.repo, release.id, update, {
70
+ name: 'update.rdf',
71
+ content_type: 'application/rdf+xml'
72
+ })
73
+ }
74
+ end
75
+
76
+ return download
77
+ end
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,83 @@
1
+ #require 'aws-sdk'
2
+ #require 'fileutils'
3
+ #require 'jwt'
4
+ #require 'nokogiri'
5
+ #require 'open-uri'
6
+ #require 'ostruct'
7
+ #require 'rake'
8
+ #require 'recursive-open-struct'
9
+ #require 'rest-client'
10
+ #require 'securerandom'
11
+ #require 'socket'
12
+ #require 'tempfile'
13
+ #require 'uri'
14
+ #require 'yaml'
15
+ #require 'zip'
16
+
17
+ module Rake
18
+ module XPI
19
+ class Config
20
+ def publish
21
+ raise "S3 publishing not configured" unless @config.s3 && @config.s3.id && @config.s3.secret
22
+ STDERR.puts "Publishing #{self.versioned_xpi} to S3"
23
+ id = ENV[@config.s3.id]
24
+ secret = ENV[@config.s3.secret]
25
+ return false unless id && secret
26
+
27
+ s3 = Aws::S3::Resource.new(region: @config.s3.region, credentials: Aws::Credentials.new(id, secret))
28
+ bucket = s3.bucket(@config.s3.bucket)
29
+
30
+ obj = bucket.object("#{release_build? ? @config.s3.prefix : 'builds'}/#{self.versioned_xpi}")
31
+ obj.upload_file(self.xpi, content_type: 'application/x-xpinstall')
32
+ if release_build?
33
+ update_rdf("https://s3.#{@config.s3.region}.amazonaws.com/#{@config.s3.bucket}/#{@config.s3.prefix}/#{self.versioned_xpi}"){|update|
34
+ obj = bucket.object("#{@config.s3.prefix}/update.rdf")
35
+ obj.upload_file(update, content_type: 'application/rdf+xml')
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ task :bucket, [:uploader, :id, :secret] do |t, args|
44
+ id = args[:id] || ENV[XPI.s3.id]
45
+ secret = args[:secret] || ENV[XPI.s3.secret]
46
+ uploader = args[:uploader]
47
+
48
+ s3 = Aws::S3::Resource.new(region: XPI.s3.region, credentials: Aws::Credentials.new(id, secret))
49
+ bucket = s3.bucket(XPI.s3.bucket)
50
+ bucket.create() unless bucket.exists?
51
+
52
+ bucket.policy.put(policy: {
53
+ "Version": "2012-10-17",
54
+ "Id": "XPI downloads",
55
+ "Statement": [
56
+ {
57
+ "Sid": "Stmt1435253907295",
58
+ "Effect": "Allow",
59
+ "Principal": { "AWS": uploader },
60
+ "Action": "s3:*",
61
+ "Resource": "arn:aws:s3:::#{XPI.s3.bucket}/*"
62
+ },
63
+ {
64
+ "Sid": "PublicRead",
65
+ "Effect": "Allow",
66
+ "Principal": "*",
67
+ "Action": "s3:GetObject",
68
+ "Resource": "arn:aws:s3:::#{XPI.s3.bucket}/*"
69
+ }
70
+ ]
71
+ }.to_json)
72
+
73
+ bucket.lifecycle.put(lifecycle_configuration: {
74
+ rules: [
75
+ {
76
+ status: "Enabled",
77
+ prefix: "builds/",
78
+ expiration: { days: 7 },
79
+ id: "cleanup-build"
80
+ }
81
+ ]
82
+ })
83
+ end
@@ -0,0 +1,81 @@
1
+ require 'net/sftp'
2
+ require 'nokogiri'
3
+ require 'shellwords'
4
+
5
+ module Rake
6
+ module XPI
7
+ class Config
8
+ include Rake::DSL
9
+
10
+ def publish
11
+ raise "Sourceforge publishing not configured" unless @config.sourceforge && @config.sourceforge.project && @config.sourceforge.user && @config.sourceforge.key
12
+
13
+ STDERR.puts "Publishing #{self.versioned_xpi} to sourceforge"
14
+
15
+ builds = 'builds'
16
+ download = "http://downloads.sourceforge.net/project/#{@config.sourceforge.project}/#{self.release_build? ? self.release : builds}/#{self.versioned_xpi}"
17
+ latest = nil
18
+ # assumes ssh keys set up properly
19
+ Net::SFTP.start('frs.sourceforge.net', @config.sourceforge.user) do |sftp|
20
+ root = "/home/frs/project/#{@config.sourceforge.project}"
21
+
22
+ mkdir = lambda do |dir|
23
+ dir = "#{root}/#{dir}" unless dir =~ /^\//
24
+ begin
25
+ sftp.mkdir!(dir)
26
+ rescue => e
27
+ STDERR.puts "#{dir} exists: #{e}"
28
+ end
29
+ end
30
+
31
+ if self.release_build?
32
+ mkdir.call('update')
33
+ update_rdf(download){|update|
34
+ sftp.upload!(update, "#{root}/update/update.rdf")
35
+ }
36
+ latest = self.release
37
+ else
38
+ begin
39
+ latest = Nokogiri::XML(sftp.download!("#{root}/update/update.rdf")).at('//em:version').inner_text
40
+ rescue => e
41
+ STDERR.puts "no existing release (#{e})"
42
+ end
43
+ end
44
+
45
+ # create builds dir
46
+ mkdir.call(builds)
47
+
48
+ # create release dir
49
+ dir = "#{root}/#{self.release_build? ? self.release : builds}"
50
+ begin
51
+ sftp.mkdir!(dir)
52
+ rescue
53
+ end
54
+ # put the XPI there
55
+ sftp.upload!(File.absolute_path(xpi), "#{dir}/#{self.versioned_xpi}")
56
+
57
+ # remove builds older than a week
58
+ cutoff = (Time.now - (7*24*60*60)).to_i
59
+ old = []
60
+ sftp.dir.foreach("#{root}/#{builds}") do |file|
61
+ old << file.longname if file.attributes.mtime < cutoff
62
+ end
63
+ old.each{|file|
64
+ sftp.remove(file)
65
+ }
66
+ end
67
+
68
+ if latest
69
+ # https://sourceforge.net/p/forge/documentation/Using%20the%20Release%20API/
70
+ RestClient.put(
71
+ "https://sourceforge.net/projects/#{@config.sourceforge.project}/files/#{latest}/#{self.versioned_xpi(latest)}",
72
+ "default=windows&default=mac&default=linux&default=bsd&default=solaris&default=others&api_key=#{ENV[@config.sourceforge.key]}",
73
+ {accept: :json}
74
+ )
75
+ end
76
+
77
+ return download
78
+ end
79
+ end
80
+ end
81
+ end
data/rake-xpi.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rake-xpi"
7
+ spec.version = '0.0.4'
8
+ spec.authors = ["Emiliano Heyns"]
9
+ spec.email = ["Emiliano.Heyns@iris-advies.com"]
10
+ spec.description = %q{rake helper to build XPI files}
11
+ spec.summary = %q{rake helper to build XPI files}
12
+ spec.homepage = "http://zotplus.github.io"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+ spec.required_ruby_version = '>= 2.2'
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+
23
+ spec.add_runtime_dependency 'aws-sdk'
24
+ spec.add_runtime_dependency 'github_api'
25
+ spec.add_runtime_dependency 'jwt'
26
+ spec.add_runtime_dependency 'multipart-post'
27
+ spec.add_runtime_dependency 'nokogiri'
28
+ spec.add_runtime_dependency 'rake', '>= 0', '>= 0'
29
+ spec.add_runtime_dependency 'recursive-open-struct'
30
+ spec.add_runtime_dependency 'rest-client'
31
+ spec.add_runtime_dependency 'rubyzip', '>= 1.0.0' # will load new rubyzip version
32
+ spec.add_runtime_dependency 'zip-zip' # will load compatibility for old rubyzip API.
33
+ end
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rake-xpi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Emiliano Heyns
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-29 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: github_api
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: jwt
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: multipart-post
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
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: nokogiri
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: recursive-open-struct
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rest-client
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubyzip
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 1.0.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 1.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: zip-zip
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: rake helper to build XPI files
168
+ email:
169
+ - Emiliano.Heyns@iris-advies.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - Gemfile
175
+ - Gemfile.lock
176
+ - Rakefile
177
+ - lib/rake/xpi.rb
178
+ - lib/rake/xpi/bintray.rb
179
+ - lib/rake/xpi/github.rb
180
+ - lib/rake/xpi/s3.rb
181
+ - lib/rake/xpi/sourceforge.rb
182
+ - rake-xpi.gemspec
183
+ homepage: http://zotplus.github.io
184
+ licenses:
185
+ - MIT
186
+ metadata: {}
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '2.2'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 2.5.0
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: rake helper to build XPI files
207
+ test_files: []