1010import commit0 .harness .lint
1111import commit0 .harness .save
1212from commit0 .harness .constants import SPLIT , SPLIT_ALL
13+ import subprocess
14+ import yaml
1315
14- app = typer .Typer (add_completion = False )
16+ commit0_app = typer .Typer (
17+ no_args_is_help = True ,
18+ add_completion = False ,
19+ context_settings = {"help_option_names" : ["-h" , "--help" ]},
20+ help = """
21+ Commit-0 is a real-world AI coding challenge. Can your agent generate a working library from commit 0?
22+
23+ See the website at https://commit-0.github.io/ for documentation and more information about Commit-0.
24+ """ ,
25+ )
1526
1627
1728class Colors :
@@ -22,6 +33,40 @@ class Colors:
2233 ORANGE = "\033 [95m"
2334
2435
36+ def check_commit0_path () -> None :
37+ """Code adapted from https://github.com/modal-labs/modal-client/blob/a8ddd418f8c65b7e168a9125451eeb70da2b6203/modal/cli/entry_point.py#L55
38+
39+ Checks whether the `commit0` executable is on the path and usable.
40+ """
41+ url = "https://commit-0.github.io/setup/"
42+ try :
43+ subprocess .run (["commit0" , "--help" ], capture_output = True )
44+ # TODO(erikbern): check returncode?
45+ return
46+ except FileNotFoundError :
47+ typer .echo (
48+ typer .style (
49+ "The `commit0` command was not found on your path!" , fg = typer .colors .RED
50+ )
51+ + "\n "
52+ + typer .style (
53+ "You may need to add it to your path or use `python -m commit0` as a workaround." ,
54+ fg = typer .colors .RED ,
55+ )
56+ )
57+ except PermissionError :
58+ typer .echo (
59+ typer .style ("The `commit0` command is not executable!" , fg = typer .colors .RED )
60+ + "\n "
61+ + typer .style (
62+ "You may need to give it permissions or use `python -m commit0` as a workaround." ,
63+ fg = typer .colors .RED ,
64+ )
65+ )
66+ typer .echo (f"See more information here:\n \n { url } " )
67+ typer .echo ("─" * 80 ) # Simple rule to separate content
68+
69+
2570def highlight (text : str , color : str ) -> str :
2671 """Highlight text with a color."""
2772 return f"{ color } { text } { Colors .RESET } "
@@ -38,7 +83,17 @@ def check_valid(one: str, total: Union[list[str], dict[str, list[str]]]) -> None
3883 )
3984
4085
41- @app .command ()
86+ def write_commit0_dot_file (dot_file_path : str , config : dict ) -> None :
87+ with open (dot_file_path , "w" ) as f :
88+ yaml .dump (config , f , default_flow_style = False )
89+
90+
91+ def read_commit0_dot_file (dot_file_path : str ) -> dict :
92+ with open (dot_file_path , "r" ) as f :
93+ return yaml .load (f , Loader = yaml .FullLoader )
94+
95+
96+ @commit0_app .command ()
4297def setup (
4398 repo_split : str = typer .Argument (
4499 ...,
@@ -49,14 +104,21 @@ def setup(
49104 ),
50105 dataset_split : str = typer .Option ("test" , help = "Split of the Huggingface dataset" ),
51106 base_dir : str = typer .Option ("repos/" , help = "Base directory to clone repos to" ),
107+ commit0_dot_file_path : str = typer .Option (
108+ ".commit0.yaml" , help = "Storing path for stateful commit0 configs"
109+ ),
52110) -> None :
53111 """Commit0 clone a repo split."""
112+ check_commit0_path ()
54113 check_valid (repo_split , SPLIT )
55114
56- typer .echo (f"Cloning repository for split: { repo_split } " )
57- typer .echo (f"Dataset name: { dataset_name } " )
58- typer .echo (f"Dataset split: { dataset_split } " )
59- typer .echo (f"Base directory: { base_dir } " )
115+ base_dir = str (Path (base_dir ).resolve ())
116+
117+ typer .echo (f"Cloning repository for split: { highlight (repo_split , Colors .ORANGE )} " )
118+ typer .echo (f"Dataset name: { highlight (dataset_name , Colors .ORANGE )} " )
119+ typer .echo (f"Dataset split: { highlight (dataset_split , Colors .ORANGE )} " )
120+ typer .echo (f"Base directory: { highlight (base_dir , Colors .ORANGE )} " )
121+ typer .echo (f"Commit0 dot file path: { highlight (commit0_dot_file_path , Colors .ORANGE )} " )
60122
61123 commit0 .harness .setup .main (
62124 dataset_name ,
@@ -65,51 +127,62 @@ def setup(
65127 base_dir ,
66128 )
67129
130+ # after successfully setup, write the commit0 dot file
131+ write_commit0_dot_file (
132+ commit0_dot_file_path ,
133+ {
134+ "dataset_name" : dataset_name ,
135+ "dataset_split" : dataset_split ,
136+ "repo_split" : repo_split ,
137+ "base_dir" : base_dir ,
138+ },
139+ )
140+
68141
69- @app .command ()
142+ @commit0_app .command ()
70143def build (
71- repo_split : str = typer .Argument (
72- ...,
73- help = f"Split of repositories, one of { ', ' .join (highlight (key , Colors .ORANGE ) for key in SPLIT .keys ())} " ,
74- ),
75- dataset_name : str = typer .Option (
76- "wentingzhao/commit0_docstring" , help = "Name of the Huggingface dataset"
77- ),
78- dataset_split : str = typer .Option ("test" , help = "Split of the Huggingface dataset" ),
79144 num_workers : int = typer .Option (8 , help = "Number of workers" ),
145+ commit0_dot_file_path : str = typer .Option (
146+ ".commit0.yaml" ,
147+ help = "Path to the commit0 dot file, where the setup config is stored" ,
148+ ),
80149) -> None :
81- """Commit0 build a repository ."""
82- check_valid ( repo_split , SPLIT )
150+ """Build Commit0 split you choose in Setup Stage ."""
151+ check_commit0_path ( )
83152
84- typer .echo (f"Building repository for split: { repo_split } " )
85- typer .echo (f"Dataset name: { dataset_name } " )
86- typer .echo (f"Dataset split: { dataset_split } " )
87- typer .echo (f"Number of workers: { num_workers } " )
153+ commit0_config = read_commit0_dot_file (commit0_dot_file_path )
154+ check_valid (commit0_config ["repo_split" ], SPLIT )
155+
156+ typer .echo (f"Building repository for split: { highlight (commit0_config ['repo_split' ], Colors .ORANGE )} " )
157+ typer .echo (f"Dataset name: { highlight (commit0_config ['dataset_name' ], Colors .ORANGE )} " )
158+ typer .echo (f"Dataset split: { highlight (commit0_config ['dataset_split' ], Colors .ORANGE )} " )
159+ typer .echo (f"Number of workers: { highlight (str (num_workers ), Colors .ORANGE )} " )
88160
89161 commit0 .harness .build .main (
90- dataset_name ,
91- dataset_split ,
92- repo_split ,
162+ commit0_config [ " dataset_name" ] ,
163+ commit0_config [ " dataset_split" ] ,
164+ commit0_config [ " repo_split" ] ,
93165 num_workers ,
94166 )
95167
96168
97- @app .command ()
169+ @commit0_app .command ()
98170def get_tests (
99171 repo_name : str = typer .Argument (
100172 ...,
101173 help = f"Name of the repository to get tests for, one of: { ', ' .join (highlight (key , Colors .ORANGE ) for key in SPLIT_ALL )} " ,
102174 ),
103175) -> None :
104176 """Get tests for a Commit0 repository."""
177+ check_commit0_path ()
105178 check_valid (repo_name , SPLIT_ALL )
106179
107180 typer .echo (f"Getting tests for repository: { repo_name } " )
108181
109182 commit0 .harness .get_pytest_ids .main (repo_name , stdout = True )
110183
111184
112- @app .command ()
185+ @commit0_app .command ()
113186def test (
114187 repo_or_repo_path : str = typer .Argument (
115188 ..., help = "Directory of the repository to test"
@@ -121,22 +194,25 @@ def test(
121194 branch : Union [str , None ] = typer .Option (
122195 None , help = "Branch to test (branch MUST be provided or use --reference)"
123196 ),
124- dataset_name : str = typer .Option (
125- "wentingzhao/commit0_docstring" , help = "Name of the Huggingface dataset"
126- ),
127- dataset_split : str = typer .Option ("test" , help = "Split of the Huggingface dataset" ),
128- base_dir : str = typer .Option ("repos/" , help = "Base directory of repos" ),
129197 backend : str = typer .Option ("local" , help = "Backend to use for testing" ),
130198 timeout : int = typer .Option (1800 , help = "Timeout for tests in seconds" ),
131199 num_cpus : int = typer .Option (1 , help = "Number of CPUs to use" ),
132200 reference : Annotated [
133201 bool , typer .Option ("--reference" , help = "Test the reference commit." )
134202 ] = False ,
203+ commit0_dot_file_path : str = typer .Option (
204+ ".commit0.yaml" ,
205+ help = "Path to the commit0 dot file, where the setup config is stored" ,
206+ ),
135207) -> None :
136208 """Run tests on a Commit0 repository."""
209+ check_commit0_path ()
137210 if repo_or_repo_path .endswith ("/" ):
138211 repo_or_repo_path = repo_or_repo_path [:- 1 ]
139212 check_valid (repo_or_repo_path .split ("/" )[- 1 ], SPLIT_ALL )
213+
214+ commit0_config = read_commit0_dot_file (commit0_dot_file_path )
215+
140216 if not branch and not reference :
141217 raise typer .BadParameter (
142218 f"Invalid { highlight ('BRANCH' , Colors .RED )} . Either --reference or provide a branch name." ,
@@ -151,9 +227,9 @@ def test(
151227 typer .echo (f"Test IDs: { test_ids } " )
152228
153229 commit0 .harness .run_pytest_ids .main (
154- dataset_name ,
155- dataset_split ,
156- base_dir ,
230+ commit0_config [ " dataset_name" ] ,
231+ commit0_config [ " dataset_split" ] ,
232+ commit0_config [ " base_dir" ] ,
157233 repo_or_repo_path ,
158234 branch ,
159235 test_ids ,
@@ -164,29 +240,25 @@ def test(
164240 )
165241
166242
167- @app .command ()
243+ @commit0_app .command ()
168244def evaluate (
169- repo_split : str = typer .Argument (
170- ...,
171- help = f"Split of repositories, one of { ', ' .join (highlight (key , Colors .ORANGE ) for key in SPLIT .keys ())} " ,
172- ),
173245 branch : Union [str , None ] = typer .Option (
174246 None , help = "Branch to evaluate (branch MUST be provided or use --reference)"
175247 ),
176- dataset_name : str = typer .Option (
177- "wentingzhao/commit0_docstring" , help = "Name of the Huggingface dataset"
178- ),
179- dataset_split : str = typer .Option ("test" , help = "Split of the Huggingface dataset" ),
180- base_dir : str = typer .Option ("repos/" , help = "Base directory of repos" ),
181248 backend : str = typer .Option ("local" , help = "Backend to use for evaluation" ),
182249 timeout : int = typer .Option (1800 , help = "Timeout for evaluation in seconds" ),
183250 num_cpus : int = typer .Option (1 , help = "Number of CPUs to use" ),
184251 num_workers : int = typer .Option (8 , help = "Number of workers to use" ),
185252 reference : Annotated [
186253 bool , typer .Option ("--reference" , help = "Evaluate the reference commit." )
187254 ] = False ,
255+ commit0_dot_file_path : str = typer .Option (
256+ ".commit0.yaml" ,
257+ help = "Path to the commit0 dot file, where the setup config is stored" ,
258+ ),
188259) -> None :
189- """Evaluate a Commit0 repository."""
260+ """Evaluate Commit0 split you choose in Setup Stage."""
261+ check_commit0_path ()
190262 if not branch and not reference :
191263 raise typer .BadParameter (
192264 f"Invalid { highlight ('BRANCH' , Colors .RED )} . Either --reference or provide a branch name" ,
@@ -196,16 +268,17 @@ def evaluate(
196268 branch = "reference"
197269 assert branch is not None , "branch is not specified"
198270
199- check_valid (repo_split , SPLIT )
271+ commit0_config = read_commit0_dot_file (commit0_dot_file_path )
272+ check_valid (commit0_config ["repo_split" ], SPLIT )
200273
201- typer .echo (f"Evaluating repository split: { repo_split } " )
274+ typer .echo (f"Evaluating repository split: { commit0_config [ ' repo_split' ] } " )
202275 typer .echo (f"Branch: { branch } " )
203276
204277 commit0 .harness .evaluate .main (
205- dataset_name ,
206- dataset_split ,
207- repo_split ,
208- base_dir ,
278+ commit0_config [ " dataset_name" ] ,
279+ commit0_config [ " dataset_split" ] ,
280+ commit0_config [ " repo_split" ] ,
281+ commit0_config [ " base_dir" ] ,
209282 branch ,
210283 backend ,
211284 timeout ,
@@ -214,14 +287,12 @@ def evaluate(
214287 )
215288
216289
217- @app .command ()
290+ @commit0_app .command ()
218291def lint (
219- files : List [Path ] = typer .Argument (
220- ..., help = "Files to lint. If not provided, all files will be linted."
221- ),
292+ files : List [Path ] = typer .Argument (..., help = "Files to lint." ),
222293) -> None :
223294 """Lint given files if provided, otherwise lint all files in the base directory."""
224- assert len ( files ) > 0 , "No files to lint."
295+ check_commit0_path ()
225296 for path in files :
226297 if not path .is_file ():
227298 raise FileNotFoundError (f"File not found: { str (path )} " )
@@ -231,33 +302,30 @@ def lint(
231302 commit0 .harness .lint .main (files )
232303
233304
234- @app .command ()
305+ @commit0_app .command ()
235306def save (
236- repo_split : str = typer .Argument (
237- ...,
238- help = f"Split of the repository, one of { ', ' .join (highlight (key , Colors .ORANGE ) for key in SPLIT .keys ())} " ,
239- ),
240307 owner : str = typer .Argument (..., help = "Owner of the repository" ),
241308 branch : str = typer .Argument (..., help = "Branch to save" ),
242- dataset_name : str = typer .Option (
243- "wentingzhao/commit0_docstring" , help = "Name of the Huggingface dataset"
244- ),
245- dataset_split : str = typer .Option ("test" , help = "Split of the Huggingface dataset" ),
246- base_dir : str = typer .Option ("repos/" , help = "Base directory of repos" ),
247309 github_token : str = typer .Option (None , help = "GitHub token for authentication" ),
310+ commit0_dot_file_path : str = typer .Option (
311+ ".commit0.yaml" ,
312+ help = "Path to the commit0 dot file, where the setup config is stored" ,
313+ ),
248314) -> None :
249- """Save a Commit0 repository to GitHub."""
250- check_valid (repo_split , SPLIT )
315+ """Save Commit0 split you choose in Setup Stage to GitHub."""
316+ check_commit0_path ()
317+ commit0_config = read_commit0_dot_file (commit0_dot_file_path )
318+ check_valid (commit0_config ["repo_split" ], SPLIT )
251319
252- typer .echo (f"Saving repository split: { repo_split } " )
320+ typer .echo (f"Saving repository split: { commit0_config [ ' repo_split' ] } " )
253321 typer .echo (f"Owner: { owner } " )
254322 typer .echo (f"Branch: { branch } " )
255323
256324 commit0 .harness .save .main (
257- dataset_name ,
258- dataset_split ,
259- repo_split ,
260- base_dir ,
325+ commit0_config [ " dataset_name" ] ,
326+ commit0_config [ " dataset_split" ] ,
327+ commit0_config [ " repo_split" ] ,
328+ commit0_config [ " base_dir" ] ,
261329 owner ,
262330 branch ,
263331 github_token ,
0 commit comments