diff --git a/src/bin/bors.rs b/src/bin/bors.rs index 9db96e0f..4c4bdd16 100644 --- a/src/bin/bors.rs +++ b/src/bin/bors.rs @@ -266,6 +266,7 @@ fn try_main(opts: Opts) -> anyhow::Result<()> { BorsGlobalEvent::RefreshPendingBuilds, BorsGlobalEvent::ProcessMergeQueue, BorsGlobalEvent::TerminateOldEC2Instances, + BorsGlobalEvent::ReloadWorkflowJobCache, ]; for event in startup_events { refresh_tx.send(event).await?; diff --git a/src/bors/event.rs b/src/bors/event.rs index 16465233..d3d51ddd 100644 --- a/src/bors/event.rs +++ b/src/bors/event.rs @@ -83,6 +83,8 @@ pub enum BorsGlobalEvent { TerminateOldEC2Instances, /// Try to create EC2 instances for jobs that have been queued for some time. BackfillEC2Instances, + /// Reload jobs of pending workfows into the in-memory job cache. + ReloadWorkflowJobCache, } #[derive(Debug)] diff --git a/src/bors/handlers/mod.rs b/src/bors/handlers/mod.rs index 534a18c6..415dabcd 100644 --- a/src/bors/handlers/mod.rs +++ b/src/bors/handlers/mod.rs @@ -19,6 +19,7 @@ use crate::bors::handlers::trybuild::{command_try_build, command_try_cancel}; use crate::bors::handlers::workflow::{ AutoBuildCancelReason, handle_workflow_completed, handle_workflow_job_completed, handle_workflow_job_started, handle_workflow_started, maybe_cancel_auto_build, + reload_workflow_job_cache, }; use crate::bors::labels::handle_label_trigger; use crate::bors::mergeability_queue::set_pr_mergeability_based_on_user_action; @@ -355,6 +356,16 @@ pub async fn handle_bors_global_event( .await?; } } + BorsGlobalEvent::ReloadWorkflowJobCache => { + tracing::info!("Attempt to reload in-memory workflow job cache"); + let span = tracing::info_span!("Reloading workflow jobs"); + for_each_repo(&ctx, |repo| { + let subspan = tracing::info_span!("Repo", "{}", repo.repository()); + reload_workflow_job_cache(&ctx, db.clone(), repo).instrument(subspan) + }) + .instrument(span) + .await?; + } } Ok(()) } diff --git a/src/bors/handlers/workflow.rs b/src/bors/handlers/workflow.rs index 6bfe085d..2e99ca22 100644 --- a/src/bors/handlers/workflow.rs +++ b/src/bors/handlers/workflow.rs @@ -9,8 +9,10 @@ use crate::bors::handlers::{get_build_kind_from_branch, is_bors_observed_branch} use crate::bors::{BuildKind, build}; use crate::database::{BuildModel, BuildStatus, PullRequestModel, WorkflowStatus}; use crate::ec2::{Ec2InstanceStartData, ParsedLabel, start_ec2_github_runner}; +use crate::github::CommitSha; use crate::github::api::client::GithubRepositoryClient; use crate::{BorsContext, PgDbClient}; +use octocrab::models::workflows::Status; use std::sync::Arc; use std::time::Duration; @@ -263,6 +265,71 @@ pub(super) async fn handle_workflow_job_completed( Ok(()) } +/// Load pending auto workflows and their jobs from GitHub Actions, and store their state into the +/// in-memory job cache. +pub(super) async fn reload_workflow_job_cache( + ctx: &BorsContext, + db: Arc, + repo: Arc, +) -> anyhow::Result<()> { + let job_cache = ctx.get_job_cache(); + + let builds = db.get_pending_builds(repo.repository()).await?; + for build in &builds { + // Right now, we only care about auto builds + if build.kind != BuildKind::Auto { + continue; + } + + let Ok(workflows) = repo + .client + .get_workflow_runs_for_commit_sha(CommitSha(build.commit_sha.clone())) + .await + else { + continue; + }; + for workflow in workflows { + match workflow.status { + WorkflowStatus::Pending => {} + WorkflowStatus::Success | WorkflowStatus::Failure => { + continue; + } + } + let Ok(workflow_jobs) = repo.client.get_jobs_for_workflow_run(workflow.id).await else { + continue; + }; + + tracing::info!( + "Reloading {} job(s) of workflow run {}", + workflow_jobs.len(), + workflow.id + ); + for job in workflow_jobs { + match job.status { + Status::Completed | Status::Failed => { + job_cache.auto_job_completed( + repo.repository(), + workflow.id, + job.id, + &job.name, + ); + } + _ => { + job_cache.auto_job_started( + repo.repository(), + workflow.id, + job.id, + &job.name, + ); + } + } + } + } + } + + Ok(()) +} + /// Why did we cancel an auto build? pub enum AutoBuildCancelReason { /// A new commit was pushed to a PR while it was being tested in an auto build.