mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-10-02 01:15:23 +08:00
* feat(idea): add IntelliJ IDEA plugin extension Add a new JetBrains IDE extension under extensions/idea/ that brings the Open Code Review workflow to IntelliJ-based IDEs. The implementation mirrors the VSCode extension architecture: - JCEF-based webview for sidebar and config panel (shared HTML/JS bundle) - Same CLI integration (ocr review, config, install) - Git integration via command-line git (branch/commit/workspace modes) - Comment mounting with RangeHighlighter and inline panels - i18n support (en/zh-cn), matching the VSCode extension - Theme-aware CSS variables synced from IDEA's LookAndFeel 195 tests pass across 15 suites. ./gradlew runIde launches successfully. Closes #499 * fix(idea): harden process/threading/disposal + subdir jump path-basis Address ocr code-review findings across the host side: - CliService: probe/runRaw/install process lifecycle (bounded joins, closeStreamsQuietly, SIGTERM+grace, independent install slot, atomic current claim), cancel getAndSet, install stale killStaleInstall. - GitService: stdout UTF-8, reader join on timeout, getState synchronized, isRelevantTo case-insensitive + os.name hoist, safeRef injection guard, getCommitFiles dedup. - ConfigService: atomic temp+rename write, dir 700, readRaw log, setMany rollback + failing-key log, @Synchronized writers, trySetPosix Windows skip. - JCEF disposal: EDT-safe browser/dialog teardown, idempotent dispose, PCE rethrow, init try-catch self-cleanup, @Volatile channel. - ReviewSession: cancel CAS, run-before-cancel guard, catch Exception+PCE. - SidebarRouter: CancelReview target capture + identity guard, startReview cancels stale session. - CommentService: jump path-basis fix (resolveProjectFile uses repoRoot to match repo-relative comment paths when project opened at a subdir). - Misc: HostStrings single-pass param replace, IdeaTheme alpha clamp + font-name sanitization, CliParse isNotBlank, Providers Locale.ROOT, ConfigUtils isNotBlank + key normalization, ConfigDraft preset-key normalization, WebviewHtml BOM strip + IOException fallback. build.gradle mavenCentral fallback, jest SPDX header, webpack mode, gradle/settings trailing newline. * Update extensions/idea/src/main/kotlin/com/alibaba/opencodereview/idea/jcef/JcefConfigPanelHost.kt Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update extensions/idea/src/main/kotlin/com/alibaba/opencodereview/idea/messages/HostMessages.kt Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(idea): update HostMessagesTest for explicitNulls=true + trailing newline - HostMessagesTest: 3 assertions updated (assertFalse→assertTrue + is JsonNull) to match explicitNulls=true (null fields now present as "field": null) - HostMessages: comment updated to reflect explicitNulls=true - CommentService: trailing newline * fix(idea): parsePorcelain arrow parsing for filenames containing ' -> ' When a filename contains ' -> ' (spaces + arrow), git quotes it. The old code used indexOf(" -> ") which matched the arrow INSIDE the filename instead of the separator, producing a corrupted path. Fix: prioritize '" -> ' (closing quote + separator, 5 chars) which unambiguously finds the separator for quoted paths. Fall back to ' -> ' for unquoted paths (no spaces → no false match). Tests: 3 new cases — quoted rename, arrow-in-name rename, arrow-no-space. * test(idea): add parsePorcelain case for unquoted-old/quoted-new rename * chore(idea): remove unused JComponent import in OcrToolWindowFactory * fix(idea): log JSON parse errors inside parseRawConfig parseRawConfig's internal runCatching swallowed JSON errors silently. readRaw's outer runCatching only catches IO errors (readText), not JSON parse errors. Added Logger.warn inside parseRawConfig so JSON errors are also recorded. Note: thisLogger() unresolved from top-level function in ConfigDraft.kt (likely inline-function context issue); used Logger.getInstance instead. * fix(idea): path traversal guard in readWorkspaceFile + isBinaryFile File(root, relPath) without validation allows ../../etc/passwd to escape the repo root. Added canonicalPath.startsWith(root + separator) check, wrapped in runCatching for graceful degradation on IO errors. pathExistsAtRef not affected — uses git ref:path syntax which git itself validates (path stays within repo tree). * Update extensions/idea/src/main/kotlin/com/alibaba/opencodereview/idea/services/ConfigService.kt Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(idea): @Synchronized on set() to prevent race with deleteCustomProvider set() goes through cli.runRaw (external CLI process) to write config.json, bypassing the @Synchronized lock that deleteCustomProvider/writeRaw use. Adding @Synchronized serializes set with deleteCustomProvider, preventing interleaving that could silently undo config changes. * style(idea): extract magic strings + trim CLI args + remove unnecessary toList() - OpenOcrToolWindowAction: extract tool window ID to companion const - ReviewSession: extract 'completed_with_errors' to named constant - CliParse: trim --from/--to/--commit args (consistent with --background) - CliParse: remove unnecessary .toList() in extractCliError (sequence is enough) * style(idea): FONT_NAME_INVALID add { symmetry + normalizeLine val expression - IdeaTheme: add { to FONT_NAME_INVALID char class (symmetric with }) - CommentAnchor: var s → val s with expression body in normalizeLine * style(idea): locale when-exhaustiveness + Linux shell fallback - HostStrings: if(locale==ZH_CN) → when(locale) for compiler exhaustiveness - ShellEnv: /bin/zsh fallback → macOS zsh / Linux bash (portability) * fix(idea): @Volatile on GitService callback properties diffDecorator and diffViewerReady are written from ReviewProjectService (on init/dispose) and read from pooled threads (git operations). Without @Volatile, the pooled thread may not see the latest value. Added @Volatile for cross-thread visibility. * fix(idea): close process streams in ShellEnv.capture via finally Added closeStreamsQuietly() extension on Process (matching CliService pattern) and a finally block in capture() to ensure inputStream/ outputStream/errorStream are closed on all three exit paths (timeout/ normal/interrupt). Previously only outputStream was closed (stdin at start), inputStream fd leaked until GC. * fix(idea): clear stale maps in show() + guard malformed FAILED + close stale streams + fix leftRefFor fallback - CommentService: clear jumpBlockReasons/locateNotes in show() first synchronized block (was only cleared later in clearHighlighters, leaving a window for EDT jumpTo to read stale entries from previous review) - SidebarRouter: only post FAILED for Malformed when session.get() != null (was unconditionally overriding IDLE/DONE state when no review was running) - CliService: close stale process streams after eviction in runRaw (killStaleInstall had closeStreamsQuietly, runRaw did not) - GitService: leftRefFor mergeBase failure returns null instead of falling back to 'from' (was inconsistent with getBranchDiff's three-dot merge-base diff) * fix(idea): resolveProjectFile use toRealPath to resolve symlinks normalize() only resolves .. and . lexically, not symlinks. A symlink inside the repo pointing outside (e.g. evil_link.txt -> /etc/passwd) passes the startsWith check but refreshAndFindFileByNioFile resolves to the symlink target — reading files outside the repo. Switched normalize() to toRealPath() which resolves all symlinks, so the startsWith check catches symlink escapes. * fix(idea): add disposed guard to scheduleFullRepaint Consistent with forceFullRepaint which already checks disposed. Prevents restarting stopped timers after dispose(). * fix(idea): register OcrWebview with proper Disposer parent to fix memory leak OcrWebview's constructor calls messageBus.connect(this), which adds OcrWebview to the Disposer tree under ROOT_DISPOSABLE (no parent). Neither JcefReviewPanel nor JcefConfigPanelHost registered OcrWebview as their child, so on IDE shutdown Disposer found 11+ leaked instances. Fix: Disposer.register(this, webview) in both JcefReviewPanel and JcefConfigPanelHost. webview.dispose() is idempotent, so the existing manual dispose calls in dispose() methods are safe alongside Disposer. * refactor: extract shared frontend to extensions/frontend/ - Move webview/ and shared/ from vscode/src/ to extensions/frontend/src/ - Split bridge.ts into bridge.vsc.ts and bridge.idea.ts - Shared webpack.config.js with OCR_TARGET env var (NormalModuleReplacementPlugin) - VSC webpack.config.js: only extension host config; webview build delegates to extensions/frontend - IDEA build.gradle.kts: frontendDir points to ../frontend, OCR_TARGET=idea - VSC extension host imports: ../../shared → @shared (tsconfig paths + webpack alias) - ts-loader: transpileOnly=true (type checking via tsc separately) - Delete extensions/idea/frontend/ (no longer needed) - Delete extensions/vscode/src/webview/ and src/shared/ (moved) Both VSC and IDEA builds verified: extension.js, webview.js, configPanel.js all produced successfully. * chore: update READMEs and tests for shared frontend extraction - idea: update architecture docs, remove stale UPSTREAM.md references - idea: bump version to 0.3.0 - idea: add MessageContractTest for host↔frontend message type drift - vscode: update architecture docs for shared frontend at extensions/frontend/ - vscode: fix test imports (../../../shared → @shared) broken by extraction * chore(idea): use brand plugin icons and expand description for marketplace listing Replace the template default plugin icon with the project brand icon (shield+eye, transparent background, aligned with the VS Code extension); add pluginIcon_dark.svg for dark IDE themes. Expand plugin.xml description with features/prerequisites HTML for the JetBrains Marketplace listing. * fix(idea): terminate CLI process tree to prevent orphaned grandchildren Process.destroy()/destroyForcibly() only signal the direct child. The globally-installed ocr CLI is a Node launcher that spawns the Go binary as a grandchild; killing only the launcher orphans the Go process, which gets reparented to the system root and keeps running after cancellation. Snapshot descendants before SIGTERM (handles stay valid after the parent dies, while live enumeration goes blind due to reparenting), then tree-kill from the snapshot after the grace period, parent first so supervisor-like parents cannot respawn children. Applied to all six kill sites: cancel, runRaw stale/finally, install finally, killStaleInstall, and probe timeout. Fallback sites drop the isAlive guard to shrink the check-then-enumerate TOCTOU window, and kill helpers never throw so stream cleanup in finally blocks is always reached. Adds CliServiceTreeKillTest: spawns a fake CLI with a grandchild, cancels, and asserts the grandchild dies (POSIX only). * build(idea): enable local Plugin Verifier and fix deprecated JCEF API Configure pluginVerification so ./gradlew verifyPlugin has an IDE to check against (2.x requires an explicit list); this only wires the verification task — the packaged zip is byte-identical before/after. Switch OcrWebview to the JBCefBrowserBase overload of JBCefJSQuery.create: the JBCefBrowser overload is scheduled for removal and was flagged by the verifier. Verifier verdict is now clean ("Compatible"). * fix: add .gitignore for extensions/frontend, remove node_modules from tracking * fix(extensions): satisfy license and english-only CI checks Add missing SPDX headers to shared config files, translate the remaining Chinese comments in extensions/frontend, exempt the webview i18n copy table in english-check, and untrack extensions/.idea. * fix(idea): validate review results and isolate cancellation * chore(idea): drop internal handoff notes * ci(extensions): cover frontend and idea, restore webview type checking - bridge.ts facade lets tsc resolve ./bridge, which only webpack's NormalModuleReplacementPlugin could map before (typecheck was broken) - build:webview installs frontend deps first so clean clones build - add frontend-ext and idea-ext workflows; extend vscode-ext paths filter * ci(idea): drop gradle cache upload on self-hosted host The idea job runs on the self-hosted host without a container, so ~/.gradle (including the ~1GB IDE distribution) already persists between runs. setup-java's post-job cache save tried to upload a 2.4GB archive and stalled the runner, leaving the job red despite green tests. * chore(extensions): add SPDX headers to kt, kts and css sources Upstream #1407 extends the license gate to kt/kts/css; the IDEA plugin and the shared frontend predated that requirement. Headers generated with scripts/add-license.sh from upstream/main. * chore(scripts): temporarily exempt extensions/idea from english-only gate The plugin's comments and zh-cn UI strings are still Chinese. Mirror the extensions/vscode/ precedent with a TEMPORARY allowedPrefixes entry, dropped once the sources are translated. Takes effect together with upstream #1407, which adds .kt/.kts to scannedExts. * chore(vscode): drop accidentally committed package-lock.json The frontend-extraction refactor ran npm install inside the vscode extension package and committed the resulting npm lockfile. That package is yarn-managed (yarn.lock, yarn install --frozen-lockfile in CI), so the npm lockfile is redundant and risks drifting out of sync with yarn.lock. Nothing references it. * chore(extensions): gitignore the foreign lockfile in each subpackage extensions/vscode is yarn-managed and extensions/frontend is npm-managed; ignore the other manager's lockfile in each so an accidental npm/yarn install cannot sneak a second lockfile into the repo again. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
48 lines
571 B
Plaintext
48 lines
571 B
Plaintext
# IDEA
|
|
.idea/
|
|
*.iml
|
|
*.ipr
|
|
*.iws
|
|
|
|
dist/
|
|
npm/*/bin/
|
|
coverage.out
|
|
coverage.html
|
|
.claude/plans
|
|
.claude/commands/comment.md
|
|
.claude/commands/read-issue.md
|
|
.claude/settings.local.json
|
|
|
|
pages/package-lock.json
|
|
scripts/hooks/
|
|
scripts/publish/.env.internal
|
|
CHANGELOG.md
|
|
|
|
vendor/
|
|
temp/
|
|
.codegraph/
|
|
|
|
# Ignore downloaded Go binary, but keep JS entry point
|
|
!bin/ocr.js
|
|
bin/ocr
|
|
bin/opencodereview
|
|
|
|
/opencodereview
|
|
|
|
/node_modules
|
|
|
|
# Mac OS X
|
|
.DS_Store
|
|
|
|
# Eclipse git ignore#
|
|
.project
|
|
.classpath
|
|
.settings/
|
|
*.factorypath
|
|
|
|
*.run.xml
|
|
**/spoon.classpath.tmp
|
|
# Python
|
|
__pycache__/
|
|
*.py[cod]
|