@@ -107,6 +107,11 @@ impl Workflow {
107107 . as_ref ( )
108108 . and_then ( |template_ref| template_ref. name . as_deref ( ) )
109109 }
110+
111+ /// The workflow creator
112+ async fn creator ( & self ) -> WorkflowCreator {
113+ WorkflowCreator :: from_argo_workflow_labels ( & self . manifest . metadata . labels )
114+ }
110115}
111116
112117#[ derive( Debug ) ]
@@ -627,6 +632,34 @@ impl WorkflowsQuery {
627632 }
628633}
629634
635+ /// Information about the creator of a workflow.
636+ #[ derive( Debug , Clone , SimpleObject , Eq , PartialEq ) ]
637+ struct WorkflowCreator {
638+ /// An identifier unique to the creator of the workflow.
639+ /// Typically this is the creator's Fed-ID.
640+ creator_id : String ,
641+ }
642+
643+ impl WorkflowCreator {
644+ /// Creates a new [`WorkflowCreator`] from the given creator ID.
645+ fn new ( creator_id : impl Into < String > ) -> Self {
646+ Self {
647+ creator_id : creator_id. into ( ) ,
648+ }
649+ }
650+
651+ /// Builds a [`WorkflowCreator`] from Argo workflow labels.
652+ fn from_argo_workflow_labels ( labels : & HashMap < String , String > ) -> Self {
653+ let creator_id = labels
654+ . get ( "workflows.argoproj.io/creator-preferred-username" )
655+ . or_else ( || labels. get ( "workflows.argoproj.io/creator" ) )
656+ . cloned ( )
657+ . unwrap_or_default ( ) ;
658+
659+ Self :: new ( creator_id)
660+ }
661+ }
662+
630663#[ cfg( test) ]
631664mod tests {
632665 use crate :: graphql:: { root_schema_builder, Authorization , Bearer , Visit } ;
@@ -1557,4 +1590,56 @@ mod tests {
15571590 } ) ;
15581591 assert_eq ! ( resp. data. into_json( ) . unwrap( ) , expected_data) ;
15591592 }
1593+
1594+ #[ tokio:: test]
1595+ async fn workflow_creator ( ) {
1596+ let workflow_name = "numpy-benchmark-wdkwj" ;
1597+ let visit = Visit {
1598+ proposal_code : "mg" . to_string ( ) ,
1599+ proposal_number : 36964 ,
1600+ number : 1 ,
1601+ } ;
1602+
1603+ let mut server = mockito:: Server :: new_async ( ) . await ;
1604+ let mut response_file_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
1605+ response_file_path. push ( "test-assets" ) ;
1606+ response_file_path. push ( "get-workflow-wdkwj.json" ) ;
1607+ let workflow_endpoint = server
1608+ . mock (
1609+ "GET" ,
1610+ & format ! ( "/api/v1/workflows/{visit}/{workflow_name}" ) [ ..] ,
1611+ )
1612+ . with_status ( 200 )
1613+ . with_header ( "content-type" , "application/json" )
1614+ . with_body_from_file ( response_file_path)
1615+ . create_async ( )
1616+ . await ;
1617+
1618+ let argo_server_url = Url :: parse ( & server. url ( ) ) . unwrap ( ) ;
1619+ let schema = root_schema_builder ( )
1620+ . data ( ArgoServerUrl ( argo_server_url) )
1621+ . data ( None :: < Authorization < Bearer > > )
1622+ . finish ( ) ;
1623+ let query = format ! (
1624+ r#"
1625+ query {{
1626+ workflow(name: "{}", visit: {{proposalCode: "{}", proposalNumber: {}, number: {}}}) {{
1627+ creator {{ creatorId }}
1628+ }}
1629+ }}
1630+ "# ,
1631+ workflow_name, visit. proposal_code, visit. proposal_number, visit. number
1632+ ) ;
1633+ let resp = schema. execute ( query) . await . into_result ( ) . unwrap ( ) ;
1634+
1635+ workflow_endpoint. assert_async ( ) . await ;
1636+ let expected_data = json ! ( {
1637+ "workflow" : {
1638+ "creator" : {
1639+ "creatorId" : "enu43627" ,
1640+ }
1641+ }
1642+ } ) ;
1643+ assert_eq ! ( resp. data. into_json( ) . unwrap( ) , expected_data) ;
1644+ }
15601645}
0 commit comments