Skip to content

Commit 99dccc4

Browse files
committed
接通Python独立文档检查与原Ruff任务复检
1 parent 5216432 commit 99dccc4

28 files changed

Lines changed: 26058 additions & 70 deletions

‎README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,3 +1104,10 @@ Native Clippy documentation findings now receive specific Errors/Panics/Safety r
11041104
Cargo documentation discovery now records manifest levels for five exact native lints per build root, bound to the observed manifest digest. Inheritance, groups, source attributes and absent declarations remain unresolved. Initialization stores details in the profile and retains AGENTS summaries/references; it does not add rules or qualify detailed documentation. See [declaration acceptance](tests/acceptance/cargo-documentation-declarations.md).
11051105

11061106
Cargo documentation discovery now associates an opted-in member with its nearest observed workspace lint declarations, retaining both manifest identities and the original member configuration reference. Unreadable or changed candidates are incomplete; nearer invalid/missing rules are not replaced with farther rules. Project-local portable relative package.workspace references now select only their declared source, with bounded traversal and digest checks; absolute/nonportable references and full membership/effective coverage remain unresolved. This candidate association grants no production qualification.
1107+
1108+
1109+
### Partial standalone Python documentation entry
1110+
1111+
`codeguard comments python . --ruff-tool /absolute/path/to/ruff --format=json` reuses project-configured native Ruff and returns `python_comments_feedback` 0.1. `native_report` retains the complete sanitized 0.12 native conversation report. Top-level `documentation_findings` selects existing D### observations and seven explicitly mapped DOC rules; top-level `next` retains current and historical documentation tasks and preparation blockers. Other convention findings remain in the native child report. Zero diagnostics do not qualify detailed comments: documentation rule coverage stays `unverified`, detailed contract qualification stays `not_granted`, and the overall exit is 3. Missing configuration creates preparation work. It does not enable preview, modify configuration or substitute WASM for documentation checks. Initialized projects reuse stable tasks and original-tool `task verify`; native facts are not closed automatically.
1112+
1113+
See [standalone entry and actual Ruff acceptance](tests/acceptance/python-comments-cli.md).

