Skip to content

Commit 9eeb4a8

Browse files
committed
feat: 接通 Java 注释统一入口与原生局部验收
1 parent 799a6e9 commit 9eeb4a8

20 files changed

Lines changed: 757 additions & 3 deletions

‎README.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,3 +834,16 @@ Explicit `grammar probe erlang FILE --format=json` now adds bounded direct-funct
834834
Erlang project and edit checks now prefer OTP, use the form-termination candidate when the tool is absent, and update one persistent task. Selected-tool failures never fall back to WASM; task rechecks preserve history and require original native confirmation. [Acceptance](tests/acceptance/erlang-form-workbench.md).
835835

836836
Unreleased source update: the Rust CVE node in `check all` discovers an existing cargo-audit in absolute PATH directories; `--cargo-audit-tool` remains the explicit override. Select an existing offline database with `--rustsec-db /path/to/offline-db`. A selected-entry failure does not switch tools or install anything, and unverified database freshness does not grant a security pass. See [acceptance evidence](tests/acceptance/cargo-audit-path-discovery.md).
837+
838+
## Unified Java comments entry (source increment, not released)
839+
840+
`comments java [path]` reuses the existing native Javadoc probes. A file selects an explicit JDK21 local observation. A project selects recognized Javadoc configuration and its main sources only. Missing configuration does not launch Javadoc or produce comment violations. Explicit Maven context selects original-POM multi-file checking; failure never falls back to a single-file probe.
841+
842+
```bash
843+
codeguard comments java File.java --java-home /absolute/jdk21 --format json
844+
codeguard comments java . --java-home /absolute/jdk21 --maven-tool /absolute/mvn --maven-repo /absolute/repository --repo-sha256 SHA256 --timeout 60s --format json
845+
```
846+
847+
The independent `java_comments_feedback 0.1.0` wrapper preserves the existing report under `native_observation`; the old `lint java --checker javadoc` protocol remains unchanged. Budget precedence is CLI, registered environment, project default, then built-in default. All native child work shares one deadline. Feedback exposes target kind, budget, observations and next actions. Zero local diagnostics still means `coverage_proven=false`, `delivery_decision=not_evaluated`, exit3 (130 on cancellation). No implicit installation or source changes occur.
848+
849+
**Current limitation:** `workbench_status=not_integrated`. Persistent Javadoc tasks, repair briefs and trusted closure remain to be connected. This entry creates no fake tasks and does not close findings from a local probe. Replace the absolute tool paths and offline-repository digest with real current values.

