mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-08-08 16:24:27 +00:00
Some checks are pending
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Pages / build (push) Waiting to run
Deploy Pages / deploy (push) Blocked by required conditions
* chore: add SPDX license headers to all source files
Add Apache-2.0 SPDX license identifiers and copyright notices to all
tracked .go, .sh, .js, .mjs, .ts, and .tsx source files.
Introduce scripts/verify-license.sh and scripts/add-license.sh for
automated verification and bulk addition of license headers. Integrate
the check into CI (ci.yml) and the Makefile (license-check target as
a prerequisite of the existing check target).
This satisfies the OpenSSF Best Practices Badge requirements for
copyright_per_file and license_per_file.
* fix: restore execute permissions on scripts
* docs: add license header instructions to CONTRIBUTING guides
* docs: add license header instructions to pages contributing guides
* fix(pages): strip unclosed HTML comment markers to satisfy CodeQL
* fix: apply code review suggestions for license scripts
- Fix portability: detect macOS vs Linux stat for permission copy
- Fix has_header: check both SPDX and copyright (match verify logic)
- Fix is_ignored: match on path boundaries to avoid false positives
- Fix year extraction: use consistent pipeline across both scripts
- Fix Bash 3.2 compat: quote array length expansion for set -u
* fix(pages): use loop-until-clean for HTML comment stripping (CodeQL)
* fix(pages): use split/join instead of replace to avoid CodeQL false positive
CodeQL's js/incomplete-multi-character-sanitization rule flags any
.replace() that removes multi-character sequences like '<!--...-->',
regardless of context. The data here comes from readFileSync on the
project's own index.html (no untrusted input), making this a false
positive. Using split(regex).join('') achieves the same result without
triggering the taint-tracking rule.
100 lines
2.9 KiB
Go
100 lines
2.9 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright 2026 alibaba/open-code-review Contributors
|
|
|
|
package diff
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/alibaba/open-code-review/internal/config/template"
|
|
"github.com/alibaba/open-code-review/internal/llm"
|
|
"github.com/alibaba/open-code-review/internal/model"
|
|
"github.com/alibaba/open-code-review/internal/stdout"
|
|
"github.com/alibaba/open-code-review/internal/telemetry"
|
|
)
|
|
|
|
// ReLocateComment calls the LLM to regenerate a precise existing_code snippet
|
|
// when text-based matching fails, then retries ResolveComment with the new snippet.
|
|
// Returns (success, response, requestMessages) so the caller can record session
|
|
// history and track token usage. Response and messages are nil on early exits.
|
|
func ReLocateComment(
|
|
ctx context.Context,
|
|
cm *model.LlmComment,
|
|
d *model.Diff,
|
|
client llm.LLMClient,
|
|
task *template.LlmConversation,
|
|
modelName string,
|
|
maxTokens int,
|
|
) (bool, *llm.ChatResponse, []llm.Message) {
|
|
if task == nil || len(task.Messages) == 0 {
|
|
return false, nil, nil
|
|
}
|
|
|
|
messages := make([]llm.Message, 0, len(task.Messages))
|
|
for _, m := range task.Messages {
|
|
content := m.Content
|
|
content = strings.ReplaceAll(content, "{diff}", d.Diff)
|
|
content = strings.ReplaceAll(content, "{existing_code}", cm.ExistingCode)
|
|
content = strings.ReplaceAll(content, "{suggestion_content}", cm.Content)
|
|
messages = append(messages, llm.NewTextMessage(m.Role, content))
|
|
}
|
|
|
|
startTime := time.Now()
|
|
_, llmSpan := telemetry.StartLLMSpan(ctx, modelName)
|
|
resp, err := client.CompletionsWithCtx(ctx, llm.ChatRequest{
|
|
Model: modelName,
|
|
Messages: messages,
|
|
MaxTokens: maxTokens,
|
|
})
|
|
duration := time.Since(startTime)
|
|
if err != nil {
|
|
telemetry.RecordLLMResult(llmSpan, duration, 0, err)
|
|
llmSpan.End()
|
|
fmt.Fprintf(stdout.Writer(), "[ocr] Re-location LLM call failed for %s: %v\n", cm.Path, err)
|
|
return false, nil, messages
|
|
}
|
|
var totalTokens int64
|
|
if resp.Usage != nil {
|
|
totalTokens = resp.Usage.TotalTokens
|
|
}
|
|
telemetry.RecordLLMResult(llmSpan, duration, totalTokens, nil)
|
|
llmSpan.End()
|
|
|
|
code := extractCodeBlock(resp.Content())
|
|
if code == "" {
|
|
return false, resp, messages
|
|
}
|
|
|
|
original := cm.ExistingCode
|
|
cm.ExistingCode = code
|
|
if ResolveComment(cm, d) {
|
|
return true, resp, messages
|
|
}
|
|
cm.ExistingCode = original
|
|
return false, resp, messages
|
|
}
|
|
|
|
// extractCodeBlock extracts the content of the first fenced code block from text.
|
|
// Returns empty string if no code block is found.
|
|
func extractCodeBlock(text string) string {
|
|
text = strings.TrimSpace(text)
|
|
start := strings.Index(text, "```")
|
|
if start < 0 {
|
|
return ""
|
|
}
|
|
afterOpen := start + 3
|
|
// Skip optional language tag on the opening fence line.
|
|
if nl := strings.IndexByte(text[afterOpen:], '\n'); nl >= 0 {
|
|
afterOpen += nl + 1
|
|
} else {
|
|
return ""
|
|
}
|
|
end := strings.Index(text[afterOpen:], "```")
|
|
if end < 0 {
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(text[afterOpen : afterOpen+end])
|
|
}
|