‎README.zh-CN.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,3 +1081,10 @@ Rust 的详细文档任务现对原生 Clippy `missing_errors_doc`、`missing_pa
10811081
Cargo 文档配置现在逐构建根记录五项精确 lint 的清单声明等级,绑定同次摘要;继承、组、源码属性和未声明均保留待核验。`init` 将详情写入项目画像,AGENTS 保留摘要与引用,不自行添加规则或授予详细文档合格。见[声明验收](tests/acceptance/cargo-documentation-declarations.md)。
10821082

10831083
Cargo文档配置发现现可将明确选择继承的成员与最近已观察workspace规则关联,保留两份清单身份及原成员配置引用;候选不可读或变化保持发现不完整,最近规则缺失/非法不能借用更远规则。项目内便携相对package.workspace引用现只选择声明来源并核验有界遍历及摘要;绝对/非便携引用、完整成员归属与生效覆盖仍待核验,这项候选关联不授予生产资格。
1084+
1085+
1086+
### Python 独立文档入口的局部能力
1087+
1088+
`codeguard comments python . --ruff-tool /absolute/path/to/ruff --format=json` 复用项目原 Ruff 配置和原工具检查,返回 `python_comments_feedback` 0.1。`native_report` 保留完整脱敏原生0.12对话报告;顶层 `documentation_findings` 仅取已有D###和七项明确DOC规则,顶层 `next` 保留当前及历史文档任务与准备任务,其他开发规范问题仍保留在原生子报告。零诊断不等于详细注释合格:规则覆盖固定 `unverified`,详细契约资格固定 `not_granted`,整体退出3。缺配置生成准备任务;不会开启preview、改配置或用WASM代替文档检查。已初始化项目沿用稳定任务和 `task verify` 原工具复检,原事实不自动关闭。
1089+
1090+
参见 [独立入口与真实Ruff验收](tests/acceptance/python-comments-cli.md)。

‎crates/codeguard-cli/src/command_catalogue.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ pub(crate) fn descriptors() -> Vec<CommandDescriptor> {
234234
},
235235
executable: cfg!(unix),
236236
operation_kind: r#"check"#,
237-
usage: r#"comments <rust|java> [path] [--timeout DURATION] [--format human|json]"#,
238-
scope: r#"Rust库文档与Java文件/项目Javadoc探针;完整文档政策与闭环尚缺"#,
239-
languages: &[r#"rust"#, r#"java"#],
237+
usage: r#"comments <rust|java|python> [path] [--timeout DURATION] [--format human|json]"#,
238+
scope: r#"Rust双原生、Java文件/项目Javadoc、Python原配置Ruff文档观察;完整政策与闭环尚缺"#,
239+
languages: &[r#"rust"#, r#"java"#, r#"python"#],
240240
},
241241
CommandDescriptor {
242242
tracking_id: Some(r#"C16"#),

‎crates/codeguard-cli/src/command_examples.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) fn examples(command: &str) -> &'static [&'static str] {
2323
"codeguard comments java File.java --workspace . --java-home /absolute/jdk21 --format json",
2424
"codeguard comments java . --java-home /absolute/jdk21 --maven-tool /absolute/mvn --maven-repo /absolute/repository --repo-sha256 SHA256 --format json",
2525
"codeguard comments rust . --cargo-tool /absolute/cargo --format json",
26+
"codeguard comments python . --ruff-tool /absolute/ruff --format json",
2627
],
2728
"task verify" => &[
2829
"codeguard task verify TASK_ID . --java-home /absolute/jdk21 --format json",

‎crates/codeguard-cli/src/lib.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,3 +534,8 @@ pub mod gradle_cve_workbench;
534534

535535
#[cfg(unix)]
536536
pub mod gradle_cve_task_recheck;
537+
538+
#[cfg(unix)]
539+
mod python_comments_arguments;
540+
#[cfg(unix)]
541+
pub mod python_comments_command;

‎crates/codeguard-cli/src/main.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ fn main() -> ExitCode {
5555
codeguard_cli::syntax_worker_command::run(rest)
5656
}
5757
#[cfg(unix)]
58+
[command, language, rest @ ..] if command == "comments" && language == "python" => {
59+
codeguard_cli::python_comments_command::run(rest)
60+
}
61+
#[cfg(unix)]
5862
[command, language, rest @ ..] if command == "comments" && language == "java" => {
5963
codeguard_cli::java_comments_command::run(rest)
6064
}

‎crates/codeguard-cli/src/next_command.rs‎

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,22 @@ pub(crate) fn read_local_brief_for_checkers(
112112
}
113113

114114
/// 选择当前或历史开放的 Rust 文档任务;保留准备任务,不借用其它 Clippy 规则。
115+
#[cfg(unix)]
115116
pub(crate) fn read_rust_documentation_brief(root: &Path) -> Result<Value, &'static str> {
116117
build_filtered_view(
117118
root,
118119
Some(&["rust.cargo_rustdoc", "rust.cargo_clippy"]),
119120
None,
120-
true,
121+
Some("rust"),
121122
)
122123
}
123124

125+
/// 选择当前或历史开放的 Python 文档任务;复用原 Ruff 原生规则分类和准备任务。
126+
#[cfg(unix)]
127+
pub(crate) fn read_python_documentation_brief(root: &Path) -> Result<Value, &'static str> {
128+
build_filtered_view(root, Some(&["python.ruff"]), None, Some("python"))
129+
}
130+
124131
/// 从本轮已同步的任务身份读取下一步;返回既有 next 协议,不扩大到其它历史任务。
125132
pub(crate) fn read_local_brief_for_tasks(
126133
root: &Path,
@@ -197,14 +204,14 @@ fn build_view(
197204
checker_ids: Option<&[&str]>,
198205
task_ids: Option<&std::collections::BTreeSet<String>>,
199206
) -> Result<Value, &'static str> {
200-
build_filtered_view(root, checker_ids, task_ids, false)
207+
build_filtered_view(root, checker_ids, task_ids, None)
201208
}
202209

203210
fn build_filtered_view(
204211
root: &Path,
205212
checker_ids: Option<&[&str]>,
206213
task_ids: Option<&std::collections::BTreeSet<String>>,
207-
rust_documentation_only: bool,
214+
documentation_language: Option<&str>,
208215
) -> Result<Value, &'static str> {
209216
let baseline = read_workspace_baseline(root).map_err(|reason| {
210217
if reason == "legacy_workspace_requires_manual_migration" {
@@ -287,17 +294,25 @@ fn build_filtered_view(
287294
.iter()
288295
.any(|checker| candidate.brief["checker_id"] == *checker)
289296
}) && task_ids.is_none_or(|ids| ids.contains(&candidate.id))
290-
&& (!rust_documentation_only
291-
|| candidate.brief["kind"] == "blocker"
292-
|| candidate.brief["checker_id"] == "rust.cargo_rustdoc"
293-
|| matches!(
294-
candidate.brief["native_rule_id"].as_str(),
295-
Some(
296-
"clippy::missing_errors_doc"
297-
| "clippy::missing_panics_doc"
298-
| "clippy::missing_safety_doc"
299-
)
300-
))
297+
&& match documentation_language {
298+
None => true,
299+
Some(_) if candidate.brief["kind"] == "blocker" => true,
300+
Some("rust") => {
301+
candidate.brief["checker_id"] == "rust.cargo_rustdoc"
302+
|| matches!(
303+
candidate.brief["native_rule_id"].as_str(),
304+
Some(
305+
"clippy::missing_errors_doc"
306+
| "clippy::missing_panics_doc"
307+
| "clippy::missing_safety_doc"
308+
)
309+
)
310+
}
311+
Some("python") => candidate.brief["native_rule_id"]
312+
.as_str()
313+
.is_some_and(codeguard_adapters::is_ruff_documentation_rule),
314+
Some(_) => false,
315+
}
301316
{
302317
candidates.push(candidate);
303318
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use std::path::PathBuf;
2+
3+
/// Python 项目注释入口参数;不隐式选择规则或改写项目配置。
4+
pub(crate) struct PythonCommentsArguments {
5+
pub root: PathBuf,
6+
pub tool: Option<PathBuf>,
7+
pub json: bool,
8+
pub timeout: Option<u64>,
9+
}
10+
impl PythonCommentsArguments {
11+
/// 解析语种后 argv,返回根目录、工具与预算;非法参数在执行工具前拒绝。
12+
pub fn parse(args: &[String]) -> Result<Self, String> {
13+
let (mut root, mut tool, mut format, mut timeout) = (None, None, None, None);
14+
let mut index = 0;
15+
while index < args.len() {
16+
let word = args[index].as_str();
17+
let (key, value) = if word.starts_with("--") && word.contains('=') {
18+
word.split_once('=').expect("已经确认赋值分隔符")
19+
} else if matches!(word, "--ruff-tool" | "--format" | "--timeout") {
20+
index += 1;
21+
(word, args.get(index).ok_or("参数缺少值")?.as_str())
22+
} else {
23+
(word, "")
24+
};
25+
match key {
26+
"--ruff-tool" if tool.is_none() => {
27+
let path = PathBuf::from(value);
28+
if !path.is_absolute() {
29+
return Err("--ruff-tool 必须为绝对路径".into());
30+
}
31+
tool = Some(path);
32+
}
33+
"--format" if format.is_none() => {
34+
format = Some(match value {
35+
"json" => true,
36+
"human" => false,
37+
_ => return Err("--format 仅支持 human|json".into()),
38+
});
39+
}
40+
"--timeout" if timeout.is_none() => {
41+
timeout = Some(crate::check_budget::parse_check_timeout(value)?)
42+
}
43+
value if !value.is_empty() && !value.starts_with('-') && root.is_none() => {
44+
root = Some(PathBuf::from(word))
45+
}
46+
_ => return Err("comments python 参数非法或重复".into()),
47+
}
48+
index += 1;
49+
}
50+
Ok(Self {
51+
root: root.unwrap_or_else(|| PathBuf::from(".")),
52+
tool,
53+
json: format.unwrap_or(false),
54+
timeout,
55+
})
56+
}
57+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//! Python 独立注释入口:复用原 Ruff 扫描,保持文档任务与开发规范任务的分类边界。
2+
use crate::check_budget::{budget_record, resolve_project_default, select_check_timeout};
3+
use crate::python_comments_arguments::PythonCommentsArguments;
4+
use serde_json::{Value, json};
5+
use std::{
6+
process::ExitCode,
7+
sync::atomic::AtomicBool,
8+
time::{Duration, Instant},
9+
};
10+
11+
/// 执行项目内已配置 Ruff 的注释观察;参数为语种后 argv,返回局部未完成或取消退出码。
12+
pub fn run(args: &[String]) -> ExitCode {
13+
let arguments = match PythonCommentsArguments::parse(args) {
14+
Ok(value) => value,
15+
Err(reason) => {
16+
eprintln!("{reason}");
17+
return ExitCode::from(2);
18+
}
19+
};
20+
let (timeout, source) = match select_check_timeout(arguments.timeout)
21+
.and_then(|(value, source)| resolve_project_default(&arguments.root, value, source))
22+
{
23+
Ok(value) => value,
24+
Err(reason) => {
25+
eprintln!("{reason}");
26+
return ExitCode::from(2);
27+
}
28+
};
29+
let deadline = Instant::now() + Duration::from_millis(timeout);
30+
let mut native = Value::Null;
31+
let mut next = Value::Null;
32+
let mut reason = "project_root_unavailable";
33+
if let Some(root) = arguments
34+
.root
35+
.canonicalize()
36+
.ok()
37+
.filter(|root| root.is_dir())
38+
{
39+
match crate::python_lint_command::scan_and_sync_report_with_deadline(
40+
&root,
41+
arguments.tool.as_deref(),
42+
deadline,
43+
&AtomicBool::new(false),
44+
) {
45+
Ok(mut report) => {
46+
// 工作台已经保存原 0.9 扫描;这里仅引用已有 0.12 对话协议,不改写原始事实。
47+
crate::python_lint_command::annotate_conversation_budget(
48+
&mut report,
49+
timeout,
50+
source,
51+
);
52+
native = report;
53+
reason = "native_documentation_coverage_unverified";
54+
if native["workspace_binding"] == "bound" {
55+
next = crate::next_command::read_python_documentation_brief(&root)
56+
.unwrap_or(Value::Null);
57+
}
58+
}
59+
Err(_) => reason = "language_registry_invalid",
60+
}
61+
}
62+
let interrupted = codeguard_runtime::sigint_cancellation_requested()
63+
|| native["incomplete_reasons"]
64+
.as_array()
65+
.is_some_and(|reasons| reasons.iter().any(|reason| reason == "request_cancelled"));
66+
if interrupted && native.is_object() {
67+
native["command_status"] = json!("cancelled");
68+
native["exit_code"] = json!(130);
69+
}
70+
let findings: Vec<_> = native["files"]
71+
.as_array()
72+
.into_iter()
73+
.flatten()
74+
.flat_map(|file| file["findings"].as_array().into_iter().flatten())
75+
.filter(|finding| {
76+
finding["rule_id"]
77+
.as_str()
78+
.is_some_and(codeguard_adapters::is_ruff_documentation_rule)
79+
})
80+
.cloned()
81+
.collect();
82+
let complete = !interrupted && native["local_scan_complete"] == true;
83+
let exit = if interrupted { 130 } else { 3 };
84+
let report = json!({"schema_version":"0.1.0","report_type":"python_comments_feedback","operation":"comments","language":"python",
85+
"command_status":if interrupted{"cancelled"}else{"incomplete"},"exit_code":exit,"authority":"local_unverified","coverage_proven":false,
86+
"delivery_decision":"not_evaluated","local_scan_complete":complete,"reason":reason,"execution_budget":budget_record(timeout,source),
87+
"native_report":native,"documentation_findings":findings,"next":next,"documentation_rule_coverage":"unverified","detailed_contract_qualification":"not_granted",
88+
"next_actions":["核对原项目 Ruff 文档规则和配置;不会隐式启用 preview 或改写规则选择。",
89+
"按稳定任务使用 task verify 原工具复检;零诊断不证明文档规则完整启用、详细内容准确或任务已关闭。"]});
90+
if arguments.json {
91+
println!("{report}");
92+
} else {
93+
println!(
94+
"Python 注释检查:原生局部完成 {};文档规则完整覆盖未验证。",
95+
complete
96+
);
97+
for finding in report["documentation_findings"]
98+
.as_array()
99+
.into_iter()
100+
.flatten()
101+
{
102+
println!(
103+
"原生规则 {}:{}:{};{};任务 {}",
104+
finding["rule_id"],
105+
finding["path"],
106+
finding["line"],
107+
finding["rule_summary"],
108+
finding["finding_id"]
109+
);
110+
}
111+
println!(
112+
"原生未完成原因:{};下一步:{}",
113+
report["native_report"]["incomplete_reasons"], report["next"]
114+
);
115+
}
116+
ExitCode::from(exit)
117+
}

0 commit comments

Comments
 (0)