Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move from service hooks to webhooks #818

Merged
merged 12 commits into from Sep 26, 2018
1 change: 1 addition & 0 deletions lib/travis/api/v3.rb
Expand Up @@ -28,6 +28,7 @@ def location(env)
ServerError = Error .create(status: 500)
NotFound = ClientError .create(:resource, status: 404, template: '%s not found (or insufficient access)')

AdminAccessRequired = ClientError .create('admin access to this repo required', status: 403)
AlreadySyncing = ClientError .create('sync already in progress', status: 409)
BuildAlreadyRunning = ClientError .create('build already running, cannot restart', status: 409)
BuildNotCancelable = ClientError .create('build is not running, cannot cancel', status: 409)
Expand Down
91 changes: 66 additions & 25 deletions lib/travis/api/v3/github.rb
Expand Up @@ -2,20 +2,26 @@

module Travis::API::V3
class GitHub
def self.config
@config ||= Travis::Config.load
end

EVENTS = %i(push pull_request issue_comment public member create delete repository)

DEFAULT_OPTIONS = {
client_id: Travis.config.oauth2.try(:client_id),
client_secret: Travis.config.oauth2.try(:client_secret),
scopes: Travis.config.oauth2.try(:scope).to_s.split(?,),
client_id: config.oauth2.try(:client_id),
client_secret: config.oauth2.try(:client_secret),
scopes: config.oauth2.try(:scope).to_s.split(?,),
user_agent: "Travis-API/3 Travis-CI/0.0.1 GH/#{GH::VERSION}",
origin: Travis.config.host,
api_url: Travis.config.github.api_url,
web_url: Travis.config.github.api_url.gsub(%r{\A(https?://)(?:api\.)?([^/]+)(?:/.*)?\Z}, '\1\2'),
ssl: Travis.config.ssl.to_h.merge(Travis.config.github.ssl || {}).compact
origin: config.host,
api_url: config.github.api_url,
web_url: config.github.api_url.gsub(%r{\A(https?://)(?:api\.)?([^/]+)(?:/.*)?\Z}, '\1\2'),
ssl: config.ssl.to_h.merge(config.github.ssl || {}).compact
}
private_constant :DEFAULT_OPTIONS

EVENTS = %i(push pull_request issue_comment public member create delete repository)
private_constant :EVENTS
HOOKS_URL = "repos/%s/hooks"
private_constant :HOOKS_URL

def self.client_config
{
Expand All @@ -37,26 +43,14 @@ def initialize(user = nil, token = nil)
@gh = GH.with(token: token, **DEFAULT_OPTIONS)
end

def set_hook(repository, flag)
hooks_url = "repos/#{repository.slug}/hooks"
payload = {
name: 'travis'.freeze,
events: EVENTS,
active: flag,
config: { domain: Travis.config.service_hook_url || '' }
}

if hook = gh[hooks_url].detect { |hook| hook['name'.freeze] == 'travis'.freeze }
gh.patch(hook['_links'.freeze]['self'.freeze]['href'.freeze], payload)
else
gh.post(hooks_url, payload)
end
def set_hook(repo, active)
set_webhook(repo, active)
deactivate_service_hook(repo)
end

def upload_key(repository)
keys_path = "repos/#{repository.slug}/keys"
key = gh[keys_path].
detect { |e| e['key'] == repository.key.encoded_public_key }
key = gh[keys_path].detect { |e| e['key'] == repository.key.encoded_public_key }

unless key
gh.post keys_path, {
Expand All @@ -66,5 +60,52 @@ def upload_key(repository)
}
end
end

private

def set_webhook(repo, active)
payload = {
name: 'web'.freeze,
events: EVENTS,
active: active,
config: { url: Travis.config.service_hook_url || '' }
}
if url = webhook_url?(repo)
info("Updating webhook repo=%s active=%s" % [repo.slug, active])
gh.patch(url, payload)
else
hooks_url = HOOKS_URL % [repo.slug]
info("Creating webhook repo=%s active=%s" % [repo.slug, active])
gh.post(hooks_url, payload)
end
end

def deactivate_service_hook(repo)
if url = service_hook_url?(repo)
info("Deactivating service hook repo=%s" % [repo.slug])
# Have to update events here too, to avoid old hooks failing validation
gh.patch(url, { events: EVENTS, active: false })
end
end

def service_hook_url?(repo)
if hook = hooks(repo).detect { |h| h['name'] == 'travis' }
hook.dig('_links', 'self', 'href')
end
end

def webhook_url?(repo)
if hook = hooks(repo).detect { |h| h['name'] == 'web' && h.dig('config', 'url') == Travis.config.service_hook_url }
hook.dig('_links', 'self', 'href')
end
end

def hooks(repo)
gh[HOOKS_URL % [repo.slug]]
end

def info(msg)
Travis.logger.info(msg)
end
end
end
7 changes: 4 additions & 3 deletions lib/travis/github.rb
@@ -1,8 +1,5 @@
require 'gh'
require 'core_ext/hash/compact'
require 'travis/github/education'
require 'travis/github/oauth'
require 'travis/github/services'

module Travis
module Github
Expand All @@ -23,5 +20,9 @@ def authenticated(user, &block)
GH.with(:token => user.github_oauth_token, &block)
end
end

require 'travis/github/education'
require 'travis/github/oauth'
require 'travis/github/services'
end
end
60 changes: 13 additions & 47 deletions lib/travis/github/services/set_hook.rb
Expand Up @@ -2,65 +2,31 @@
require 'travis/services/base'

module Travis
module API; end # Load-order issue
require 'travis/api/v3/github'

module Github
module Services
class SetHook < Travis::Services::Base
EVENTS = %i(push pull_request issue_comment public member create delete repository)

register :github_set_hook

def run
Github.authenticated(current_user) do
update
end
v3_github.set_hook(repo, active?)
end

private

def repo
@repo ||= run_service(:find_repo, id: params[:id])
end

def active?
params[:active]
end

def hook
@hook ||= find || create
end

def update
GH.patch(hook_url, payload) unless hook['active'] == active?
end

def find
GH[hooks_url].detect { |hook| hook['name'] == 'travis' && hook['config']['domain'] == domain }
end

def create
GH.post(hooks_url, payload)
end

def payload
{
:name => 'travis',
:events => EVENTS,
:active => active?,
:config => { :user => current_user.login, :token => current_user.tokens.first.token, :domain => domain }
}
end

def hooks_url
"repos/#{repo.slug}/hooks"
end
def active?
params[:active]
end

def hook_url
hook['_links']['self']['href']
end
def v3_github
@v3_github ||= Travis::API::V3::GitHub.new(current_user, current_user.github_oauth_token)
end

def domain
Travis.config.service_hook_url || ''
end
def repo
@repo ||= run_service(:find_repo, id: params[:id])
end
end
end
end
Expand Down
61 changes: 0 additions & 61 deletions lib/travis/testing/payloads.rb
Expand Up @@ -138,67 +138,6 @@
"created":true
}),


:hook_inactive => %({
"last_response": {
"status": "ok",
"message": "",
"code": 200
},
"config": {
"domain": "staging.travis-ci.org",
"user": "svenfuchs",
"token": "token"
},
"created_at": "2011-09-18T10:49:06Z",
"events": [
"push",
"pull_request",
"issue_comment",
"public",
"member"
],
"active": false,
"updated_at": "2012-08-09T09:32:42Z",
"name": "travis",
"_links": {
"self": {
"href": "https://api.github.com/repos/svenfuchs/minimal/hooks/77103"
}
},
"id": 77103
}),

:hook_active => %({
"last_response": {
"status": "ok",
"message": "",
"code": 200
},
"config": {
"domain": "staging.travis-ci.org",
"user": "svenfuchs",
"token": "token"
},
"created_at": "2011-09-18T10:49:06Z",
"events": [
"push",
"pull_request",
"issue_comment",
"public",
"member"
],
"active": true,
"updated_at": "2012-08-09T09:32:42Z",
"name": "travis",
"_links": {
"self": {
"href": "https://api.github.com/repos/svenfuchs/minimal/hooks/77103"
}
},
"id": 77103
}),

:oauth => {
"uid" => "234423",
"user_info" => {
Expand Down
13 changes: 7 additions & 6 deletions spec/integration/v2/hooks_spec.rb
@@ -1,4 +1,5 @@
require 'travis/testing/payloads'
require 'travis/api/v3/github'

describe 'Hooks', set_app: true do
before(:each) do
Expand All @@ -21,20 +22,20 @@

let :payload do
{
:name => 'travis',
:events => Travis::Github::Services::SetHook::EVENTS,
:name => 'web',
:events => Travis::API::V3::GitHub::EVENTS,
:active => true,
:config => { :user => user.login, :token => user.tokens.first.token, :domain => 'listener.travis-ci.org' }
:config => { url: 'notify.travis-ci.org' }
}
end

before(:each) do
Travis.config.service_hook_url = 'listener.travis-ci.org'
Travis.config.service_hook_url = 'notify.travis-ci.org'
stub_request(:get, "https://api.github.com/repos/#{repo.slug}/hooks?per_page=100").to_return(status: 200, body: '[]')
stub_request(:post, "https://api.github.com/repos/#{repo.slug}/hooks")
end

it 'sets the hook' do
GH.stubs(:[]).returns([])
GH.expects(:post).with(target, payload).returns(GH.load(PAYLOADS[:github][:hook_active]))
response = put 'hooks', { hook: { id: hook.id, active: 'true' } }, headers
repo.reload.active?.should == true
response.should be_successful
Expand Down
60 changes: 0 additions & 60 deletions spec/support/payloads.rb
Expand Up @@ -483,66 +483,6 @@
}
}),

'hook_inactive' => %({
"last_response": {
"status": "ok",
"message": "",
"code": 200
},
"config": {
"domain": "staging.travis-ci.org",
"user": "svenfuchs",
"token": "token"
},
"created_at": "2011-09-18T10:49:06Z",
"events": [
"push",
"pull_request",
"issue_comment",
"public",
"member"
],
"active": false,
"updated_at": "2012-08-09T09:32:42Z",
"name": "travis",
"_links": {
"self": {
"href": "https://api.github.com/repos/svenfuchs/minimal/hooks/77103"
}
},
"id": 77103
}),

'hook_active' => %({
"last_response": {
"status": "ok",
"message": "",
"code": 200
},
"config": {
"domain": "staging.travis-ci.org",
"user": "svenfuchs",
"token": "token"
},
"created_at": "2011-09-18T10:49:06Z",
"events": [
"push",
"pull_request",
"issue_comment",
"public",
"member"
],
"active": true,
"updated_at": "2012-08-09T09:32:42Z",
"name": "travis",
"_links": {
"self": {
"href": "https://api.github.com/repos/svenfuchs/minimal/hooks/77103"
}
},
"id": 77103
}),

'rkh' => %({
"user": {
"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4",
Expand Down