Skip to content

Commit 4e60785

Browse files
committed
add .commit.yaml
1 parent 13a68c9 commit 4e60785

File tree

3 files changed

+144
-75
lines changed

3 files changed

+144
-75
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,5 @@ cython_debug/
164164
logs/
165165
repos/
166166
config.yml
167-
hydra_outputs/
167+
hydra_outputs/
168+
.commit0*

commit0/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from commit0.cli import app as commit0_app
1+
from commit0.cli import commit0_app
22

33

44
def main() -> None:

commit0/cli.py

Lines changed: 141 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,19 @@
1010
import commit0.harness.lint
1111
import commit0.harness.save
1212
from 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

1728
class 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+
2570
def 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()
4297
def 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()
70143
def 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()
98170
def 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()
113186
def 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()
168244
def 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()
218291
def 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()
235306
def 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

Comments
 (0)