Skip to content

Commit 5d2cf6b

Browse files
Merge pull request #55 from FRRouting/master
Release 2.1.3
2 parents da0f908 + ba99578 commit 5d2cf6b

33 files changed

+771
-202
lines changed

.github/workflows/ruby.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ jobs:
2222
runs-on: ubuntu-latest
2323
steps:
2424
- name: Check out code
25-
uses: actions/checkout@v3
25+
uses: actions/checkout@v4
2626

2727
- uses: ruby/setup-ruby@v1
2828
with:
2929
ruby-version: 3.0.0
3030

3131
- name: rubocop
32-
uses: reviewdog/action-rubocop@v2
32+
uses: reviewdog/action-rubocop@v2.6.0
3333
with:
3434
github_token: ${{ secrets.GITHUB_TOKEN }}
3535
rubocop_version: gemfile
@@ -55,7 +55,7 @@ jobs:
5555
5656
steps:
5757
- name: Checkout
58-
uses: actions/checkout@v3
58+
uses: actions/checkout@v4
5959
with:
6060
fetch-depth: 0
6161

.rubocop.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ require:
22
- rubocop-performance
33

44
AllCops:
5+
TargetRubyVersion: 3.0
56
NewCops: enable
67
DisplayCopNames: true
78
SuggestExtensions: false

app/github_app.rb

+9-2
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,16 @@ def sinatra_logger_level
5252

5353
authenticate_request
5454

55-
github = Github::UpdateStatus.new(@payload)
55+
logger.info "Received event UpdateStatus: #{@payload}"
56+
puts "Received event UpdateStatus: #{@payload}"
5657

57-
halt github.update
58+
if @payload['status'] == 'finished'
59+
github = Github::PlanExecution::Finished.new(@payload)
60+
halt github.finished
61+
else
62+
github = Github::UpdateStatus.new(@payload)
63+
halt github.update
64+
end
5865
end
5966

6067
post '/slack' do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
#
3+
# 20240311164958_create_audit_retry.rb
4+
# Part of NetDEF CI System
5+
#
6+
# Copyright (c) 2024 by
7+
# Network Device Education Foundation, Inc. ("NetDEF")
8+
#
9+
# frozen_string_literal: true
10+
11+
class CreateAuditRetry < ActiveRecord::Migration[6.0]
12+
def change
13+
create_table :audit_retries do |t|
14+
t.string :github_username
15+
t.string :github_id
16+
t.string :github_type
17+
t.string :retry_type
18+
t.timestamps
19+
20+
t.references :check_suite, index: true, foreign_key: true
21+
end
22+
end
23+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
#
3+
# 20240312134402_add_ci_job_audit_retry.rb
4+
# Part of NetDEF CI System
5+
#
6+
# Copyright (c) 2024 by
7+
# Network Device Education Foundation, Inc. ("NetDEF")
8+
#
9+
# frozen_string_literal: true
10+
11+
class AddCiJobAuditRetry < ActiveRecord::Migration[6.0]
12+
def change
13+
create_table :audit_retries_ci_jobs, id: false do |t|
14+
t.belongs_to :ci_job
15+
t.belongs_to :audit_retry
16+
end
17+
end
18+
end

db/schema.rb

+20-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,28 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[7.0].define(version: 2024_02_07_070831) do
13+
ActiveRecord::Schema[7.0].define(version: 2024_03_12_134402) do
1414
# These are extensions that must be enabled in order to support this database
1515
enable_extension "plpgsql"
1616

17+
create_table "audit_retries", force: :cascade do |t|
18+
t.string "github_username"
19+
t.string "github_id"
20+
t.string "github_type"
21+
t.string "retry_type"
22+
t.datetime "created_at", null: false
23+
t.datetime "updated_at", null: false
24+
t.bigint "check_suite_id"
25+
t.index ["check_suite_id"], name: "index_audit_retries_on_check_suite_id"
26+
end
27+
28+
create_table "audit_retries_ci_jobs", id: false, force: :cascade do |t|
29+
t.bigint "ci_job_id"
30+
t.bigint "audit_retry_id"
31+
t.index ["audit_retry_id"], name: "index_audit_retries_ci_jobs_on_audit_retry_id"
32+
t.index ["ci_job_id"], name: "index_audit_retries_ci_jobs_on_ci_job_id"
33+
end
34+
1735
create_table "audit_statuses", force: :cascade do |t|
1836
t.integer "status", default: 0, null: false
1937
t.string "agent"
@@ -119,6 +137,7 @@
119137
t.index ["ci_job_id"], name: "index_topotest_failures_on_ci_job_id"
120138
end
121139

