From 2a3b1eeef0fed89e372f4c34fba7cf99572f70fd Mon Sep 17 00:00:00 2001 From: AndriiMysko Date: Fri, 11 Dec 2020 11:58:56 +0200 Subject: [PATCH 1/4] Switch to using the vcs service --- Gemfile | 1 - Gemfile.lock | 1 - lib/travis/addons/github_status/task.rb | 368 ++++--------------- lib/travis/api.rb | 8 +- lib/travis/backends/base.rb | 2 +- lib/travis/backends/github.rb | 76 ---- lib/travis/backends/vcs.rb | 2 +- lib/travis/tasks.rb | 11 - spec/addons/email/mailer/build_spec.rb | 11 + spec/addons/github_check_status/task_spec.rb | 14 +- spec/addons/github_status/task_spec.rb | 179 +++------ spec/spec_helper.rb | 2 - 12 files changed, 143 insertions(+), 532 deletions(-) delete mode 100644 lib/travis/backends/github.rb diff --git a/Gemfile b/Gemfile index 0e667f20..fb015225 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,6 @@ gem 'keen' gem 'jemalloc', git: 'https://github.com/joshk/jemalloc-rb' -gem 'gh' gem 'aws-sdk' gem 'actionmailer' gem 'roadie' diff --git a/Gemfile.lock b/Gemfile.lock index 8cd9eb27..eeab7ba0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1197,7 +1197,6 @@ DEPENDENCIES faraday (~> 1.0) faraday_middleware foreman - gh guard guard-rspec intercom (~> 3.8.0) diff --git a/lib/travis/addons/github_status/task.rb b/lib/travis/addons/github_status/task.rb index 22294bbc..72eceeeb 100644 --- a/lib/travis/addons/github_status/task.rb +++ b/lib/travis/addons/github_status/task.rb @@ -1,4 +1,3 @@ -require 'gh' module Travis module Addons module GithubStatus @@ -33,312 +32,69 @@ class Task < Travis::Task REDIS_PREFIX = 'travis-tasks:github-status:'.freeze private - def url - client.create_status_url(repository[:vcs_id], sha) - end - def process(timeout) - return process_vcs if repository[:vcs_type] != 'GithubRepository'.freeze - users_tried = [] - status = :not_ok - - message = %W[ - type=github_status - build=#{build[:id]} - repo=#{repository[:slug]} - state=#{state} - commit=#{sha} - tokens_count=#{tokens.size} - installation_id=#{installation_id} - ].join(' ') - - if !installation_id.nil? && process_via_github_app - info("#{message} processed_with=#{client.name}") - return - end - - while !tokens.empty? and status != :ok do - username, token = tokens.shift - unless token - error("#{message} username=#{username} token=#{token.to_s}") - next - end - - status, details = process_with_token(username, token) - if status == :ok - info("#{message} username=#{username} processed_with=user_token token=#{token[0,3]}...") - return - elsif status == :skipped - info "#{message} message=\"Token for #{username} failed within the last hour. Skipping\"" - next - end - - # we can't post any more status to this commit, so there's - # no point in trying further - return if details[:status].to_i == 422 - - users_tried << username - error(%W[ - type=github_status - build=#{build[:id]} - repo=#{repository[:slug]} - error=not_updated - commit=#{sha} - username=#{username} - url=#{url} - github_response=#{details[:status]} - processed_with=user_token - users_tried=#{users_tried} - last_token_tried="#{token.to_s[0,3]}..." - rate_limit=#{rate_limit_info details[:response_headers]} - github_request_id=#{github_request_id details[:response_headers]} - ].join(' ')) - end - - error("#{message} message=\"All known tokens failed to update status\"") - end - - def process_vcs - client.create_status( - process_via_gh_apps: false, - id: repository[:vcs_id], - type: repository[:vcs_type], - ref: sha, - pr_number: payload[:pull_request] && payload[:pull_request][:number], - payload: status_payload - ) - end - - def tokens - params.fetch(:tokens) { { '' => params[:token] } } - end - - def process_with_token(username, token) - Travis.redis_pool.with do |redis| - if redis.exists(errored_token_key(token)) - return [:skipped, {}] - end - end - - value = authenticated(token) do - client.create_status( - process_via_gh_apps: false, - id: repository[:vcs_id], - type: repository[:vcs_type], - ref: sha, - payload: status_payload - ) - end - [:ok, value] - rescue GH::Error(:response_status => 401), - GH::Error(:response_status => 403), - GH::Error(:response_status => 404), - GH::Error(:response_status => 422) => e - mark_token(username, token) if e.info[:response_status] == 403 - error(%W[ - type=github_status - build=#{build[:id]} - repo=#{repository[:slug]} - state=#{state} - commit=#{sha} - username=#{username} - response_status=#{e.info[:response_status]} - reason=#{ERROR_REASONS.fetch(Integer(e.info[:response_status]))} - processed_with=user_token - body=#{e.info[:response_body]} - last_token_tried="#{token.to_s[0,3]}..." - rate_limit=#{rate_limit_info e.info[:response_headers]} - github_request_id=#{github_request_id e.info[:response_headers]} - ].join(' ')) - - return [ - :error, - { - status: e.info[:response_status], - reason: e.info[:response_body], - response_headers: e.info[:response_headers] - } - ] - rescue GH::Error => e - message = %W[ - type=github_status - build=#{build[:id]} - repo=#{repository[:slug]} - error=not_updated - commit=#{sha} - url=#{url} - response_status=#{e.info[:response_status]} - message=#{e.message} - processed_with=user_token - body=#{e.info[:response_body]} - last_token_tried="#{token.to_s[0,3]}..." - rate_limit=#{rate_limit_info e.info[:response_headers]} - github_request_id=#{github_request_id e.info[:response_headers]} - ].join(' ') - error(message) - raise message - end - - def process_via_github_app - response = client.create_status( - process_via_gh_apps: true, - id: repository[:vcs_id], - type: repository[:vcs_type], - ref: sha, - payload: status_payload.to_json - ) - - if response.success? - info(%W[ - type=github_status - repo=#{repository[:slug]} - response_status=#{response.status} - processed_with=#{client.name} - ].join(' ')) - return true - end - - status_int = Integer(response.status) - case status_int - when 401, 403, 404, 422 - error(%W[ - type=github_status - build=#{build[:id]} - repo=#{repository[:slug]} - state=#{state} - commit=#{sha} - installation_id=#{installation_id} - response_status=#{status_int} - reason=#{ERROR_REASONS.fetch(status_int)} - processed_with=#{client.name} - body=#{response.body} - ].join(' ')) - return nil - else - message = %W[ - type=github_status - build=#{build[:id]} - repo=#{repository[:slug]} - error=not_updated - commit=#{sha} - url=#{url} - response_status=#{status_int} - processed_with=#{client.name} - body=#{response.body} - ].join(' ') - error(message) - raise message - end - end - - def target_url - with_utm("#{Travis.config.http_host}/#{Travis::Addons::Util::Helpers.vcs_prefix(repository[:vcs_type])}/#{repository[:vcs_slug] || repository[:slug]}/builds/#{build[:id]}", :github_status) - end - - def status_payload - { - state: state, - description: description, - target_url: target_url, - context: context - } - end - - def client - @client ||= Travis::Api.backend(repository[:vcs_id], repository[:vcs_type], installation_id: installation_id) - end - - def installation_id - params.fetch(:installation, nil) - end - - def sha - pull_request? ? request[:head_commit] : commit[:sha] - end - - def context - build_type = pull_request? ? "pr" : "push" - "continuous-integration/travis-ci/#{build_type}" - end - - def state - STATES[build[:state]] - end - - def description - DESCRIPTIONS[state] - end - - def authenticated(token, &block) - GH.with(gh_no_tokencheck_stack.build(http_options(token)), &block) - end - - def gh_no_tokencheck_stack - return @gh_no_tokencheck_stack if @gh_no_tokencheck_stack - @gh_no_tokencheck_stack = ::GH::Stack.new do - use ::GH::Instrumentation - use ::GH::Parallel - use ::GH::Pagination - use ::GH::LinkFollower - use ::GH::MergeCommit - use ::GH::LazyLoader - use ::GH::Normalizer - use ::GH::CustomLimit - use ::GH::Remote - end - - @gh_no_tokencheck_stack.options.merge! ::GH::DefaultStack.options - @gh_no_tokencheck_stack - end - - def http_options(token) - super().merge(token: token, headers: headers, ssl: (Travis.config.github.ssl || {}).to_hash.compact) - end - - def headers - { - "Accept" => "application/vnd.github.v3+json" - } - end - - def rate_limit_info(headers) - return {error: "headers were nil"} unless headers - - unless rate_limit_headers_complete? headers - return {error: "response headers did not contain rate limit information"} - end - - { - limit: headers["x-ratelimit-limit"].to_i, - remaining: headers["x-ratelimit-remaining"].to_i, - next_limit_reset_in: headers["x-ratelimit-reset"].to_i - Time.now.to_i - } - end - - def rate_limit_headers_complete?(headers) - !headers.nil? && - !headers["x-ratelimit-limit" ].to_s.empty? && - !headers["x-ratelimit-remaining"].to_s.empty? && - !headers["x-ratelimit-reset" ].to_s.empty? - end - - def github_request_id(headers) - if headers.respond_to? :[] - headers["x-github-request-id"] - end - end - - def errored_token_key(token) - token_hash = Digest::SHA256.hexdigest(token) - REDIS_PREFIX + "errored_tokens:#{token_hash}" - end - - def mark_token(login, token) - info "message=\"A request with token belonging to #{login} failed. Will skip using this token for 1 hour.\"" - Travis.redis_pool.with do |redis| - redis.set errored_token_key(token), "", ex: 60*60 # an hour - end - end + def url + client.create_status_url(repository[:vcs_id], sha) + end + + def process(_timeout) + client.create_status( + id: repository[:vcs_id], + type: repository[:vcs_type], + ref: sha, + pr_number: payload[:pull_request] && payload[:pull_request][:number], + payload: status_payload + ) + + message = %W[ + type=github_status + build=#{build[:id]} + repo=#{repository[:slug]} + state=#{state} + commit=#{sha} + installation_id=#{installation_id} + ].join(' ') + + info("#{message} processed_with=#{client.name}") + end + + def target_url + with_utm("#{Travis.config.http_host}/#{Travis::Addons::Util::Helpers.vcs_prefix(repository[:vcs_type])}/#{repository[:vcs_slug] || repository[:slug]}/builds/#{build[:id]}", :github_status) + end + + def status_payload + { + state: state, + description: description, + target_url: target_url, + context: context + } + end + + def client + @client ||= Travis::Api.backend(repository[:vcs_id], repository[:vcs_type], installation_id: installation_id) + end + + def installation_id + params.fetch(:installation, nil) + end + + def sha + pull_request? ? request[:head_commit] : commit[:sha] + end + + def context + build_type = pull_request? ? "pr" : "push" + "continuous-integration/travis-ci/#{build_type}" + end + + def state + STATES[build[:state]] + end + + def description + DESCRIPTIONS[state] + end end end end diff --git a/lib/travis/api.rb b/lib/travis/api.rb index 931de97b..4a581ea4 100644 --- a/lib/travis/api.rb +++ b/lib/travis/api.rb @@ -1,5 +1,4 @@ require 'travis/backends/base' -require 'travis/backends/github' require 'travis/backends/vcs' module Travis @@ -7,12 +6,7 @@ module Api extend self def backend(vcs_id, vcs_type, installation_id: nil) - if Travis::Rollout.matches?(:vcs, id: vcs_id) || !vcs_type.match(/Github/) - Travis::Backends::Vcs.new - else - Travis::Backends::Github.new(installation_id) - end + Travis::Backends::Vcs.new end - end end diff --git a/lib/travis/backends/base.rb b/lib/travis/backends/base.rb index f83ce519..c8a33239 100644 --- a/lib/travis/backends/base.rb +++ b/lib/travis/backends/base.rb @@ -17,7 +17,7 @@ def check_runs(id:, type:, ref:, check_run_name:) raise NotImplementedError end - def create_status(process_via_gh_apps:, id:, type:, ref:, payload:) + def create_status(id:, type:, ref:, payload:) raise NotImplementedError end diff --git a/lib/travis/backends/github.rb b/lib/travis/backends/github.rb deleted file mode 100644 index 0c8e5397..00000000 --- a/lib/travis/backends/github.rb +++ /dev/null @@ -1,76 +0,0 @@ -require 'metriks' -require 'travis/github_apps' - -module Travis - module Backends - class Github < Travis::Backends::Base - def initialize(installation_id) - @installation_id = installation_id - end - - def name - 'github_apps' - end - - def create_check_run(id:, type:, payload:) - count_request - github_apps.post_with_app("/repositories/#{id}/check-runs", payload) - end - - def update_check_run(id:, type:, check_run_id:, payload:) - count_request - github_apps.patch_with_app("/repositories/#{id}/check-runs/#{check_run_id}", payload) - end - - def check_runs(id:, type:, ref:, check_run_name:) - path = "/repositories/#{id}/commits/#{ref}/check-runs?check_name=#{URI.encode(check_run_name)}&filter=all" - count_request - github_apps.get_with_app(path) - end - - def create_status(process_via_gh_apps:, id:, type:, ref:, payload:) - url = "/repositories/#{id}/statuses/#{ref}" - - count_request - if process_via_gh_apps - github_apps.post_with_app(url, payload) - else - GH.post(url, payload) - end - end - - def file_url(id:, type:, slug:, branch:, file:) - "#{Travis.config.github.url}/#{slug}/blob/#{branch}/#{file}" - end - - def branch_url(id:, type:, slug:, branch:) - "#{Travis.config.github.url}/#{slug}/tree/#{branch}" - end - - def create_check_run_url(id) - "#{GH.api_host}/repositories/#{id}/check-runs" - end - - def create_status_url(id, ref) - "#{GH.api_host}/repositories/#{id}/statuses/#{ref}" - end - - private - - def count_request - ::Metriks.meter("travis.github_api.requests").mark - end - - def github_apps - @github_apps ||= Travis::GithubApps.new( - @installation_id, - apps_id: Travis.config.github_apps.id, - private_pem: Travis.config.github_apps.private_pem, - redis: Travis.config.redis.to_h, - debug: Travis.config.github_apps.debug, - accept_header: 'application/vnd.github.antiope-preview+json' - ) - end - end - end -end diff --git a/lib/travis/backends/vcs.rb b/lib/travis/backends/vcs.rb index 1be10e80..7dc87022 100644 --- a/lib/travis/backends/vcs.rb +++ b/lib/travis/backends/vcs.rb @@ -20,7 +20,7 @@ def check_runs(id:, type:, ref:, check_run_name:) client.get("/repos/#{CGI::escape(id)}/checks", vcs_type: type, commit: ref, check_run_name: check_run_name) end - def create_status(process_via_gh_apps:, id:, type:, ref:, payload:, pr_number:) + def create_status(id:, type:, ref:, payload:, pr_number:) client.post("/repos/#{CGI::escape(id)}/status", vcs_type: type, commit: ref, payload: payload, pr_number: pr_number) end diff --git a/lib/travis/tasks.rb b/lib/travis/tasks.rb index 5ec9ecd8..9bbb87cb 100644 --- a/lib/travis/tasks.rb +++ b/lib/travis/tasks.rb @@ -1,7 +1,6 @@ $:.unshift(File.expand_path('..', File.dirname(__FILE__))) require 'bundler/setup' -require 'gh' require 'roadie' require 'ostruct' require 'travis/exceptions' @@ -61,16 +60,6 @@ def call(worker, msg, queue) c.redis = { url: url, namespace: config[:namespace], size: config[:pool_size] } end -GH.set( - client_id: Travis.config.oauth2.try(:client_id), - client_secret: Travis.config.oauth2.try(:client_secret), - origin: Travis.config.host, - api_url: Travis.config.github.api_url, - ssl: Travis.config.ssl.to_h.merge(Travis.config.github.ssl || {}).to_h.compact, - formatter: Travis.config.github_status.formatter, - user_agent: "Travis-CI GH/#{GH::VERSION}" -) - module Roadie def self.app @_config ||= OpenStruct.new(roadie: OpenStruct.new(enabled: true, provider: nil, after_inlining: nil)) diff --git a/spec/addons/email/mailer/build_spec.rb b/spec/addons/email/mailer/build_spec.rb index d8f68281..dda25284 100644 --- a/spec/addons/email/mailer/build_spec.rb +++ b/spec/addons/email/mailer/build_spec.rb @@ -8,6 +8,15 @@ let(:recipients) { ['owner@example.com', 'committer@example.com', 'author@example.com'] } let(:broadcasts) { [{ message: 'message', category: 'announcement' }] } let(:email) { described_class.finished_email(data, recipients, broadcasts) } + let(:vcs_client) { Travis::Backends::VcsClient.new } + + let(:conn) { + Faraday.new do |builder| + builder.adapter :test do |stub| + stub.get('/repos/549743/urls/branch?branch=master&vcs_type=GithubRepository') { |env| [200, {}, '{ "url": "https://github.com/svenfuchs/minimal/tree/master" }'] } + end + end + } before :each do Travis::Addons::Email.setup @@ -17,6 +26,8 @@ Travis.config.build_email_footer = true Travis.config.email = {} Travis.config.assets = {} + Travis::Backends::Vcs.any_instance.stubs(:client).returns(vcs_client) + vcs_client.stubs(:client).returns(conn) end describe 'finished build email notification' do diff --git a/spec/addons/github_check_status/task_spec.rb b/spec/addons/github_check_status/task_spec.rb index 3ae5e945..cef19c06 100644 --- a/spec/addons/github_check_status/task_spec.rb +++ b/spec/addons/github_check_status/task_spec.rb @@ -9,7 +9,7 @@ let(:subject) { Travis::Addons::GithubCheckStatus::Task.new(payload, installation: installation_id) } let(:payload) { Marshal.load(Marshal.dump(TASK_PAYLOAD)) } let(:io) { StringIO.new } - let(:gh_apps) { Travis::GithubApps.new installation_id } + let(:vcs_client) { Travis::Backends::VcsClient.new } let(:installation_id) { '12345' } let(:slug) { 'svenfuchs/minimal' } @@ -21,7 +21,7 @@ builder.adapter :test do |stub| stub.post("app/installations/12345/access_tokens") { |env| [201, {}, "{\"token\":\"github_apps_access_token\",\"expires_at\":\"2018-04-03T20:52:14Z\"}"] } stub.post("/repositories/549743/check-runs") { |env| [201, {}, check_run_response(response_data)] } - stub.get("/repositories/549743/commits/#{sha}/check-runs?check_name=Travis+CI+-+Branch&filter=all") { |env| [200, {}, check_run_list_response(response_data)] } + stub.get("/repos/549743/checks?check_run_name=Travis+CI+-+Branch&commit=#{sha}&vcs_type=GithubRepository") { |env| [200, {}, check_run_list_response(response_data)] } stub.patch("/repositories/549743/check-runs/1") { |env| [200, {}, check_run_response(response_data)] } end end @@ -32,8 +32,8 @@ end it 'makes expected API calls' do - Travis::Backends::Github.any_instance.expects(:github_apps).times(1).returns(gh_apps) - gh_apps.expects(:github_api_conn).times(2).returns(conn) + Travis::Backends::Vcs.any_instance.stubs(:client).returns(vcs_client) + vcs_client.stubs(:client).returns(conn) subject.run end @@ -44,15 +44,15 @@ builder.adapter :test do |stub| stub.post("app/installations/12345/access_tokens") { |env| [201, {}, "{\"token\":\"github_apps_access_token\",\"expires_at\":\"2018-04-03T20:52:14Z\"}"] } stub.post("/repositories/549743/check-runs") { |env| [201, {}, check_run_response(response_data)] } - stub.get("/repositories/549743/commits/#{sha}/check-runs?check_name=Travis+CI+-+Branch&filter=all") { |env| [403, {}, check_run_list_response(response_data)] } + stub.get("/repos/549743/checks?check_run_name=Travis+CI+-+Branch&commit=#{sha}&vcs_type=GithubRepository") { |env| [403, {}, check_run_list_response(response_data)] } stub.patch("/repositories/549743/check-runs/1") { |env| [200, {}, check_run_response(response_data)] } end end } it 'makes expected API calls' do - Travis::Backends::Github.any_instance.expects(:github_apps).times(1).returns(gh_apps) - gh_apps.expects(:github_api_conn).times(2).returns(conn) + Travis::Backends::Vcs.any_instance.stubs(:client).returns(vcs_client) + vcs_client.stubs(:client).returns(conn) subject.run end end diff --git a/spec/addons/github_status/task_spec.rb b/spec/addons/github_status/task_spec.rb index cc8d95c1..a46a26bf 100644 --- a/spec/addons/github_status/task_spec.rb +++ b/spec/addons/github_status/task_spec.rb @@ -11,7 +11,6 @@ let(:target_url) { 'https://travis-ci.org/github/svenfuchs/minimal/builds/1?utm_source=github_status&utm_medium=notification' } let(:payload) { Marshal.load(Marshal.dump(TASK_PAYLOAD)) } let(:io) { StringIO.new } - let(:gh_apps) { stub('github_apps') } let(:installation_id) { '12345' } let(:rate_limit_data) { {"x-ratelimit-limit" => "60", "x-ratelimit-remaining" => "59", "x-ratelimit-reset" => (Time.now.to_i + 2000).to_s} } let(:no_tokencheck_stack) { instance.send :gh_no_tokencheck_stack } @@ -22,22 +21,26 @@ def redis before do Travis.logger = Logger.new(io) - tokens.each do |t| - Redis.new(url: Travis.config.redis.url).del(Travis::Addons::GithubStatus::Task::REDIS_PREFIX + "errored_tokens:" + token_hash(t)) - end end def run instance.run end - def token_hash(token) - Digest::SHA256.hexdigest(token) - end - it 'posts status info for a created build' do payload["build"]["state"] = 'created' - GH.expects(:post).with(url, state: 'pending', description: 'The Travis CI build is in progress', target_url: target_url, context: 'continuous-integration/travis-ci/push').returns({}) + Travis::Backends::Vcs.any_instance.expects(:create_status).with( + id: payload['repository']['vcs_id'], + type: payload['repository']['vcs_type'], + ref: '62aae5f70ceee39123ef', + pr_number: payload['pull_request'] && payload['pull_request']['number'], + payload: { + state: 'pending', + description: 'The Travis CI build is in progress', + target_url: target_url, + context: 'continuous-integration/travis-ci/push' + } + ) run expect(io.string).to include('processed_with=') @@ -45,131 +48,69 @@ def token_hash(token) it 'posts status info for a passed build' do payload["build"]["state"] = 'passed' - GH.expects(:post).with(url, state: 'success', description: 'The Travis CI build passed', target_url: target_url, context: 'continuous-integration/travis-ci/push').returns({}) + Travis::Backends::Vcs.any_instance.expects(:create_status).with( + id: payload['repository']['vcs_id'], + type: payload['repository']['vcs_type'], + ref: '62aae5f70ceee39123ef', + pr_number: payload['pull_request'] && payload['pull_request']['number'], + payload: { + state: 'success', + description: 'The Travis CI build passed', + target_url: target_url, + context: 'continuous-integration/travis-ci/push' + } + ) run end it 'posts status info for a failed build' do payload["build"]["state"] = 'failed' - GH.expects(:post).with(url, state: 'failure', description: 'The Travis CI build failed', target_url: target_url, context: 'continuous-integration/travis-ci/push').returns({}) + Travis::Backends::Vcs.any_instance.expects(:create_status).with( + id: payload['repository']['vcs_id'], + type: payload['repository']['vcs_type'], + ref: '62aae5f70ceee39123ef', + pr_number: payload['pull_request'] && payload['pull_request']['number'], + payload: { + state: 'failure', + description: 'The Travis CI build failed', + target_url: target_url, + context: 'continuous-integration/travis-ci/push' + } + ) run end it 'posts status info for a errored build' do payload['build']["state"] = 'errored' - GH.expects(:post).with(url, state: 'error', description: 'The Travis CI build could not complete due to an error', target_url: target_url, context: 'continuous-integration/travis-ci/push').returns({}) + Travis::Backends::Vcs.any_instance.expects(:create_status).with( + id: payload['repository']['vcs_id'], + type: payload['repository']['vcs_type'], + ref: '62aae5f70ceee39123ef', + pr_number: payload['pull_request'] && payload['pull_request']['number'], + payload: { + state: 'error', + description: 'The Travis CI build could not complete due to an error', + target_url: target_url, + context: 'continuous-integration/travis-ci/push' + } + ) run end it 'posts status info for a canceled build' do payload["build"]["state"] = 'canceled' - GH.expects(:post).with(url, state: 'error', description: 'The Travis CI build could not complete due to an error', target_url: target_url, context: 'continuous-integration/travis-ci/push').returns({}) + Travis::Backends::Vcs.any_instance.expects(:create_status).with( + id: payload['repository']['vcs_id'], + type: payload['repository']['vcs_type'], + ref: '62aae5f70ceee39123ef', + pr_number: payload['pull_request'] && payload['pull_request']['number'], + payload: { + state: 'error', + description: 'The Travis CI build could not complete due to an error', + target_url: target_url, + context: 'continuous-integration/travis-ci/push' + } + ) run end - - it 'authenticates using the token passed into the task' do - GH.expects(:with).with(instance_of(GH::Instrumentation)).returns({}) - run - end - - it 'authenticates using the next token if the first token failed' do - error = { response_status: 403, response_headers: rate_limit_data } - GH.stubs(:post).raises(GH::Error.new('failed', nil, error)) - instrumentation = GH::Instrumentation.new - no_tokencheck_stack.expects(:build).with() { |hash| hash[:token] == '12345'}.returns(instrumentation) - no_tokencheck_stack.expects(:build).with() { |hash| hash[:token] == '67890'}.returns(instrumentation) - run - end - - it 'accepts a single token using the legacy payload' do - GH.expects(:with).with(instance_of(GH::Instrumentation)).returns({}) - subject.new(payload, token: '12345').run - end - - it 'does not raise if a 422 error was returned by GH' do - error = { response_status: 422, response_headers: rate_limit_data } - GH.stubs(:post).raises(GH::Error.new('failed', nil, error)) - expect { - run - }.not_to raise_error - expect(io.string).to include('response_status=422') - expect(io.string).to include('reason=maximum_number_of_statuses') - end - - it 'does not raise if a 403 error was returned by GH and marks the token invalid' do - error = { response_status: 403, response_headers: rate_limit_data } - GH.stubs(:post).raises(GH::Error.new('failed', nil, error)) - expect { - run - }.not_to raise_error - expect(io.string).to match /A request with token belonging to svenfuchs failed\./ - expect(io.string).to include('response_status=403') - expect(io.string).to include('reason=incorrect_auth_or_suspended_acct') - expect(redis.exists(Travis::Addons::GithubStatus::Task::REDIS_PREFIX + 'errored_tokens:' + token_hash('12345'))).to be true - end - - it 'does not raise if a 404 error was returned by GH' do - error = { response_status: 404, response_headers: rate_limit_data } - GH.stubs(:post).raises(GH::Error.new('failed', nil, error)) - expect { - run - }.not_to raise_error - expect(io.string).to include('response_status=404') - expect(io.string).to include('reason=repo_not_found_or_incorrect_auth') - expect(io.string).to include('users_tried=') - end - - context "a user token has been invalidated" do - before do - tokens.each do |token| - redis.set(Travis::Addons::GithubStatus::Task::REDIS_PREFIX + 'errored_tokens:' + token_hash(token), "") - end - end - - after do - tokens.each do |token| - redis.del(Travis::Addons::GithubStatus::Task::REDIS_PREFIX + 'errored_tokens:' + token_hash(token)) - end - end - - it "skips using the token" do - expect { run }.not_to raise_error - expect(io.string).to match /Token for svenfuchs failed/ - end - end - - describe 'logging' do - it 'warns about a failed request' do - GH.stubs(:post).raises(GH::Error.new(nil, nil, {response_headers: rate_limit_data})) - expect { - run - }.to raise_error RuntimeError - expect(io.string).to include('error=not_updated') - expect(io.string).to include('message=GH request failed') - expect(io.string).to include('rate_limit=') - end - - it "doesn't raise an error with bad credentials" do - error = { response_status: 401, response_headers: rate_limit_data } - GH.stubs(:post).raises(GH::Error.new('failed', nil, error)) - expect { - run - }.to_not raise_error - end - end - - context 'with a github apps installation id' do - let(:params) { { installation: installation_id } } - let :response do - stub(success?: true, status: 201) - end - - it 'processes via github apps' do - Travis::Backends::Github.any_instance.stubs(:github_apps).returns(gh_apps) - gh_apps.expects(:post_with_app) - .with(url, instance.send(:status_payload).to_json) - .returns(response) - run - end - end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7bb0bed4..b3cb1890 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,7 +14,6 @@ ActionMailer::Base.delivery_method = :test require 'mocha/api' -require 'gh' require 'capybara' include Mocha::API @@ -31,7 +30,6 @@ c.before :each do Travis.config.oauth2 ||= {} Travis.config.oauth2.scope = 'public_repo,user' - GH.reset end end From 7b56800b17f0aeabc4665773f44483ea39414a8d Mon Sep 17 00:00:00 2001 From: AndriiMysko Date: Wed, 23 Dec 2020 14:41:34 +0200 Subject: [PATCH 2/4] Debug --- lib/travis/addons/github_status/task.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/travis/addons/github_status/task.rb b/lib/travis/addons/github_status/task.rb index 72eceeeb..5aa53c26 100644 --- a/lib/travis/addons/github_status/task.rb +++ b/lib/travis/addons/github_status/task.rb @@ -38,6 +38,9 @@ def url end def process(_timeout) + pp client + pp payload + client.create_status( id: repository[:vcs_id], type: repository[:vcs_type], From aa9ed7ba2f062459bc4c1d60123746e5302382a7 Mon Sep 17 00:00:00 2001 From: AndriiMysko Date: Wed, 23 Dec 2020 15:21:03 +0200 Subject: [PATCH 3/4] Debug --- lib/travis/addons/github_check_status/task.rb | 4 ++++ lib/travis/addons/github_status/task.rb | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/travis/addons/github_check_status/task.rb b/lib/travis/addons/github_check_status/task.rb index 9564ac40..7e0153c6 100644 --- a/lib/travis/addons/github_check_status/task.rb +++ b/lib/travis/addons/github_check_status/task.rb @@ -13,6 +13,10 @@ def process(timeout) check_run = check_runs(sha).select { |check_run| check_run["external_id"] == build[:id].to_s }.first + pp "type=github_check_status build=#{build[:id]} repo=#{repository[:slug]} state=#{build[:state]} installation_id=#{installation_id} sha=#{sha}" + pp client + pp check_run + if check_run response = client.update_check_run(id: repository[:vcs_id], type: repository[:vcs_type], check_run_id: check_run["id"], payload: check_status_payload.to_json) else diff --git a/lib/travis/addons/github_status/task.rb b/lib/travis/addons/github_status/task.rb index 5aa53c26..72eceeeb 100644 --- a/lib/travis/addons/github_status/task.rb +++ b/lib/travis/addons/github_status/task.rb @@ -38,9 +38,6 @@ def url end def process(_timeout) - pp client - pp payload - client.create_status( id: repository[:vcs_id], type: repository[:vcs_type], From 9299cec64adc7c5bda5ea6b36136f7c7b164dbe1 Mon Sep 17 00:00:00 2001 From: AndriiMysko Date: Wed, 23 Dec 2020 17:39:27 +0200 Subject: [PATCH 4/4] Revert debug --- lib/travis/addons/github_check_status/task.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/travis/addons/github_check_status/task.rb b/lib/travis/addons/github_check_status/task.rb index 7e0153c6..9564ac40 100644 --- a/lib/travis/addons/github_check_status/task.rb +++ b/lib/travis/addons/github_check_status/task.rb @@ -13,10 +13,6 @@ def process(timeout) check_run = check_runs(sha).select { |check_run| check_run["external_id"] == build[:id].to_s }.first - pp "type=github_check_status build=#{build[:id]} repo=#{repository[:slug]} state=#{build[:state]} installation_id=#{installation_id} sha=#{sha}" - pp client - pp check_run - if check_run response = client.update_check_run(id: repository[:vcs_id], type: repository[:vcs_type], check_run_id: check_run["id"], payload: check_status_payload.to_json) else