‎README.zh-CN.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,3 +817,16 @@ C/C++源码构建还支持明确的独立原生上下文:`codeguard lint c mai
817817
Erlang 项目与编辑检查已原生优先,缺工具时补充函数终止符候选并更新同一持久任务;所选工具失败不回退WASM,原工具复检保留历史。[验收](tests/acceptance/erlang-form-workbench.md)。
818818

819819
源码增量(尚未发布):项目 `check all` 的 Rust CVE 节点可发现绝对 PATH 中已有的 cargo-audit,显式 `--cargo-audit-tool` 优先;使用 `--rustsec-db /path/to/offline-db` 指定现有离线数据库。所选入口失败不换工具、不自动安装,数据库未核验仍不声明安全通过。见[验收](tests/acceptance/cargo-audit-path-discovery.md)。
820+
821+
## Java 注释统一入口(源码增量,尚未发布)
822+
823+
`comments java [path]` 复用既有原生 Javadoc 探针:文件模式执行显式 JDK21 局部诊断;项目模式只选择已识别配置及所属主源码。缺配置不运行 Javadoc,也不生成注释违规。显式 Maven 上下文选择原 POM 多文件检查,失败不退回单文件探针。
824+
825+
```bash
826+
codeguard comments java File.java --java-home /absolute/jdk21 --format json
827+
codeguard comments java . --java-home /absolute/jdk21 --maven-tool /absolute/mvn --maven-repo /absolute/repository --repo-sha256 SHA256 --timeout 60s --format json
828+
```
829+
830+
独立包装协议 `java_comments_feedback 0.1.0` 保留 `native_observation` 原报告,不修改旧 `lint java --checker javadoc` 的协议。预算使用 CLI、登记环境变量、项目默认值、内置默认值的优先级;所有原生子任务共用截止时间。报告显示 `target_kind`、`execution_budget`、具体观察和下一步;局部零诊断仍是 `coverage_proven=false`、`delivery_decision=not_evaluated`,退出3(取消130)。不隐式安装或修改源码。
831+
832+
**当前限制:** `workbench_status=not_integrated`。Javadoc 持久任务、修复简报及可信关闭还需接通,本入口不伪造任务,不据局部探针关闭问题。示例中的绝对工具路径和离线仓库摘要需替换为当前真实环境。

‎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 [path] [--cargo-tool ABS_PATH] [--timeout DURATION] [--format human|json]"#,
238-
scope: r#"Rust库文档探针;完整文档政策与闭环尚缺"#,
239-
languages: &[r#"rust"#],
237+
usage: r#"comments <rust|java> [path] [--timeout DURATION] [--format human|json]"#,
238+
scope: r#"Rust库文档与Java文件/项目Javadoc探针;完整文档政策与闭环尚缺"#,
239+
languages: &[r#"rust"#, r#"java"#],
240240
},
241241
CommandDescriptor {
242242
tracking_id: Some(r#"C16"#),

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ pub(crate) fn examples(command: &str) -> &'static [&'static str] {
1313
"codeguard lint java File.java --maven-tool /absolute/mvn --java-home /absolute/jdk --maven-repo /absolute/repository --repo-sha256 SHA256 --format json",
1414
"codeguard lint typescript file.ts --node-tool /absolute/node --eslint-entry /absolute/eslint/bin/eslint.js --eslint-version VERSION --config /absolute/eslint.config.js --cwd /absolute/project --format json",
1515
],
16+
"comments" => &[
17+
"codeguard comments java File.java --java-home /absolute/jdk21 --format json",
18+
"codeguard comments java . --java-home /absolute/jdk21 --maven-tool /absolute/mvn --maven-repo /absolute/repository --repo-sha256 SHA256 --format json",
19+
"codeguard comments rust . --cargo-tool /absolute/cargo --format json",
20+
],
1621
"task verify" => &[
1722
"codeguard task verify TASK_ID . --rustfmt-tool /absolute/toolchain/bin/rustfmt --format json",
1823
"codeguard task verify TASK_ID . --go-tool /absolute/sdk/bin/go --format json",
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//! Java 注释统一入口,复用原生探针并保留项目配置与局部检查边界。
2+
3+
use crate::check_budget::{
4+
budget_record, parse_check_timeout, resolve_project_default, select_check_timeout,
5+
};
6+
use crate::discovery::discover;
7+
use crate::java_javadoc_command::{Args, observe};
8+
use crate::java_javadoc_scan::{NativeContext, observe_project};
9+
use codeguard_adapters::legacy_registry;
10+
use codeguard_runtime::NativeObservation;
11+
use serde_json::json;
12+
use std::collections::{BTreeSet, HashSet};
13+
use std::path::PathBuf;
14+
use std::process::ExitCode;
15+
use std::sync::atomic::AtomicBool;
16+
use std::time::{Duration, Instant};
17+
18+
/// 执行 Java 注释检查;输入为入口剩余参数,返回参数错误、取消或局部未完成状态。
19+
pub fn run(args: &[String]) -> ExitCode {
20+
let mut target = PathBuf::from(".");
21+
let mut options = std::collections::BTreeMap::new();
22+
let mut seen = HashSet::new();
23+
let mut positional = false;
24+
let mut index = 0;
25+
while index < args.len() {
26+
let argument = &args[index];
27+
if argument.starts_with('-') {
28+
let (key, inline) = argument
29+
.split_once('=')
30+
.map_or((argument.as_str(), None), |(key, value)| (key, Some(value)));
31+
if !matches!(
32+
key,
33+
"--java-home"
34+
| "--maven-tool"
35+
| "--maven-repo"
36+
| "--repo-sha256"
37+
| "--timeout"
38+
| "--format"
39+
) || !seen.insert(key.to_owned())
40+
{
41+
eprintln!("未知或重复参数:{key}");
42+
return ExitCode::from(2);
43+
}
44+
let value = if let Some(value) = inline {
45+
value.to_owned()
46+
} else {
47+
index += 1;
48+
let Some(value) = args.get(index).filter(|value| !value.starts_with('-')) else {
49+
eprintln!("{key} 缺少参数值");
50+
return ExitCode::from(2);
51+
};
52+
value.clone()
53+
};
54+
if value.is_empty() {
55+
eprintln!("{key} 不能为空");
56+
return ExitCode::from(2);
57+
}
58+
options.insert(key.to_owned(), value);
59+
} else if positional {
60+
eprintln!("只能指定一个检查路径");
61+
return ExitCode::from(2);
62+
} else {
63+
target = PathBuf::from(argument);
64+
positional = true;
65+
}
66+
index += 1;
67+
}
68+
let format = options.get("--format").map_or("human", String::as_str);
69+
if !matches!(format, "human" | "json") {
70+
eprintln!("--format 仅支持 human/json");
71+
return ExitCode::from(2);
72+
}
73+
let timeout = options
74+
.get("--timeout")
75+
.map(|value| parse_check_timeout(value))
76+
.transpose()
77+
.and_then(select_check_timeout)
78+
.and_then(|(value, source)| {
79+
resolve_project_default(
80+
if target.is_file() {
81+
target.parent().unwrap_or(&target)
82+
} else {
83+
&target
84+
},
85+
value,
86+
source,
87+
)
88+
});
89+
let (timeout, source) = match timeout {
90+
Ok(value) => value,
91+
Err(reason) => {
92+
eprintln!("{reason}");
93+
return ExitCode::from(2);
94+
}
95+
};
96+
let java_home = options.get("--java-home").map(PathBuf::from);
97+
let maven_tool = options.get("--maven-tool").map(PathBuf::from);
98+
let maven_repo = options.get("--maven-repo").map(PathBuf::from);
99+
if [java_home.as_ref(), maven_tool.as_ref(), maven_repo.as_ref()]
100+
.into_iter()
101+
.flatten()
102+
.any(|path| !path.is_absolute())
103+
{
104+
eprintln!("原生工具与仓库路径必须为绝对路径");
105+
return ExitCode::from(2);
106+
}
107+
let deadline = Instant::now() + Duration::from_millis(timeout);
108+
let cancelled = AtomicBool::new(false);
109+
let mut report = json!({"schema_version":"0.1.0", "report_type":"java_comments_feedback", "operation":"comments", "language":"java", "category":"comments", "target_kind":"unavailable", "command_status":"incomplete", "exit_code":3, "reason":"target_unavailable", "execution_budget":budget_record(timeout, source), "native_observation":null, "discovery":null, "coverage_proven":false, "authority":"local_unverified", "delivery_decision":"not_evaluated", "workbench_status":"not_integrated", "next_actions":["依据原生诊断修复注释或配置;使用相同原生上下文重新执行 comments java", "Javadoc 持久任务适配尚未接通,不能据此关闭任务"]});
110+
if let Ok(path) = target.canonicalize() {
111+
if path.is_file() {
112+
if maven_tool.is_some() || maven_repo.is_some() || options.contains_key("--repo-sha256")
113+
{
114+
eprintln!("Maven 上下文仅用于项目目录检查");
115+
return ExitCode::from(2);
116+
}
117+
report["target_kind"] = json!("file");
118+
report["native_observation"] = observe(
119+
&Args {
120+
source: path,
121+
java_home,
122+
json: true,
123+
},
124+
deadline,
125+
&cancelled,
126+
);
127+
report["reason"] = report["native_observation"]["reason"].clone();
128+
} else if path.is_dir() {
129+
report["target_kind"] = json!("project");
130+
if let Ok(registry) = legacy_registry() {
131+
let discovery = discover(&path, &registry, &NativeObservation);
132+
let sources = discovery
133+
.languages
134+
.get("java")
135+
.map(|language| language.source_files.clone())
136+
.unwrap_or_else(BTreeSet::new);
137+
report["native_observation"] = observe_project(
138+
&path,
139+
&sources,
140+
&discovery.checker_configurations,
141+
&NativeContext {
142+
manifest_sha256: &discovery.manifest_sha256,
143+
java_home: java_home.as_deref(),
144+
maven_tool: maven_tool.as_deref(),
145+
maven_repo: maven_repo.as_deref(),
146+
repo_sha256: options.get("--repo-sha256").map(String::as_str),
147+
deadline,
148+
cancelled: &cancelled,
149+
},
150+
);
151+
report["discovery"] = discovery.to_json();
152+
report["reason"] = json!("project_comments_observed_with_unverified_coverage");
153+
} else {
154+
report["reason"] = json!("registry_unavailable");
155+
}
156+
}
157+
}
158+
let exit = if codeguard_runtime::sigint_cancellation_requested()
159+
|| report["reason"] == "request_cancelled"
160+
{
161+
130
162+
} else {
163+
3
164+
};
165+
if exit == 130 {
166+
report["command_status"] = json!("cancelled");
167+
report["reason"] = json!("request_cancelled");
168+
report["exit_code"] = json!(130);
169+
}
170+
if format == "json" {
171+
println!("{report}");
172+
} else {
173+
println!(
174+
"Java 注释检查:{};范围 {};原因 {}",
175+
report["command_status"], report["target_kind"], report["reason"]
176+
);
177+
println!("原生观察:{}", report["native_observation"]);
178+
for action in report["next_actions"].as_array().into_iter().flatten() {
179+
println!("下一步:{action}");
180+
}
181+
}
182+
ExitCode::from(exit)
183+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ mod java_cve_scan;
146146
mod java_dependency_scan;
147147
#[cfg(unix)]
148148
pub mod java_javadoc_command;
149+
#[cfg(unix)]
150+
pub mod java_comments_command;
149151
mod java_javadoc_scan;
150152
#[cfg(unix)]
151153
pub mod java_lint_dispatch;

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

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

0 commit comments

Comments
 (0)