Skip to content

Commit

Permalink
Add TravisBranchMonitor
Browse files Browse the repository at this point in the history
Worker that is in charge of monitoring Travis for build_failures, and
will create BuildFailure records and send messages to gitter as needed.
  • Loading branch information
NickLaMuro committed Mar 18, 2020
1 parent 69ceb27 commit bb6cf63
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 0 deletions.
98 changes: 98 additions & 0 deletions app/workers/travis_branch_monitor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
require 'travis'

class TravisBranchMonitor
include Sidekiq::Worker
sidekiq_options :queue => :miq_bot, :retry => false

include Sidetiq::Schedulable
recurrence { hourly.minute_of_hour(0, 15, 30, 45) }

include SidekiqWorkerMixin

class << self
private

# For this class, sometimes the repo needs to be mapped to a specific
# gitter room, so a hash is required.
#
# This override allows for doing this in the config
#
# travis_branch_monitor:
# included_repos:
# ManageIQ/manageiq-ui-classic: ManageIQ/ui
# ManageIQ/manageiq-gems-pending: ManageIQ/core
# ManageIQ/manageiq:
# ManageIQ/miq_bot:
#
# Which you are allowed to leave the value empty, and the key will be used
# where appropriate (not used in this class).
#
# The result from the above for this method will then be:
#
# [
# [
# "ManageIQ/manageiq-ui-classic",
# "ManageIQ/manageiq-gems-pending",
# "ManageIQ/manageiq",
# "ManageIQ/miq_bot"
# ],
# []
# ]
#
def included_and_excluded_repos
super # just used for error handling...

[
settings.included_repos.try(:to_h).try(:stringify_keys).try(:keys),
settings.excluded_repos.try(:to_h).try(:stringify_keys).try(:keys)
]
end
end

def perform
if !first_unique_worker?
logger.info("#{self.class} is already running, skipping")
else
process_repos
end
end

def process_repos
enabled_repos.each do |repo|
process_repo(repo)
end
end

def process_repo(repo)
# repo.regular_branch_names.each do |branch|
# end

# TODO: Handle this for all release branches
process_branch(repo, 'master')
end

def process_branch(repo, branch)
branch_record = repo.regular_branches.where(:name => branch).first

# If we already have a failure record, call notify with that record
return branch_record.notify_of_failure if branch_record.previously_failing?

# otherwise, check if any builds exist with a failures, and if so, update
# the branch_record to add the `travis_build_failure_id`.
v3_client = TravisV3Client.new(:repo => Travis::Repository.find(repo.name))
branch_builds = v3_client.repo_branch_builds(branch)

if branch_builds.first.failed?
first_failure = find_first_recent_failure(branch_builds)
branch_record.update(:travis_build_failure_id => first_failure.id)

branch_record.notify_of_failure
end
end

private

def find_first_recent_failure(builds)
builds.take_while(&:failed?).last
end
end
69 changes: 69 additions & 0 deletions spec/workers/travis_branch_monitor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
describe TravisBranchMonitor do
include IncludedReposConfigMethods

describe ".included_and_excluded_repos (private)" do
it "builds the list from a hash of only keys" do
stub_settings included_repos_keys_only
expected = %w[ManageIQ/manageiq ManageIQ/miq_bot]

expect(described_class.send(:included_and_excluded_repos)).to eq([expected, nil])
end

it "builds the list from a hash of keys with values" do
stub_settings included_repos_keys_and_values
expected = %w[ManageIQ/manageiq-ui-classic ManageIQ/manageiq-gems-pending]

expect(described_class.send(:included_and_excluded_repos)).to eq([expected, nil])
end

it "builds the list from a mixed hash with keys and some values" do
stub_settings included_repos_mixed_keys_with_some_values
expected = %w[
ManageIQ/manageiq-ui-classic
ManageIQ/manageiq-gems-pending
ManageIQ/manageiq
ManageIQ/miq_bot
]

expect(described_class.send(:included_and_excluded_repos)).to eq([expected, nil])
end
end

describe "#find_first_recent_failure (private)" do
def passed(build_id)
build = Travis::Client::Build.new(nil, build_id)
allow(build).to receive(:inspect_info).and_return("Foo/foo##{build_id}")
build.tap { |b| b.update_attributes(:state => "passed") }
end

def failed(build_id)
build = Travis::Client::Build.new(nil, build_id)
allow(build).to receive(:inspect_info).and_return("Foo/foo##{build_id}")
build.tap { |b| b.update_attributes(:state => "failed") }
end

it "returns earliest failure" do
earliest_failure = failed(2)
builds = [
failed(4),
failed(3),
earliest_failure,
passed(1)
]

expect(subject.send(:find_first_recent_failure, builds)).to eq(earliest_failure)
end

it "returns nil if the first build has passed" do
builds = [
passed(5),
failed(4),
failed(3),
failed(2),
passed(1)
]

expect(subject.send(:find_first_recent_failure, builds)).to eq(nil)
end
end
end

0 comments on commit bb6cf63

Please sign in to comment.