140+
add_foreign_key "audit_retries", "check_suites"
122141
add_foreign_key "check_suites", "pull_requests"
123142
add_foreign_key "ci_jobs", "check_suites"
124143
add_foreign_key "ci_jobs", "stages"

lib/bamboo_ci/running_plan.rb

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,23 @@
1111
require 'logger'
1212

1313
require_relative 'api'
14+
require_relative '../helpers/github_logger'
1415

1516
module BambooCi
1617
class RunningPlan
1718
extend BambooCi::Api
1819

1920
def self.fetch(plan_key)
20-
@logger = Logger.new($stdout)
21+
@logger = GithubLogger.instance.create('github_running_plan.log', Logger::INFO)
22+
2123
resp = get_request(URI("https://127.0.0.1/rest/api/latest/result/#{plan_key}?expand=stages.stage.results"))
2224

23-
return [] if resp.nil? or resp.empty?
25+
return [] if resp.nil? or resp.empty? or resp.dig('stages', 'stage').nil?
26+
27+
mount_jobs(resp)
28+
end
2429

30+
def self.mount_jobs(resp)
2531
jobs = []
2632
resp.dig('stages', 'stage').each do |stage|
2733
stage.dig('results', 'result').each do |job|

lib/github/build/action.rb

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def create_jobs(rerun)
4343
@jobs.each do |job|
4444
ci_job = create_ci_job(job)
4545

46+
next if ci_job.nil?
47+
4648
if rerun
4749
next unless ci_job.stage.configuration.can_retry?
4850

@@ -66,6 +68,8 @@ def stage_with_start_in_progress(ci_job)
6668
def create_ci_job(job)
6769
stage_config = StageConfiguration.find_by(bamboo_stage_name: job[:stage])
6870

71+
return if stage_config.nil?
72+
6973
stage = Stage.find_by(check_suite: @check_suite, name: stage_config.github_check_run_name)
7074

7175
logger(Logger::INFO, "create_jobs - #{job.inspect} -> #{stage.inspect}")

lib/github/build/retry.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
module Github
1414
module Build
1515
class Retry
16-
def initialize(check_suite, github, logger_level: Logger::INFO)
16+
def initialize(check_suite, github, audit_retry, logger_level: Logger::INFO)
1717
@check_suite = check_suite
1818
@github = github
1919
@loggers = []
2020
@stages_config = StageConfiguration.all
21+
@audit_retry = audit_retry
2122

2223
%w[github_app.log github_build_retry.log].each do |filename|
2324
@loggers << GithubLogger.instance.create(filename, logger_level)
@@ -48,6 +49,8 @@ def enqueued_failure_tests
4849
logger(Logger::WARN, "Enqueue CiJob: #{ci_job.inspect}")
4950
ci_job.enqueue(@github)
5051
ci_job.update(retry: ci_job.retry + 1)
52+
@audit_retry.ci_jobs << ci_job
53+
@audit_retry.save
5154
end
5255
end
5356

lib/github/build_plan.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def ci_vars
175175
end
176176

177177
def fetch_plan
178-
plan = Plan.find_by_github_repo_name(@payload.dig('repository', 'full_name'))
178+
plan = Plan.find_by(github_repo_name: @payload.dig('repository', 'full_name'))
179179

180180
return plan.bamboo_ci_plan_name unless plan.nil?
181181

lib/github/check.rb

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
require 'yaml'
1616
require 'logger'
1717

18+
require_relative '../helpers/configuration'
19+
1820
module Github
1921
class Check
2022
attr_reader :app, :check_suite

