diff --git a/lib/bamboo_ci/stop_plan.rb b/lib/bamboo_ci/stop_plan.rb index 54de48f..89537b0 100644 --- a/lib/bamboo_ci/stop_plan.rb +++ b/lib/bamboo_ci/stop_plan.rb @@ -26,7 +26,7 @@ def self.build(bamboo_ci_ref) end def self.comment(check_suite, new_check_suite) - new_url = "https://ci1.netdef.org/browse/#{new_check_suite.bamboo_ci_ref}" + new_url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{new_check_suite.bamboo_ci_ref}" comment = "This execution was cancelled due to a new commit or `ci:rerun` (#{new_url})" add_comment_to_ci(check_suite.bamboo_ci_ref, comment) diff --git a/lib/github/build/action.rb b/lib/github/build/action.rb index bb954ae..1557ad5 100644 --- a/lib/github/build/action.rb +++ b/lib/github/build/action.rb @@ -77,7 +77,7 @@ def create_jobs(rerun) if rerun next unless ci_job.stage.configuration.can_retry? - url = "https://ci1.netdef.org/browse/#{ci_job.job_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{ci_job.job_ref}" ci_job.enqueue(@github, { title: ci_job.name, summary: "Details at [#{url}](#{url})" }) else ci_job.create_check_run @@ -156,7 +156,7 @@ def create_stage(stage_config) status: 'queued', name: name) - url = "https://ci1.netdef.org/browse/#{stage.check_suite.bamboo_ci_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{stage.check_suite.bamboo_ci_ref}" output = { title: "#{stage.name} summary", summary: "Uninitialized stage\nDetails at [#{url}](#{url})" } stage.enqueue(@github, output: output) @@ -172,7 +172,7 @@ def create_stage(stage_config) # @return [Hash] The initial output. def initial_output(ci_job) output = { title: '', summary: '' } - url = "https://ci1.netdef.org/browse/#{ci_job.check_suite.bamboo_ci_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{ci_job.check_suite.bamboo_ci_ref}" output[:title] = "#{ci_job.name} summary" output[:summary] = "Details at [#{url}](#{url})" diff --git a/lib/github/build/retry.rb b/lib/github/build/retry.rb index ba0f74c..b592638 100644 --- a/lib/github/build/retry.rb +++ b/lib/github/build/retry.rb @@ -36,7 +36,7 @@ def enqueued_stages next if stage.nil? next if stage.success? - url = "https://ci1.netdef.org/browse/#{stage.check_suite.bamboo_ci_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{stage.check_suite.bamboo_ci_ref}" output = { title: "#{stage.name} summary", summary: "Uninitialized stage\nDetails at [#{url}](#{url})" } stage.enqueue(@github, output: output) diff --git a/lib/github/build/summary.rb b/lib/github/build/summary.rb index 81b1430..3b6378f 100644 --- a/lib/github/build/summary.rb +++ b/lib/github/build/summary.rb @@ -101,7 +101,7 @@ def must_continue_next_stage(current_stage) end def cancelling_next_stage(pending_stage) - url = "https://ci1.netdef.org/browse/#{pending_stage.check_suite.bamboo_ci_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{pending_stage.check_suite.bamboo_ci_ref}" output = { title: "#{pending_stage.name} summary", @@ -122,7 +122,7 @@ def finished_summary(stage) end def finished_stage_summary(stage) - url = "https://ci1.netdef.org/browse/#{stage.check_suite.bamboo_ci_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{stage.check_suite.bamboo_ci_ref}" output = { title: "#{stage.name} summary", summary: "#{summary_basic_output(stage)}\nDetails at [#{url}](#{url}).".force_encoding('utf-8') @@ -146,7 +146,7 @@ def finished_stage_update(stage, output) end def update_summary(stage) - url = "https://ci1.netdef.org/browse/#{@check_suite.bamboo_ci_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{@check_suite.bamboo_ci_ref}" output = { title: "#{stage.name} summary", summary: "#{summary_basic_output(stage)}\nDetails at [#{url}](#{url}).".force_encoding('utf-8') @@ -196,7 +196,7 @@ def in_progress_message(jobs) message = "\n\n:arrow_right: Jobs in progress: #{in_progress.size}/#{jobs.size}\n\n" message + jobs.where(status: %i[in_progress]).map do |job| - "- **#{job.name}** -> https://ci1.netdef.org/browse/#{job.job_ref}\n" + "- **#{job.name}** -> https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{job.job_ref}\n" end.join("\n") end @@ -206,13 +206,13 @@ def queued_message(jobs) message = ":arrow_right: Jobs queued: #{queued.size}/#{jobs.size}\n\n" message + queued.map do |job| - "- **#{job.name}** -> https://ci1.netdef.org/browse/#{job.job_ref}\n" + "- **#{job.name}** -> https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{job.job_ref}\n" end.join("\n") end def success_message(jobs) jobs.where(status: :success).map do |job| - "- **#{job.name}** -> https://ci1.netdef.org/browse/#{job.job_ref}\n" + "- **#{job.name}** -> https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{job.job_ref}\n" end.join("\n") end @@ -227,7 +227,7 @@ def generate_message(name, job) failures = build_message(job) if name.downcase.match?('build') failures = checkout_message(job) if name.downcase.match?('source') - "- #{job.name} -> https://ci1.netdef.org/browse/#{job.job_ref}\n#{failures}" + "- #{job.name} -> https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{job.job_ref}\n#{failures}" end def tests_message(job) diff --git a/lib/github/plan_execution/finished.rb b/lib/github/plan_execution/finished.rb index fc1bf99..733bfb8 100644 --- a/lib/github/plan_execution/finished.rb +++ b/lib/github/plan_execution/finished.rb @@ -34,8 +34,12 @@ class Finished # # @param [Hash] payload The payload containing information about the CheckSuite. def initialize(payload) - @check_suite = CheckSuite.find_by(bamboo_ci_ref: payload['bamboo_ref']) if payload['bamboo_ref'] - @check_suite = CheckSuite.find(payload['check_suite_id']) if payload['check_suite_id'] + @check_suite = CheckSuite.where( + bamboo_ci_ref: payload['bamboo_ref'] + ).or( + CheckSuite.where(id: payload['check_suite_id']) + ).last + @logger = GithubLogger.instance.create('github_plan_execution_finished.log', Logger::INFO) @hanged = payload['hanged'] || false end @@ -180,7 +184,7 @@ def update_ci_job_status(github_check, ci_job, state) # @param [CiJob] ci_job The CI job to create the message for. # @return [Hash] The output message. def create_output_message(ci_job) - url = "https://ci1.netdef.org/browse/#{ci_job.job_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{ci_job.job_ref}" { title: ci_job.name, diff --git a/lib/helpers/configuration.rb b/lib/helpers/configuration.rb index 6cf32c5..7503365 100644 --- a/lib/helpers/configuration.rb +++ b/lib/helpers/configuration.rb @@ -27,6 +27,12 @@ def debug? config.key? 'debug' and config['debug'] end + def ci_url + return @config['ci']['url'] if @config.key?('ci') && @config['ci'].key?('url') + + 'https://ci1.netdef.org' + end + private def configuration diff --git a/lib/models/stage.rb b/lib/models/stage.rb index 98f5dfd..8384e73 100644 --- a/lib/models/stage.rb +++ b/lib/models/stage.rb @@ -117,14 +117,19 @@ def github_stage_full_name(name) end def output_in_progress + url = GitHubApp::Configuration.instance.ci_url in_progress = jobs.where(status: :in_progress) header = ":arrow_right: Jobs in progress: #{in_progress.size}/#{jobs.size}\n\n" - in_progress_jobs = jobs.where(status: :in_progress).map do |job| - "- **#{job.name}** -> https://ci1.netdef.org/browse/#{job.job_ref}\n" - end.join("\n") + in_progress_jobs = mount_in_progress_jobs(jobs) - url = "https://ci1.netdef.org/browse/#{check_suite.bamboo_ci_ref}" + url = "https://#{url}/browse/#{check_suite.bamboo_ci_ref}" { title: "#{name} summary", summary: "#{header}#{in_progress_jobs}\nDetails at [#{url}](#{url})" } end + + def mount_in_progress_jobs(jobs) + jobs.where(status: :in_progress).map do |job| + "- **#{job.name}** -> https://#{url}/browse/#{job.job_ref}\n" + end.join("\n") + end end diff --git a/lib/slack_bot/slack_bot.rb b/lib/slack_bot/slack_bot.rb index 48ad5fc..1cfccfe 100644 --- a/lib/slack_bot/slack_bot.rb +++ b/lib/slack_bot/slack_bot.rb @@ -149,7 +149,7 @@ def send_stage_notification(stage, pull_request, subscription) url = "#{GitHubApp::Configuration.instance.config['slack_bot_url']}/github/user" pr_url = "https://github.com/#{pull_request.repository}/pull/#{pull_request.github_pr_id}" - bamboo_link = "https://ci1.netdef.org/browse/#{stage.check_suite.bamboo_ci_ref}" + bamboo_link = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{stage.check_suite.bamboo_ci_ref}" post_request(URI(url), machine: 'slack_bot.netdef.org', @@ -197,7 +197,7 @@ def pull_request_message(check_suite, status) pr = check_suite.pull_request pr_url = "https://github.com/#{pr.repository}/pull/#{pr.github_pr_id}" - bamboo_link = "https://ci1.netdef.org/browse/#{check_suite.bamboo_ci_ref}" + bamboo_link = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{check_suite.bamboo_ci_ref}" "PR <#{pr_url}|##{pr.github_pr_id}>. <#{bamboo_link}|#{status}> " end @@ -205,7 +205,7 @@ def pull_request_message(check_suite, status) def generate_notification_message(job, status) pr = job.check_suite.pull_request pr_url = "https://github.com/#{pr.repository}/pull/#{pr.github_pr_id}/checks?check_run_id=#{job.check_ref}" - bamboo_link = "https://ci1.netdef.org/browse/#{job.job_ref}" + bamboo_link = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{job.job_ref}" "PR <#{pr_url}|##{pr.github_pr_id}>. <#{bamboo_link}|#{job.name} - #{status}> " end diff --git a/rbenv-setup.yml b/rbenv-setup.yml new file mode 100644 index 0000000..9862581 --- /dev/null +++ b/rbenv-setup.yml @@ -0,0 +1,115 @@ +--- +- name: Install RbEnv and Ruby build dependencies + hosts: all + become: yes + + vars: + rbenv_packages: + - git + - curl + - build-essential + - libssl-dev + - zlib1g-dev + - libpq-dev + - rbenv + - libffi-dev + - libyaml-dev + - autoconf + - bison + + tasks: + - name: Update apt cache + apt: + update_cache: yes + + - name: Install required packages for rbenv and Ruby + apt: + name: "{{ rbenv_packages }}" + state: present + install_recommends: yes + + - name: Ensure rbenv is initialized in .bashrc + lineinfile: + path: ~/.bashrc + line: 'eval "$(rbenv init -)"' + state: present + insertafter: EOF + become: no + + - name: Install rbenv using git + git: + repo: 'https://github.com/rbenv/rbenv.git' + dest: ~/.rbenv + update: no + become: no + + - name: Add rbenv to PATH + lineinfile: + path: ~/.bashrc + line: 'export PATH="$HOME/.rbenv/bin:$PATH"' + state: present + insertafter: EOF + become: no + + - name: Install ruby-build as rbenv plugin + git: + repo: 'https://github.com/rbenv/ruby-build.git' + dest: ~/.rbenv/plugins/ruby-build + update: no + become: no + + - name: Ensure rbenv is initialized in .bashrc + lineinfile: + path: ~/.bashrc + line: 'eval "$(rbenv init -)"' + state: present + insertafter: EOF + become: no + + - name: Reload shell to use rbenv + shell: | + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init -)" + args: + executable: /bin/bash + become: no + + - name: Install Ruby 3.1.2 + shell: | + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init -)" + rbenv install -s 3.1.2 + args: + creates: ~/.rbenv/versions/3.1.2 + executable: /bin/bash + become: no + + - name: Set Ruby 3.1.2 as local version + shell: | + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init -)" + rbenv local 3.1.2 + args: + chdir: "{{ ansible_env.PWD }}" + executable: /bin/bash + become: no + + - name: Install bundler gem + shell: | + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init -)" + gem install bundler + rbenv rehash + args: + executable: /bin/bash + become: no + + - name: Run bundle install + shell: | + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init -)" + bundle install + args: + chdir: "{{ ansible_env.PWD }}" + executable: /bin/bash + become: no \ No newline at end of file diff --git a/reports/build_stage_failed.rb b/reports/build_stage_failed.rb index 2dbe897..d41006c 100644 --- a/reports/build_stage_failed.rb +++ b/reports/build_stage_failed.rb @@ -23,7 +23,7 @@ .where(jobs: { created_at: [begin_date..end_date], status: %i[failure skipped] }) .where(check_suites: { author: author }) .each do |stage| - message = "Check Suite ID: https://ci1.netdef.org/browse/#{stage.check_suite.bamboo_ci_ref}" + message = "Check Suite ID: https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{stage.check_suite.bamboo_ci_ref}" check_suites << message unless check_suites.include? message end diff --git a/reports/github_user_usage.rb b/reports/github_user_usage.rb index 794a916..f2eaf86 100644 --- a/reports/github_user_usage.rb +++ b/reports/github_user_usage.rb @@ -28,7 +28,7 @@ else puts "Check Suites for user: #{user.github_login}" user.check_suites.each do |cs| - puts "Check Suite: https://ci1.netdef.org/browse/#{cs.bamboo_ci_ref}" + puts "Check Suite: https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{cs.bamboo_ci_ref}" end end diff --git a/spec/lib/github/build/summary_spec.rb b/spec/lib/github/build/summary_spec.rb index 1488b1e..333e641 100644 --- a/spec/lib/github/build/summary_spec.rb +++ b/spec/lib/github/build/summary_spec.rb @@ -403,7 +403,7 @@ create(:ci_job, :success, stage: stage, check_suite: check_suite, name: 'Sourcecode', summary: 'HI') end let(:message) do - "Sourcecode -> https://ci1.netdef.org/browse/#{ci_job.job_ref}\n```\nHI\n```" + "Sourcecode -> https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{ci_job.job_ref}\n```\nHI\n```" end it 'must update stage' do diff --git a/spec/lib/helpers/configuration_spec.rb b/spec/lib/helpers/configuration_spec.rb new file mode 100644 index 0000000..55ebfb0 --- /dev/null +++ b/spec/lib/helpers/configuration_spec.rb @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: BSD-2-Clause +# +# configuration_spec.rb +# Part of NetDEF CI System +# +# Copyright (c) 2025 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# frozen_string_literal: true + +describe GitHubApp::Configuration do + let(:config_path) { File.expand_path('config.yml', File.join(File.dirname(__FILE__), '../../../')) } + let(:default_config) do + { + 'debug' => true, + 'ci' => { 'url' => 'https://custom.ci.url' } + } + end + + before do + allow(YAML).to receive(:load_file).and_return(default_config) + if described_class.instance_variable_defined?(:@singleton__instance__) + described_class.__send__(:remove_instance_variable, :@singleton__instance__) + end + end + + after do + if described_class.instance_variable_defined?(:@singleton__instance__) + described_class.__send__(:remove_instance_variable, :@singleton__instance__) + end + end + + describe '.instance' do + it 'returns a singleton instance' do + expect(described_class.instance).to be_a(described_class) + expect(described_class.instance).to equal(described_class.instance) + end + end + + describe '#config' do + it 'loads the configuration from YAML' do + expect(described_class.instance.config).to eq(default_config) + end + end + + describe '#debug?' do + context 'when debug is true' do + it 'returns true' do + expect(described_class.instance.debug?).to be true + end + end + + context 'when debug is false' do + before do + allow(YAML).to receive(:load_file).and_return(default_config.merge('debug' => false)) + end + + it 'returns false' do + expect(described_class.instance.debug?).to be false + end + end + + context 'when debug key is missing' do + before do + allow(YAML).to receive(:load_file).and_return(default_config.except('debug')) + end + + it 'returns false' do + expect(described_class.instance.debug?).to be false + end + end + end + + describe '#ci_url' do + context 'when ci url is present' do + it 'returns the configured ci url' do + expect(described_class.instance.ci_url).to eq('https://custom.ci.url') + end + end + + context 'when ci key is missing' do + before do + allow(YAML).to receive(:load_file).and_return(default_config.except('ci')) + end + + it 'returns the default ci url' do + expect(described_class.instance.ci_url).to eq('https://ci1.netdef.org') + end + end + + context 'when ci url is missing' do + before do + allow(YAML).to receive(:load_file).and_return(default_config.merge('ci' => {})) + end + + it 'returns the default ci url' do + expect(described_class.instance.ci_url).to eq('https://ci1.netdef.org') + end + end + end + + describe '#reload' do + it 'reloads the configuration' do + expect(YAML).to receive(:load_file).twice.and_return(default_config) + instance = described_class.instance + instance.reload + end + end +end diff --git a/workers/single_sync.rb b/workers/single_sync.rb index 5388e9a..6f69b96 100644 --- a/workers/single_sync.rb +++ b/workers/single_sync.rb @@ -57,7 +57,7 @@ def create_ci_job(check_suite, result, bamboo_ci_ref, github_check) end def update_ci_job_status(github_check, ci_job, state) - url = "https://ci1.netdef.org/browse/#{ci_job.job_ref}" + url = "https://#{GitHubApp::Configuration.instance.ci_url}/browse/#{ci_job.job_ref}" output = { title: ci_job.name, summary: "Details at [#{url}](#{url})\nUnfortunately we were unable to access the execution results."