1313# limitations under the License.
1414
1515import argparse
16+ import datetime as dt
17+ import os
18+ from collections .abc import Mapping
1619from pathlib import Path
1720
1821from ruamel .yaml import YAML
@@ -44,10 +47,30 @@ def seconds_to_time(seconds: int) -> str:
4447 return f"{ hours :02d} :{ minutes :02d} :{ secs :02d} "
4548
4649
50+ def _pipeline_timestamp (created_at : str | None ) -> str :
51+ """Return a path-safe UTC timestamp for generated nightly session names."""
52+ if created_at :
53+ try :
54+ parsed = dt .datetime .fromisoformat (created_at )
55+ return parsed .astimezone (dt .UTC ).strftime ("%Y_%m_%d__%H_%M_%S_UTC" )
56+ except ValueError :
57+ pass
58+ return dt .datetime .now (dt .UTC ).strftime ("%Y_%m_%d__%H_%M_%S_UTC" )
4759
48- def generate_job (
49- entry : dict , scope : str , default_timeout_s : int , cleanup_timeout_s : int , min_timeout_s : int
50- ) -> dict :
60+
61+ def session_name_from_env (env : Mapping [str , str ] = os .environ ) -> str | None :
62+ """Return the generated-pipeline session name, if this run should define one."""
63+ explicit = env .get ("NEMO_CI_SESSION_NAME" , "" ).strip ()
64+ if explicit :
65+ return explicit
66+
67+ if env .get ("CI_PIPELINE_SOURCE" ) == "schedule" or env .get ("PARENT_PIPELINE_SOURCE" ) == "schedule" :
68+ return f"nightly-{ _pipeline_timestamp (env .get ('CI_PIPELINE_CREATED_AT' ))} "
69+
70+ return None
71+
72+
73+ def generate_job (entry : dict , scope : str , default_timeout_s : int , cleanup_timeout_s : int , min_timeout_s : int ) -> dict :
5174 """
5275 Generate a GitLab CI job for a single benchmark entry.
5376
@@ -79,13 +102,14 @@ def generate_job(
79102 }
80103
81104
82- def generate_pipeline (curator_dir : str , scope : str ) -> dict :
105+ def generate_pipeline (curator_dir : str , scope : str , session_name : str | None = None ) -> dict :
83106 """
84107 Generate a GitLab CI pipeline from Curator benchmark entries.
85108
86109 Args:
87110 curator_dir: Path to the Curator repository
88111 scope: Scope of the testing (nightly, release, test)
112+ session_name: Optional session name to set for all generated benchmark jobs
89113
90114 Returns:
91115 pipeline: Dictionary defining the GitLab CI pipeline
@@ -104,6 +128,8 @@ def generate_pipeline(curator_dir: str, scope: str) -> dict:
104128 pipeline = {
105129 "include" : ["curator/curator_ci_template.yml" ],
106130 }
131+ if session_name :
132+ pipeline ["variables" ] = {"NEMO_CI_SESSION_NAME" : session_name }
107133
108134 entries = config .get ("entries" , [])
109135 job_count = 0
@@ -122,9 +148,7 @@ def generate_pipeline(curator_dir: str, scope: str) -> dict:
122148
123149
124150def main () -> None :
125- parser = argparse .ArgumentParser (
126- description = "Generate GitLab CI jobs for Curator benchmarks"
127- )
151+ parser = argparse .ArgumentParser (description = "Generate GitLab CI jobs for Curator benchmarks" )
128152 parser .add_argument (
129153 "--curator-dir" ,
130154 type = str ,
@@ -140,14 +164,17 @@ def main() -> None:
140164
141165 args = parser .parse_args ()
142166
143- pipeline = generate_pipeline (args .curator_dir , args .scope )
167+ session_name = session_name_from_env ()
168+ pipeline = generate_pipeline (args .curator_dir , args .scope , session_name = session_name )
144169
145170 output_file = "generated_curator_benchmark_tests.yml"
146171 with open (output_file , "w" ) as f :
147172 yaml .dump (pipeline , f )
148173
149- job_count = len ([k for k in pipeline if k != "include" ])
174+ job_count = len ([k for k in pipeline if k not in { "include" , "variables" } ])
150175 print (f"Generated pipeline with { job_count } jobs -> { output_file } " )
176+ if session_name :
177+ print (f"Using benchmark session name: { session_name } " )
151178
152179
153180if __name__ == "__main__" :
0 commit comments