Skip to content

Commit

Permalink
Merge branch 'rubygems-webhook'
Browse files Browse the repository at this point in the history
* rubygems-webhook:
  move updater script logic to class
  support rubygems.org web hooks
  rubygems api key in sample config
  • Loading branch information
zapnap committed May 6, 2015
2 parents 526d2fb + 29820af commit 3334e45
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 73 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ gem 'syntax'
gem 'json'
gem 'rake'
gem 'asciidoctor'
gem 'version_sorter'
gem 'yard', :git => 'git://github.com/lsegal/yard', :branch => "frameless"
gem 'yard-rails'
gem 'yard-kramdown'
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ GEM
atomic
tilt (1.4.1)
tzinfo (0.3.37)
version_sorter (2.0.0)
yard-kramdown (0.0.1)
yard-rails (0.3.0)
yard
Expand Down Expand Up @@ -92,6 +93,7 @@ DEPENDENCIES
sinatra (>= 1.3)
sqlite3
syntax
version_sorter
yard!
yard-kramdown
yard-rails
Expand Down
54 changes: 38 additions & 16 deletions app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
require 'extensions'
require 'scm_router'
require 'scm_checkout'
require 'gem_updater'
require 'gems_router'
require 'featured_router'
require 'stdlib_router'
require 'recent_store'

require 'digest/sha2'
require 'rack/etag'
require 'version_sorter'

class Hash; alias blank? empty? end
class NilClass; def blank?; true end end
Expand Down Expand Up @@ -81,7 +84,7 @@ def self.load_gems_adapter
opts = adapter_options
contents.each do |line|
name, *versions = *line.split(/\s+/)
opts[:libraries][name] = versions.map do |v|
opts[:libraries][name] = VersionSorter.sort(versions).map do |v|
ver, platform = *v.split(',')
lib = LibraryVersion.new(name, ver, nil, :remote_gem)
lib.platform = platform
Expand Down Expand Up @@ -254,22 +257,41 @@ def shorten_commit_link(commit)

# Checkout and post commit hooks

post_all '/checkout', '/projects/update' do
begin
if params[:payload] # backwards compatibility
payload = JSON.parse(params[:payload])
url = payload['repository']['url']
elsif request.media_type.match(/json/)
payload = JSON.parse(request.body.read || '{}')
payload = payload['payload'] if payload.keys.include?('payload')
url = payload['repository']['url']
else
url = params[:url]
commit = params[:commit]
commit = nil if commit == ''
end
post '/checkout/rubygems' do
data = JSON.parse(request.body.read || '{}')

authorization = Digest::SHA2.hexdigest(data['name'] + data['version'] + settings.rubygems)
if env['HTTP_AUTHORIZATION'] != authorization
log.error "rubygems unauthorized: #{env['HTTP_AUTHORIZATION']}"
error 401
end

