Skip to content

Commit 0300ad4

Browse files
committed
add
1 parent 194c1c1 commit 0300ad4

File tree

3 files changed

+181
-69
lines changed

3 files changed

+181
-69
lines changed

src/code2skill/api.py

Lines changed: 106 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,35 @@ def create_scan_config(
8080
)
8181

8282

83-
def scan(
84-
repo_path: Path | str = ".",
83+
def _create_scan_config_from_namespace(args) -> ScanConfig:
84+
return create_scan_config(
85+
repo_path=args.repo_path,
86+
command=args.command,
87+
output_dir=args.output_dir,
88+
mode=args.mode,
89+
base_ref=getattr(args, "base_ref", None),
90+
head_ref=getattr(args, "head_ref", "HEAD"),
91+
diff_file=getattr(args, "diff_file", None),
92+
report_path=getattr(args, "report_json", None),
93+
pricing_file=getattr(args, "pricing_file", None),
94+
structure_only=getattr(args, "structure_only", False),
95+
llm_provider=getattr(args, "llm", "openai"),
96+
llm_model=getattr(args, "model", None),
97+
max_skills=getattr(args, "max_skills", 8),
98+
max_files=args.max_files,
99+
max_file_size_kb=args.max_file_size_kb,
100+
max_total_chars=args.max_total_chars,
101+
max_incremental_changed_files=getattr(args, "max_incremental_changed_files", 64),
102+
)
103+
104+
105+
def _run_with_scan_config(
85106
*,
107+
runner,
108+
repo_path: Path | str,
109+
command: CommandName,
86110
output_dir: Path | str = ".code2skill",
87-
mode: Literal["full", "incremental"] = "full",
111+
mode: ModeName | None = None,
88112
base_ref: str | None = None,
89113
head_ref: str = "HEAD",
90114
diff_file: Path | str | None = None,
@@ -99,12 +123,10 @@ def scan(
99123
max_total_chars: int = 120000,
100124
max_incremental_changed_files: int = 64,
101125
):
102-
from .application import run_scan
103-
104-
return run_scan(
126+
return runner(
105127
create_scan_config(
106128
repo_path=repo_path,
107-
command="scan",
129+
command=command,
108130
output_dir=output_dir,
109131
mode=mode,
110132
base_ref=base_ref,
@@ -124,6 +146,49 @@ def scan(
124146
)
125147

126148

149+
def scan(
150+
repo_path: Path | str = ".",
151+
*,
152+
output_dir: Path | str = ".code2skill",
153+
mode: Literal["full", "incremental"] = "full",
154+
base_ref: str | None = None,
155+
head_ref: str = "HEAD",
156+
diff_file: Path | str | None = None,
157+
report_path: Path | str | None = None,
158+
pricing_file: Path | str | None = None,
159+
structure_only: bool = False,
160+
llm_provider: LLMProvider = "openai",
161+
llm_model: str | None = None,
162+
max_skills: int = 8,
163+
max_files: int = 40,
164+
max_file_size_kb: int = 256,
165+
max_total_chars: int = 120000,
166+
max_incremental_changed_files: int = 64,
167+
):
168+
from .application import run_scan
169+
170+
return _run_with_scan_config(
171+
runner=run_scan,
172+
repo_path=repo_path,
173+
command="scan",
174+
output_dir=output_dir,
175+
mode=mode,
176+
base_ref=base_ref,
177+
head_ref=head_ref,
178+
diff_file=diff_file,
179+
report_path=report_path,
180+
pricing_file=pricing_file,
181+
structure_only=structure_only,
182+
llm_provider=llm_provider,
183+
llm_model=llm_model,
184+
max_skills=max_skills,
185+
max_files=max_files,
186+
max_file_size_kb=max_file_size_kb,
187+
max_total_chars=max_total_chars,
188+
max_incremental_changed_files=max_incremental_changed_files,
189+
)
190+
191+
127192
def estimate(
128193
repo_path: Path | str = ".",
129194
*,
@@ -141,22 +206,21 @@ def estimate(
141206
):
142207
from .application import run_estimate
143208

144-
return run_estimate(
145-
create_scan_config(
146-
repo_path=repo_path,
147-
command="estimate",
148-
output_dir=output_dir,
149-
mode=mode,
150-
base_ref=base_ref,
151-
head_ref=head_ref,
152-
diff_file=diff_file,
153-
report_path=report_path,
154-
pricing_file=pricing_file,
155-
max_files=max_files,
156-
max_file_size_kb=max_file_size_kb,
157-
max_total_chars=max_total_chars,
158-
max_incremental_changed_files=max_incremental_changed_files,
159-
)
209+
return _run_with_scan_config(
210+
runner=run_estimate,
211+
repo_path=repo_path,
212+
command="estimate",
213+
output_dir=output_dir,
214+
mode=mode,
215+
base_ref=base_ref,
216+
head_ref=head_ref,
217+
diff_file=diff_file,
218+
report_path=report_path,
219+
pricing_file=pricing_file,
220+
max_files=max_files,
221+
max_file_size_kb=max_file_size_kb,
222+
max_total_chars=max_total_chars,
223+
max_incremental_changed_files=max_incremental_changed_files,
160224
)
161225

162226

@@ -181,26 +245,25 @@ def run_ci(
181245
):
182246
from .application import run_ci as run_ci_application
183247

184-
return run_ci_application(
185-
create_scan_config(
186-
repo_path=repo_path,
187-
command="ci",
188-
output_dir=output_dir,
189-
mode=mode,
190-
base_ref=base_ref,
191-
head_ref=head_ref,
192-
diff_file=diff_file,
193-
report_path=report_path,
194-
pricing_file=pricing_file,
195-
structure_only=structure_only,
196-
llm_provider=llm_provider,
197-
llm_model=llm_model,
198-
max_skills=max_skills,
199-
max_files=max_files,
200-
max_file_size_kb=max_file_size_kb,
201-
max_total_chars=max_total_chars,
202-
max_incremental_changed_files=max_incremental_changed_files,
203-
)
248+
return _run_with_scan_config(
249+
runner=run_ci_application,
250+
repo_path=repo_path,
251+
command="ci",
252+
output_dir=output_dir,
253+
mode=mode,
254+
base_ref=base_ref,
255+
head_ref=head_ref,
256+
diff_file=diff_file,
257+
report_path=report_path,
258+
pricing_file=pricing_file,
259+
structure_only=structure_only,
260+
llm_provider=llm_provider,
261+
llm_model=llm_model,
262+
max_skills=max_skills,
263+
max_files=max_files,
264+
max_file_size_kb=max_file_size_kb,
265+
max_total_chars=max_total_chars,
266+
max_incremental_changed_files=max_incremental_changed_files,
204267
)
205268

206269

src/code2skill/cli.py

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -264,31 +264,9 @@ def _add_skill_arguments(
264264

265265

266266
def _build_config(args):
267-
from .api import create_scan_config
268-
269-
return create_scan_config(
270-
repo_path=args.repo_path,
271-
command=args.command,
272-
output_dir=args.output_dir,
273-
mode=args.mode,
274-
base_ref=getattr(args, "base_ref", None),
275-
head_ref=getattr(args, "head_ref", "HEAD"),
276-
diff_file=getattr(args, "diff_file", None),
277-
report_path=getattr(args, "report_json", None),
278-
pricing_file=getattr(args, "pricing_file", None),
279-
structure_only=getattr(args, "structure_only", False),
280-
llm_provider=getattr(args, "llm", "openai"),
281-
llm_model=getattr(args, "model", None),
282-
max_skills=getattr(args, "max_skills", 8),
283-
max_files=args.max_files,
284-
max_file_size_kb=args.max_file_size_kb,
285-
max_total_chars=args.max_total_chars,
286-
max_incremental_changed_files=getattr(
287-
args,
288-
"max_incremental_changed_files",
289-
64,
290-
),
291-
)
267+
from .api import _create_scan_config_from_namespace
268+
269+
return _create_scan_config_from_namespace(args)
292270

293271

294272
def _print_command_summary(summary) -> None:

tests/test_api.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22

33
import json
44
from pathlib import Path
5+
from types import SimpleNamespace
56

67
from code2skill.capabilities.adapt.targets import get_target_definition
7-
from code2skill.api import adapt_repository, create_scan_config, estimate, run_ci, scan
8+
from code2skill.api import (
9+
_create_scan_config_from_namespace,
10+
_run_with_scan_config,
11+
adapt_repository,
12+
create_scan_config,
13+
estimate,
14+
run_ci,
15+
scan,
16+
)
817

918

1019
def test_create_scan_config_builds_repo_relative_defaults(tmp_path: Path) -> None:
@@ -94,6 +103,68 @@ def test_create_scan_config_resolves_relative_optional_paths_from_repo_root(
94103
assert config.run.pricing is not None
95104

96105

106+
def test_create_scan_config_from_namespace_reads_cli_shape(tmp_path: Path) -> None:
107+
repo_path = tmp_path / "repo"
108+
repo_path.mkdir()
109+
args = SimpleNamespace(
110+
repo_path=str(repo_path),
111+
command="ci",
112+
output_dir=".generated",
113+
mode="auto",
114+
base_ref="origin/main",
115+
head_ref="HEAD~1",
116+
diff_file="changes.diff",
117+
report_json="reports/report.json",
118+
pricing_file=None,
119+
structure_only=True,
120+
llm="qwen",
121+
model="qwen-plus-latest",
122+
max_skills=3,
123+
max_files=20,
124+
max_file_size_kb=128,
125+
max_total_chars=5000,
126+
max_incremental_changed_files=10,
127+
)
128+
129+
config = _create_scan_config_from_namespace(args)
130+
131+
assert config.repo_path == repo_path.resolve()
132+
assert config.output_dir == (repo_path / ".generated").resolve()
133+
assert config.run.base_ref == "origin/main"
134+
assert config.run.head_ref == "HEAD~1"
135+
assert config.run.diff_file == (repo_path / "changes.diff").resolve()
136+
assert config.run.report_path == (repo_path / "reports" / "report.json").resolve()
137+
assert config.run.structure_only is True
138+
assert config.run.llm_provider == "qwen"
139+
140+
141+
def test_run_with_scan_config_builds_config_once(monkeypatch, tmp_path: Path) -> None:
142+
repo_path = tmp_path / "repo"
143+
repo_path.mkdir()
144+
sentinel = object()
145+
captured: dict[str, object] = {}
146+
147+
def fake_runner(config):
148+
captured["config"] = config
149+
return sentinel
150+
151+
result = _run_with_scan_config(
152+
runner=fake_runner,
153+
repo_path=repo_path,
154+
command="scan",
155+
output_dir=".generated",
156+
llm_provider="qwen",
157+
llm_model="qwen-plus-latest",
158+
max_skills=2,
159+
)
160+
161+
assert result is sentinel
162+
config = captured["config"]
163+
assert config.run.command == "scan"
164+
assert config.run.llm_provider == "qwen"
165+
assert config.run.max_skills == 2
166+
167+
97168
def test_scan_shortcut_delegates_to_core_with_built_config(
98169
monkeypatch,
99170
tmp_path: Path,

0 commit comments

Comments
 (0)