11use std:: sync:: Arc ;
22use std:: { collections:: HashMap , time:: SystemTime } ;
33
4+ use super :: user:: { GitHubUser , User } ;
45use crate :: bors:: PullRequestStatus ;
5- use base64:: Engine ;
6- use chrono:: { DateTime , Utc } ;
7- use octocrab:: models:: CheckSuiteId ;
8- use octocrab:: models:: pulls:: MergeableState ;
9- use octocrab:: models:: repos:: Object ;
10- use octocrab:: models:: repos:: Object :: Commit ;
11-
126use crate :: database:: WorkflowStatus ;
137use crate :: github:: { GithubRepoName , PullRequestNumber } ;
148use crate :: permissions:: PermissionType ;
159use crate :: tests:: mocks:: comment:: Comment ;
1610use crate :: tests:: mocks:: permissions:: Permissions ;
1711use crate :: tests:: mocks:: pull_request:: mock_pull_requests;
12+ use crate :: tests:: mocks:: workflow:: WorkflowJob ;
1813use crate :: tests:: mocks:: { GitHubState , WorkflowRunData , default_pr_number, dynamic_mock_req} ;
14+ use base64:: Engine ;
15+ use chrono:: { DateTime , Utc } ;
16+ use octocrab:: models:: pulls:: MergeableState ;
17+ use octocrab:: models:: repos:: Object ;
18+ use octocrab:: models:: repos:: Object :: Commit ;
19+ use octocrab:: models:: workflows:: { Conclusion , Status , Step } ;
20+ use octocrab:: models:: { CheckSuiteId , JobId , RunId } ;
1921use parking_lot:: Mutex ;
2022use serde:: Serialize ;
2123use tokio:: sync:: mpsc:: Sender ;
@@ -25,8 +27,6 @@ use wiremock::{
2527 matchers:: { method, path} ,
2628} ;
2729
28- use super :: user:: { GitHubUser , User } ;
29-
3030#[ derive( Clone , Debug ) ]
3131pub struct CheckRunData {
3232 pub name : String ,
@@ -386,6 +386,7 @@ pub async fn mock_repo(
386386 mock_cancel_workflow ( repo. clone ( ) , mock_server) . await ;
387387 mock_check_runs ( repo. clone ( ) , mock_server) . await ;
388388 mock_workflow_runs ( repo. clone ( ) , mock_server) . await ;
389+ mock_workflow_jobs ( repo. clone ( ) , mock_server) . await ;
389390 mock_config ( repo, mock_server) . await ;
390391}
391392
@@ -580,8 +581,8 @@ async fn mock_workflow_runs(repo: Arc<Mutex<Repo>>, mock_server: &MockServer) {
580581 #[ derive( serde:: Serialize , Debug ) ]
581582 struct WorkflowRunResponse {
582583 id : octocrab:: models:: RunId ,
583- status : String ,
584- conclusion : Option < String > ,
584+ status : Status ,
585+ conclusion : Option < Conclusion > ,
585586 }
586587
587588 #[ derive( serde:: Serialize , Debug ) ]
@@ -607,25 +608,64 @@ async fn mock_workflow_runs(repo: Arc<Mutex<Repo>>, mock_server: &MockServer) {
607608 let response = WorkflowRunsResponse {
608609 workflow_runs : workflow_runs
609610 . into_iter ( )
610- . map ( |run| WorkflowRunResponse {
611- id : run. workflow_run . run_id ,
612- status : match run. status {
613- WorkflowStatus :: Pending => "pending" ,
614- WorkflowStatus :: Success | WorkflowStatus :: Failure => "completed" ,
611+ . map ( |run| {
612+ let ( status, conclusion) = status_to_gh ( run. status ) ;
613+ WorkflowRunResponse {
614+ id : run. workflow_run . run_id ,
615+ status,
616+ conclusion,
615617 }
616- . to_string ( ) ,
617- conclusion : match run. status {
618- WorkflowStatus :: Success => Some ( "success" . to_string ( ) ) ,
619- WorkflowStatus :: Failure => Some ( "failure" . to_string ( ) ) ,
620- _ => None ,
621- } ,
622618 } )
623619 . collect ( ) ,
624620 } ;
625621 ResponseTemplate :: new ( 200 ) . set_body_json ( response)
626622 } ,
627623 "GET" ,
628- format ! ( "^/repos/{repo_name}/actions/runs" ) ,
624+ format ! ( "^/repos/{repo_name}/actions/runs$" ) ,
625+ )
626+ . mount ( mock_server)
627+ . await ;
628+ }
629+
630+ /// Returns (status, conclusion).
631+ fn status_to_gh ( status : WorkflowStatus ) -> ( Status , Option < Conclusion > ) {
632+ let conclusion = match status {
633+ WorkflowStatus :: Success => Some ( Conclusion :: Success ) ,
634+ WorkflowStatus :: Failure => Some ( Conclusion :: Failure ) ,
635+ _ => None ,
636+ } ;
637+ let status = match status {
638+ WorkflowStatus :: Pending => Status :: Pending ,
639+ WorkflowStatus :: Success | WorkflowStatus :: Failure => Status :: Completed ,
640+ } ;
641+ ( status, conclusion)
642+ }
643+
644+ async fn mock_workflow_jobs ( repo : Arc < Mutex < Repo > > , mock_server : & MockServer ) {
645+ let repo_name = repo. lock ( ) . name . clone ( ) ;
646+ dynamic_mock_req (
647+ move |_req : & Request , [ run_id] : [ & str ; 1 ] | {
648+ let repo = repo. lock ( ) ;
649+ let run_id: RunId = run_id. parse :: < u64 > ( ) . expect ( "Non-integer run id" ) . into ( ) ;
650+ let workflow_run = repo
651+ . workflow_runs
652+ . iter ( )
653+ . find ( |w| w. workflow_run . run_id == run_id)
654+ . unwrap_or_else ( || panic ! ( "Workflow run with ID {run_id} not found" ) ) ;
655+
656+ let response = GitHubWorkflowJobs {
657+ total_count : workflow_run. workflow_run . jobs . len ( ) as u64 ,
658+ jobs : workflow_run
659+ . workflow_run
660+ . jobs
661+ . iter ( )
662+ . map ( |job| workflow_job_to_gh ( job, run_id) )
663+ . collect ( ) ,
664+ } ;
665+ ResponseTemplate :: new ( 200 ) . set_body_json ( response)
666+ } ,
667+ "GET" ,
668+ format ! ( "^/repos/{repo_name}/actions/runs/(.*)/jobs" ) ,
629669 )
630670 . mount ( mock_server)
631671 . await ;
@@ -923,3 +963,73 @@ struct GitHubRef {
923963 url : Url ,
924964 object : Object ,
925965}
966+
967+ #[ derive( Serialize ) ]
968+ struct GitHubWorkflowJobs {
969+ total_count : u64 ,
970+ jobs : Vec < GitHubWorkflowJob > ,
971+ }
972+
973+ #[ derive( Serialize ) ]
974+ struct GitHubWorkflowJob {
975+ id : JobId ,
976+ run_id : RunId ,
977+ workflow_name : String ,
978+ head_branch : String ,
979+ run_url : Url ,
980+ run_attempt : u32 ,
981+
982+ node_id : String ,
983+ head_sha : String ,
984+ url : Url ,
985+ html_url : Url ,
986+ status : Status ,
987+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
988+ conclusion : Option < Conclusion > ,
989+ created_at : DateTime < Utc > ,
990+ started_at : DateTime < Utc > ,
991+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
992+ completed_at : Option < DateTime < Utc > > ,
993+ name : String ,
994+ steps : Vec < Step > ,
995+ check_run_url : String ,
996+ labels : Vec < String > ,
997+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
998+ runner_id : Option < u32 > ,
999+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
1000+ runner_name : Option < String > ,
1001+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
1002+ runner_group_id : Option < u32 > ,
1003+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
1004+ runner_group_name : Option < String > ,
1005+ }
1006+
1007+ fn workflow_job_to_gh ( job : & WorkflowJob , run_id : RunId ) -> GitHubWorkflowJob {
1008+ let WorkflowJob { id, status } = job;
1009+ let ( status, conclusion) = status_to_gh ( * status) ;
1010+ GitHubWorkflowJob {
1011+ id : * id,
1012+ run_id,
1013+ workflow_name : "" . to_string ( ) ,
1014+ head_branch : "" . to_string ( ) ,
1015+ run_url : "https://test.com" . parse ( ) . unwrap ( ) ,
1016+ run_attempt : 0 ,
1017+ node_id : "" . to_string ( ) ,
1018+ head_sha : "" . to_string ( ) ,
1019+ url : "https://test.com" . parse ( ) . unwrap ( ) ,
1020+ html_url : format ! ( "https://github.com/job-logs/{id}" ) . parse ( ) . unwrap ( ) ,
1021+ status,
1022+ conclusion,
1023+ created_at : Default :: default ( ) ,
1024+ started_at : Default :: default ( ) ,
1025+ completed_at : None ,
1026+ name : format ! ( "Job {id}" ) ,
1027+ steps : vec ! [ ] ,
1028+ check_run_url : "" . to_string ( ) ,
1029+ labels : vec ! [ ] ,
1030+ runner_id : None ,
1031+ runner_name : None ,
1032+ runner_group_id : None ,
1033+ runner_group_name : None ,
1034+ }
1035+ }
0 commit comments