url = (url || '').sub(%r{^http://}, 'git://')
update_rubygems(data)
end

def update_rubygems(data={})
gem = GemUpdater.new(self, data['name'], data['version'])
gem.flush_cache
gem.register
"OK"
end

post_all '/checkout', '/checkout/github', '/projects/update' do
if request.media_type.match(/json/)
data = JSON.parse(request.body.read || '{}')
update_github(data)
elsif params[:payload] # legacy
update_github(params[:payload])
else
data = { :url => params[:url], :commit => params[:commit] }
data[:commit] = nil if data[:commit] == ''
update_github(data)
end
end

def update_github(data={})
begin
url = (data[:url] || '').sub(%r{^http://}, 'git://')
commit ||= nil

if url =~ %r{github\.com/([^/]+)/([^/]+)}
Expand Down
4 changes: 4 additions & 0 deletions config/config.yaml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
# Whether or not disk caching is enabled. Defaults to false
# caching: false

# If you want to enable Rubygems.org gem push notifications, uncomment the
# following line and add your API key:
# rubygems: YOUR_API_KEY

# If you have Airbrake, uncomment the following line and add your API key:
# airbrake: YOUR_API_KEY

Expand Down
90 changes: 90 additions & 0 deletions lib/gem_updater.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
require_relative 'cache'
require 'rubygems'
require 'yard'

class GemVersion
attr_accessor :name, :version, :platform

def initialize(name, version, platform)
@name, @version, @platform = name.to_s, version.to_s, platform.to_s
end

def to_s
platform == "ruby" ? version : [version,platform].join(',')
end
end

class GemUpdater
include YARD::Server

attr_accessor :gem, :settings, :app

class << self
def fetch_remote_gems
libs = {}
if Gem::VERSION < '2.0'
Gem::SpecFetcher.fetcher.list(true).values.flatten(1).each do |info|
(libs[info[0]] ||= []) << GemVersion.new(*info)
end
else # RubyGems 2.x API
Gem::SpecFetcher.fetcher.available_specs(:released).first.values.flatten(1).each do |tuple|
(libs[tuple.name] ||= []) << GemVersion.new(tuple.name, tuple.version, tuple.platform)
end
end

libs
end

def update_remote_gems
libs = fetch_remote_gems
changed_gems = {}
File.readlines(REMOTE_GEMS_FILE).each do |line|
name, rest = *line.split(/\s+/, 2)
changed_gems[name] = rest
end if File.exist?(REMOTE_GEMS_FILE)

File.open(REMOTE_GEMS_FILE, 'w') do |file|
libs.each do |name, versions|
line = pick_best_versions(versions).join(' ')
changed_gems.delete(name) if changed_gems[name] && changed_gems[name].strip == line.strip
file.puts("#{name} #{line}")
end
end

changed_gems.keys.each do |gem_name|
flush_cache(gem_name)
end

changed_gems
end

def pick_best_versions(versions)
seen = {}
uniqversions = []
versions.each do |ver|
uniqversions |= [ver.version]
(seen[ver.version] ||= []).send(ver.platform == "ruby" ? :unshift : :push, ver)
end
uniqversions.map {|v| seen[v].first }
end

def flush_cache(gem_name)
Cache.invalidate("/gems", "/gems/~#{gem_name[0, 1]}", "/gems/#{gem_name}")
end
end

def initialize(app, name, version, platform='ruby')
self.settings = app.settings
self.app = app
self.gem = GemVersion.new(name, version, platform)
end

def register
settings.gems_adapter.add_library(LibraryVersion.new(gem.name, gem.version, nil, :remote_gem))
end

# TODO: improve this cache invalidation to be version specific
def flush_cache
self.class.flush_cache(name)
end
end
59 changes: 2 additions & 57 deletions scripts/update_remote_gems.rb
Original file line number Diff line number Diff line change
@@ -1,62 +1,7 @@
#!/bin/env ruby
require 'rubygems'
require_relative '../init'

class GemVersion
attr_accessor :name, :version, :platform

def initialize(name, version, platform)
@name, @version, @platform = name.to_s, version.to_s, platform.to_s
end

def to_s
platform == "ruby" ? version : [version,platform].join(',')
end
end

def pick_best_versions(versions)
seen = {}
uniqversions = []
versions.each do |ver|
uniqversions |= [ver.version]
(seen[ver.version] ||= []).send(ver.platform == "ruby" ? :unshift : :push, ver)
end
uniqversions.map {|v| seen[v].first }
end

libs = {}
if Gem::VERSION < '2.0'
Gem::SpecFetcher.fetcher.list(true).values.flatten(1).each do |info|
(libs[info[0]] ||= []) << GemVersion.new(*info)
end
else # RubyGems 2.x API
Gem::SpecFetcher.fetcher.available_specs(:released).first.values.flatten(1).each do |tuple|
(libs[tuple.name] ||= []) << GemVersion.new(tuple.name, tuple.version, tuple.platform)
end
end

# Keep track of updated gems
changed_gems = {}
File.readlines(REMOTE_GEMS_FILE).each do |line|
name, rest = *line.split(/\s+/, 2)
changed_gems[name] = rest
end if File.exist?(REMOTE_GEMS_FILE)

File.open(REMOTE_GEMS_FILE, 'w') do |file|
libs.each do |k, v|
line = pick_best_versions(v).join(' ')
changed_gems.delete(k) if changed_gems[k] && changed_gems[k].strip == line.strip
file.puts("#{k} #{line}")
end
end

# Clear cache for gem frames page with new gems
# TODO: improve this cache invalidation to be version specific
changed_gems.keys.each do |gem_name|
Cache.invalidate "/gems/~#{gem_name[0,1]}", "/gems/#{gem_name}/",
"/list/gems/#{gem_name}/"
end
require_relative '../lib/gem_updater'

changed_gems = GemUpdater.update_remote_gems
if changed_gems.size > 0
puts ">> Updated #{changed_gems.size} gems:"
puts changed_gems.keys.join(', ')
Expand Down

0 comments on commit 3334e45

Please sign in to comment.