lib/github/plan_execution/finished.rb

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
#
3+
# check_suite_finished.rb
4+
# Part of NetDEF CI System
5+
#
6+
# Copyright (c) 2024 by
7+
# Network Device Education Foundation, Inc. ("NetDEF")
8+
#
9+
# frozen_string_literal: true
10+
11+
require_relative '../../slack_bot/slack_bot'
12+
require_relative '../../github/build/action'
13+
require_relative '../../github/build/summary'
14+
15+
module Github
16+
module PlanExecution
17+
class Finished
18+
include BambooCi::Api
19+
20+
def initialize(payload)
21+
@check_suite = CheckSuite.find_by(bamboo_ci_ref: payload['bamboo_ref'])
22+
@logger = GithubLogger.instance.create('github_plan_execution_finished.log', Logger::INFO)
23+
end
24+
25+
def finished
26+
@logger.info ">>> Check Suite: #{@check_suite.inspect}"
27+
28+
return [404, 'Check Suite not found'] if @check_suite.nil?
29+
30+
fetch_ci_execution
31+
build_status = fetch_build_status
32+
33+
@logger.info ">>> build_status: #{build_status.inspect}"
34+
35+
return [200, 'Still running'] if in_progress?(build_status)
36+
37+
check_stages
38+
clear_deleted_jobs
39+
40+
[200, 'Finished']
41+
end
42+
43+
private
44+
45+
# This method will move all tests that no longer exist in BambooCI to the skipped state,
46+
# because there are no executions for them.
47+
def clear_deleted_jobs
48+
github_check = Github::Check.new(@check_suite)
49+
50+
@check_suite.ci_jobs.where(status: %w[queued in_progress]).each do |ci_job|
51+
ci_job.skipped(github_check)
52+
end
53+
end
54+
55+
# Checks if CI still running
56+
def in_progress?(build_status)
57+
@logger.info ">>> ci_stopped?: #{ci_stopped?(build_status)}"
58+
@logger.info ">>> ci_hanged?: #{ci_hanged?(build_status)}"
59+
60+
return false if ci_hanged?(build_status)
61+
return false if build_status['currentStage'].casecmp('final').zero?
62+
63+
true
64+
end
65+
66+
def ci_stopped?(build_status)
67+
build_status.key?('message') and !build_status.key?('finished')
68+
end
69+
70+
def ci_hanged?(build_status)
71+
return true if ci_stopped?(build_status)
72+
73+
build_status.dig('progress', 'percentageCompleted').to_f >= 2.0
74+
end
75+
76+
def update_stage_status(ci_job, result, github)
77+
return if ci_job.nil? || (ci_job.finished? && !ci_job.job_ref.nil?)
78+
79+
update_ci_job_status(github, ci_job, result['state'])
80+
end
81+
82+
def update_ci_job_status(github_check, ci_job, state)
83+
ci_job.enqueue(github_check) if ci_job.job_ref.nil?
84+
85+
output = create_output_message(ci_job)
86+
87+
case state
88+
when 'Unknown'
89+
ci_job.cancelled(github_check, output: output, agent: 'WatchDog')
90+
slack_notify_cancelled(ci_job)
91+
when 'Failed'
92+
ci_job.failure(github_check, output: output, agent: 'WatchDog')
93+
slack_notify_failure(ci_job)
94+
when 'Successful'
95+
ci_job.success(github_check, output: output, agent: 'WatchDog')
96+
slack_notify_success(ci_job)
97+
else
98+
puts 'Ignored'
99+
end
100+
101+
build_summary(ci_job)
102+
end
103+
104+
def create_output_message(ci_job)
105+
url = "https://ci1.netdef.org/browse/#{ci_job.job_ref}"
106+
107+
{
108+
title: ci_job.name,
109+
summary: "Details at [#{url}](#{url})\nUnfortunately we were unable to access the execution results."
110+
}
111+
end
112+
113+
def build_summary(ci_job)
114+
summary = Github::Build::Summary.new(ci_job, agent: 'WatchDog')
115+
summary.build_summary
116+
117+
finished_execution?(ci_job.check_suite)
118+
end
119+
120+
def finished_execution?(check_suite)
121+
return false unless current_execution?(check_suite)
122+
return false unless check_suite.finished?
123+
124+
SlackBot.instance.execution_finished_notification(check_suite)
125+
end
126+
127+
def current_execution?(check_suite)
128+
pull_request = check_suite.pull_request
129+
last_check_suite = pull_request.check_suites.reload.all.order(:created_at).last
130+
131+
check_suite.id == last_check_suite.id
132+
end
133+
134+
def slack_notify_success(job)
135+
SlackBot.instance.notify_success(job)
136+
end
137+
138+
def slack_notify_failure(job)
139+
SlackBot.instance.notify_errors(job)
140+
end
141+
142+
def slack_notify_cancelled(job)
143+
SlackBot.instance.notify_cancelled(job)
144+
end
145+
146+
def check_stages
147+
github_check = Github::Check.new(@check_suite)
148+
@logger.info ">>> @result: #{@result.inspect}"
149+
@result.dig('stages', 'stage').each do |stage|
150+
stage.dig('results', 'result').each do |result|
151+
ci_job = CiJob.find_by(job_ref: result['buildResultKey'], check_suite_id: @check_suite.id)
152+
153+
update_stage_status(ci_job, result, github_check)
154+
end
155+
end
156+
end
157+
158+
def fetch_ci_execution
159+
@result = get_status(@check_suite.bamboo_ci_ref)
160+
end
161+
162+
def fetch_build_status
163+
get_request(URI("https://127.0.0.1/rest/api/latest/result/status/#{@check_suite.bamboo_ci_ref}"))
164+
end
165+
end
166+
end
167+
end

0 commit comments

Comments
 (0)