From daa824bf112ec81cd0810693fc564956884fd80d Mon Sep 17 00:00:00 2001 From: Rodrigo Nardi Date: Sat, 30 May 2026 20:51:04 -0300 Subject: [PATCH] Refactor plan fetching logic to support legacy pull requests without associated plans --- lib/github/re_run/command.rb | 4 +- lib/github/re_run/comment.rb | 6 ++- spec/lib/github/re_run/command_spec.rb | 51 ++++++++++++++++++++++++++ spec/lib/github/re_run/comment_spec.rb | 48 ++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/lib/github/re_run/command.rb b/lib/github/re_run/command.rb index 6cdc2ab..7bf2eea 100644 --- a/lib/github/re_run/command.rb +++ b/lib/github/re_run/command.rb @@ -40,7 +40,9 @@ def start private def suite_by_plan(check_suite) - check_suite.pull_request.plans.each do |plan| + plans = check_suite.pull_request.plans.presence || Plan.where(github_repo_name: repo) + + plans.each do |plan| CreateExecutionByCommand .delay(run_at: TIMER.seconds.from_now.utc, queue: 'create_execution_by_command') .create(plan.id, check_suite.id, @payload) diff --git a/lib/github/re_run/comment.rb b/lib/github/re_run/comment.rb index 670cd64..e743aba 100644 --- a/lib/github/re_run/comment.rb +++ b/lib/github/re_run/comment.rb @@ -41,7 +41,7 @@ def confirm_and_start github_reaction_feedback(comment_id) - @pull_request.plans.each do |plan| + fetch_plans.each do |plan| CreateExecutionByComment .delay(run_at: TIMER.seconds.from_now.utc, queue: 'create_execution_by_comment') .create(@pull_request.id, @payload, plan) @@ -50,6 +50,10 @@ def confirm_and_start [200, 'Scheduled Plan Runs'] end + def fetch_plans + @pull_request.plans.presence || Plan.where(github_repo_name: repo) + end + def github_reaction_feedback(comment_id) return if comment_id.nil? diff --git a/spec/lib/github/re_run/command_spec.rb b/spec/lib/github/re_run/command_spec.rb index a05476a..59c964a 100644 --- a/spec/lib/github/re_run/command_spec.rb +++ b/spec/lib/github/re_run/command_spec.rb @@ -91,6 +91,57 @@ end end + context 'when the pull request has no associated plans (legacy)' do + let(:plan) { create(:plan, github_repo_name: 'Unit/Test') } + let(:pull_request) { create(:pull_request, repository: 'Unit/Test', plans: []) } + let(:check_suite) { create(:check_suite, :with_running_ci_jobs, pull_request: pull_request) } + let(:fake_plan_run) { BambooCi::PlanRun.new(nil, plan) } + let(:check_suites) { CheckSuite.where(commit_sha_ref: check_suite.commit_sha_ref) } + let(:payload) do + { + 'action' => 'created', + 'check_suite' => { + 'head_sha' => check_suite.commit_sha_ref, + 'pull_requests' => [{ 'number' => pull_request.github_pr_id }] + }, + 'repository' => { 'full_name' => 'Unit/Test' } + } + end + + before do + plan + check_suite + + allow(Octokit::Client).to receive(:new).and_return(fake_client) + allow(fake_client).to receive(:find_app_installations).and_return([{ 'id' => 1 }]) + allow(fake_client).to receive(:create_app_installation_access_token).and_return({ 'token' => 1 }) + + allow(Github::Check).to receive(:new).and_return(fake_github_check) + allow(fake_github_check).to receive(:create).and_return(check_suite) + allow(fake_github_check).to receive(:add_comment) + allow(fake_github_check).to receive(:cancelled) + allow(fake_github_check).to receive(:in_progress) + allow(fake_github_check).to receive(:queued) + allow(fake_github_check).to receive(:skipped) + allow(fake_github_check).to receive(:comment_reaction_thumb_up) + allow(fake_github_check).to receive(:fetch_username).and_return({}) + allow(fake_github_check).to receive(:check_runs_for_ref).and_return({}) + + allow(BambooCi::PlanRun).to receive(:new).and_return(fake_plan_run) + allow(fake_plan_run).to receive(:start_plan).and_return(200) + allow(fake_plan_run).to receive(:bamboo_reference).and_return('UNIT-TEST-1') + + allow(BambooCi::StopPlan).to receive(:build) + allow(BambooCi::RunningPlan).to receive(:fetch).and_return([]) + end + + it 'must return success using plans from repository' do + expect(rerun.start).to eq([200, 'Scheduled Plan Runs']) + expect(check_suites.size).to eq(2) + expect(check_suites.last.re_run).to be_truthy + end + end + context 'when receives a valid command but invalid PR ID' do let(:check_suite) { create(:check_suite, :with_running_ci_jobs) } let(:ci_jobs) do diff --git a/spec/lib/github/re_run/comment_spec.rb b/spec/lib/github/re_run/comment_spec.rb index 1ebb0f3..16e042e 100644 --- a/spec/lib/github/re_run/comment_spec.rb +++ b/spec/lib/github/re_run/comment_spec.rb @@ -303,6 +303,54 @@ end end + context 'when the pull request has no associated plans (legacy)' do + let(:plan) { create(:plan, github_repo_name: 'test') } + let(:pull_request) { create(:pull_request, github_pr_id: 22, repository: 'test', plans: []) } + let(:check_suite) { create(:check_suite, :with_running_ci_jobs, pull_request: pull_request) } + let(:fake_plan_run) { BambooCi::PlanRun.new(nil, plan) } + let(:check_suites) { CheckSuite.where(commit_sha_ref: check_suite.commit_sha_ref) } + let(:payload) do + { + 'action' => 'created', + 'comment' => { 'body' => "CI:rerun ##{check_suite.commit_sha_ref}", 'id' => 1, 'user' => { 'login' => 'John' } }, + 'repository' => { 'full_name' => 'test' }, + 'issue' => { 'number' => pull_request.github_pr_id } + } + end + + before do + plan + check_suite + + allow(Octokit::Client).to receive(:new).and_return(fake_client) + allow(fake_client).to receive(:find_app_installations).and_return([{ 'id' => 1 }]) + allow(fake_client).to receive(:create_app_installation_access_token).and_return({ 'token' => 1 }) + + allow(Github::Check).to receive(:new).and_return(fake_github_check) + allow(fake_github_check).to receive(:create).and_return(check_suite) + allow(fake_github_check).to receive(:add_comment) + allow(fake_github_check).to receive(:cancelled) + allow(fake_github_check).to receive(:in_progress) + allow(fake_github_check).to receive(:queued) + allow(fake_github_check).to receive(:comment_reaction_thumb_up) + allow(fake_github_check).to receive(:fetch_username).and_return({}) + allow(fake_github_check).to receive(:check_runs_for_ref).and_return({}) + + allow(BambooCi::PlanRun).to receive(:new).and_return(fake_plan_run) + allow(fake_plan_run).to receive(:start_plan).and_return(200) + allow(fake_plan_run).to receive(:bamboo_reference).and_return('UNIT-TEST-1') + + allow(BambooCi::StopPlan).to receive(:build) + allow(BambooCi::RunningPlan).to receive(:fetch).and_return([]) + end + + it 'must return success using plans from repository' do + expect(rerun.start).to eq([200, 'Scheduled Plan Runs']) + expect(check_suites.size).to eq(2) + expect(check_suites.last.re_run).to be_truthy + end + end + context 'when receives an invalid pull request' do let(:pull_request) { create(:pull_request, github_pr_id: 12, repository: 'test') } let(:check_suite) { create(:check_suite, :with_running_ci_jobs, pull_request: pull_request) }