Skip to content

Commit 292398a

Browse files
authored
Merge pull request #69 from HexmosTech/fake-review
Enhance Fake review
2 parents fa210ba + 12ac501 commit 292398a

5 files changed

Lines changed: 157 additions & 76 deletions

File tree

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: build build-win build-all build-local build-local-test run run-fake-review bump release release-internal release-gh clean test testall test-pkg upload-secrets download-secrets security-govulncheck security-govulncheck-json security-osv security-triage security-gitleaks security-b2-audit security-b2-cleanup-plan security-b2-cleanup-apply security-publish-release-manifest security-secret-regression security-sbom security-sbom-cyclonedx security-sbom-spdx security-sbom-validate release-notes-init release-notes-check release-preflight
1+
.PHONY: build build-win build-all build-local build-local-test run run-fake-review dev-ui bump release release-internal release-gh clean test testall test-pkg upload-secrets download-secrets security-govulncheck security-govulncheck-json security-osv security-triage security-gitleaks security-b2-audit security-b2-cleanup-plan security-b2-cleanup-apply security-publish-release-manifest security-secret-regression security-sbom security-sbom-cyclonedx security-sbom-spdx security-sbom-validate release-notes-init release-notes-check release-preflight
22

33
# Go parameters
44
GOENV=env -u GOROOT
@@ -70,6 +70,14 @@ run: build-local
7070
run-fake-review: build-local-test
7171
@WAIT=$${WAIT:-30s} TMP_REPO=$${TMP_REPO:-/tmp/lrc-fake-review-repo} scripts/fake_review.sh $(ARGS)
7272

73+
# Run fake review with live JS reloading — edit files in internal/staticserve/static/, refresh browser
74+
# No rebuild needed after JS changes: just edit and refresh the browser tab.
75+
dev-ui: build-local-test
76+
@LRC_STATIC_DEV_DIR=$(CURDIR)/internal/staticserve/static \
77+
WAIT=$${WAIT:-5s} \
78+
TMP_REPO=$${TMP_REPO:-/tmp/lrc-fake-review-repo} \
79+
scripts/fake_review.sh $(ARGS)
80+
7381
# Bump lrc version by editing appVersion in main.go
7482
# Prompts for version bump type (patch/minor/major)
7583
bump:

internal/appcore/bridge.go

Lines changed: 89 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func buildFakeCompletedResultForFiles(baseFiles []reviewmodel.DiffReviewFileResu
113113

114114
if totalComments > 0 {
115115
result.Summary = fmt.Sprintf(
116-
"%s\n\n## Synthetic Coverage\n\n- Generated %d synthetic comment(s) across %d file(s)\n- Includes deterministic Copy Issue scenarios: first-line (no prev), last-line (no next), interior-line (both prev/next)",
116+
"%s\n\n## Synthetic Coverage\n\n- Generated %d synthetic comment(s) across %d file(s)\n- Covers Critical, Error, Warning, and Info severities across targeted files",
117117
strings.TrimSpace(result.Summary),
118118
totalComments,
119119
len(files),
@@ -124,88 +124,106 @@ func buildFakeCompletedResultForFiles(baseFiles []reviewmodel.DiffReviewFileResu
124124
return result
125125
}
126126

127+
type syntheticCommentSpec struct {
128+
linePickIndex int // -1 = last available line, ≥0 = Nth available line
129+
severity string
130+
category string
131+
content string
132+
}
133+
134+
// perFileCommentSpecs maps each fake review file's base name to the comments to
135+
// generate for it. Line numbers are resolved at runtime from actual diff hunks.
136+
var perFileCommentSpecs = map[string][]syntheticCommentSpec{
137+
"README.md": {
138+
{
139+
linePickIndex: 0,
140+
severity: "Critical",
141+
category: "Documentation",
142+
content: "README is missing required Go version and platform prerequisites — document these before shipping.",
143+
},
144+
},
145+
"edge_cases.txt": {
146+
{
147+
linePickIndex: 0,
148+
severity: "Error",
149+
category: "Logic",
150+
content: "`alpha-updated` is inconsistent with downstream parser expectations; update the canonical test fixture.",
151+
},
152+
{
153+
linePickIndex: -1,
154+
severity: "Error",
155+
category: "Logic",
156+
content: "`delta-updated` does not match the expected integration test output — realign the test data.",
157+
},
158+
},
159+
"fake_large_config.toml": {
160+
{
161+
linePickIndex: 0,
162+
severity: "Warning",
163+
category: "Configuration",
164+
content: "`enable_telemetry = true` in a generated config risks leaking test data to analytics endpoints — disable for local runs.",
165+
},
166+
},
167+
"only_one_line.txt": {
168+
{
169+
linePickIndex: 0,
170+
severity: "Info",
171+
category: "Style",
172+
content: "Single-line file — confirm the seed suffix is stable enough for snapshot testing.",
173+
},
174+
},
175+
"ui_connectors_handlers.go": {
176+
{
177+
linePickIndex: 0,
178+
severity: "Info",
179+
category: "Style",
180+
content: "`normalizeConnectorName` chains three sequential string operations; consider combining into a single `strings.Map` pass for clarity.",
181+
},
182+
},
183+
}
184+
127185
func buildSyntheticCommentsByFile(files []reviewmodel.DiffReviewFileResult) map[string][]reviewmodel.DiffReviewComment {
128186
commentsByFile := make(map[string][]reviewmodel.DiffReviewComment)
129187

130-
// Primary scenario: find one hunk that has enough lines to guarantee
131-
// first-line, last-line, and interior-line comments.
132188
for _, file := range files {
133-
for _, hunk := range file.Hunks {
134-
numbers := collectHunkAddedLineNumbers(hunk)
135-
if len(numbers) < 3 {
136-
continue
137-
}
138-
139-
interiorIdx := 1
140-
if interiorIdx >= len(numbers)-1 {
141-
interiorIdx = len(numbers) / 2
142-
}
143-
if interiorIdx <= 0 {
144-
interiorIdx = 1
145-
}
146-
if interiorIdx >= len(numbers)-1 {
147-
interiorIdx = len(numbers) - 2
148-
}
149-
150-
commentsByFile[file.FilePath] = []reviewmodel.DiffReviewComment{
151-
{
152-
Line: numbers[0],
153-
Severity: "Warning",
154-
Category: "Context",
155-
Content: "Hunk-start line: verify Copy Issue handles missing previous line context correctly.",
156-
},
157-
{
158-
Line: numbers[len(numbers)-1],
159-
Severity: "Error",
160-
Category: "Context",
161-
Content: "Hunk-end line: verify Copy Issue handles missing next line context correctly.",
162-
},
163-
{
164-
Line: numbers[interiorIdx],
165-
Severity: "Info",
166-
Category: "Context",
167-
Content: "Interior line: verify Copy Issue includes both previous and next lines in the code excerpt.",
168-
},
169-
}
170-
return commentsByFile
189+
base := file.FilePath
190+
if idx := strings.LastIndex(base, "/"); idx >= 0 {
191+
base = base[idx+1:]
192+
}
193+
specs, ok := perFileCommentSpecs[base]
194+
if !ok {
195+
continue
171196
}
172-
}
173197

174-
// Fallback for very small diffs: emit whatever subset is possible.
175-
for _, file := range files {
198+
var allLines []int
176199
for _, hunk := range file.Hunks {
177-
numbers := collectHunkAddedLineNumbers(hunk)
178-
if len(numbers) == 0 {
179-
continue
180-
}
200+
allLines = append(allLines, collectHunkAddedLineNumbers(hunk)...)
201+
}
202+
if len(allLines) == 0 {
203+
continue
204+
}
181205

182-
comments := []reviewmodel.DiffReviewComment{
183-
{
184-
Line: numbers[0],
185-
Severity: "Warning",
186-
Category: "Context",
187-
Content: "Hunk-start line: verify Copy Issue handles missing previous line context correctly.",
188-
},
206+
var comments []reviewmodel.DiffReviewComment
207+
for _, spec := range specs {
208+
idx := spec.linePickIndex
209+
if idx < 0 {
210+
idx = len(allLines) + idx
189211
}
190-
if len(numbers) > 1 {
191-
comments = append(comments, reviewmodel.DiffReviewComment{
192-
Line: numbers[len(numbers)-1],
193-
Severity: "Error",
194-
Category: "Context",
195-
Content: "Hunk-end line: verify Copy Issue handles missing next line context correctly.",
196-
})
212+
if idx < 0 {
213+
idx = 0
197214
}
198-
if len(numbers) > 2 {
199-
comments = append(comments, reviewmodel.DiffReviewComment{
200-
Line: numbers[1],
201-
Severity: "Info",
202-
Category: "Context",
203-
Content: "Interior line: verify Copy Issue includes both previous and next lines in the code excerpt.",
204-
})
215+
if idx >= len(allLines) {
216+
idx = len(allLines) - 1
205217
}
206-
218+
comments = append(comments, reviewmodel.DiffReviewComment{
219+
Line: allLines[idx],
220+
Severity: spec.severity,
221+
Category: spec.category,
222+
Content: spec.content,
223+
})
224+
}
225+
if len(comments) > 0 {
207226
commentsByFile[file.FilePath] = comments
208-
return commentsByFile
209227
}
210228
}
211229

internal/staticserve/static/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ async function initApp() {
332332
return {
333333
...prev,
334334
...data,
335-
files: prev.files || data.files || []
335+
files: data.files || prev.files || []
336336
};
337337
});
338338
return data;

internal/staticserve/static_serve.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ package staticserve
22

33
import (
44
"embed"
5+
"encoding/json"
6+
"mime"
57
"net/http"
8+
"os"
9+
"path/filepath"
10+
"strings"
611

712
"github.com/HexmosTech/git-lrc/result"
813
)
@@ -16,13 +21,42 @@ type JSONHunkData = result.JSONHunkData
1621
type JSONLineData = result.JSONLineData
1722
type JSONCommentData = result.JSONCommentData
1823

24+
func devStaticDir() string {
25+
return os.Getenv("LRC_STATIC_DEV_DIR")
26+
}
27+
1928
// RenderPreactHTML renders the Preact-based HTML with embedded JSON data.
2029
func RenderPreactHTML(data *result.HTMLTemplateData) (string, error) {
30+
if dir := devStaticDir(); dir != "" {
31+
jsonData := result.ConvertToJSONData(data)
32+
jsonBytes, err := json.Marshal(jsonData)
33+
if err != nil {
34+
return "", err
35+
}
36+
htmlBytes, err := os.ReadFile(filepath.Join(dir, "index.html"))
37+
if err != nil {
38+
return "", err
39+
}
40+
html := strings.Replace(string(htmlBytes), "{{.JSONData}}", string(jsonBytes), 1)
41+
if data.FriendlyName != "" {
42+
html = strings.Replace(html, "<title>LiveReview Results</title>",
43+
"<title>LiveReview Results — "+data.FriendlyName+"</title>", 1)
44+
}
45+
return html, nil
46+
}
2147
return result.RenderPreactHTML(data, staticFiles)
2248
}
2349

2450
// GetStaticHandler returns an HTTP handler for serving static files.
2551
func GetStaticHandler() http.Handler {
52+
if dir := devStaticDir(); dir != "" {
53+
_ = mime.AddExtensionType(".mjs", "application/javascript; charset=utf-8")
54+
fs := http.FileServer(http.Dir(dir))
55+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56+
w.Header().Set("Cache-Control", "no-store")
57+
fs.ServeHTTP(w, r)
58+
})
59+
}
2660
return result.GetStaticHandler(staticFiles)
2761
}
2862

@@ -31,7 +65,10 @@ func ServeStaticFile(w http.ResponseWriter, r *http.Request, filename string) er
3165
return result.ServeStaticFile(w, filename, staticFiles)
3266
}
3367

34-
// ReadFile reads a file from the embedded static directory.
68+
// ReadFile reads a file from the embedded static directory (or filesystem in dev mode).
3569
func ReadFile(name string) ([]byte, error) {
70+
if dir := devStaticDir(); dir != "" {
71+
return os.ReadFile(filepath.Join(dir, name))
72+
}
3673
return staticFiles.ReadFile("static/" + name)
3774
}

review/fake_mode.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,25 @@ func BuildFakeSubmitResponse(now time.Time, friendlyName string) CreateResponse
4848

4949
func BuildFakeCompletedResult() *Response {
5050
return &Response{
51-
Status: "completed",
52-
Summary: "# Fake Review Summary\n\nThis is a fake review generated by `build-local-test` for end-to-end testing.\n\n- No AI request was sent\n- Review data is synthetic and deterministic",
51+
Status: "completed",
52+
Summary: `# Fake Review Summary
53+
54+
This is a fake review generated by ` + "`build-local-test`" + ` for end-to-end testing.
55+
56+
- No AI request was sent
57+
- Review data is synthetic and deterministic
58+
59+
## Overview
60+
61+
The connector handler refactor adds empty-payload validation and provider-name normalization. Configuration scaffolding and edge-case fixtures have been updated to extend test coverage.
62+
63+
## Technical Highlights
64+
65+
- ` + "`src/ui_connectors_handlers.go`" + `: ` + "`handleConnector`" + ` now rejects empty payloads and injects a default ` + "`provider`" + ` key, closing a class of silent dispatch failures.
66+
- ` + "`src/fake_large_config.toml`" + `: New config scaffold added; confirm ` + "`enable_telemetry = true`" + ` is intentional before merging to a shared environment.
67+
68+
## Impact
69+
70+
Risk: Enabling telemetry in a generated config file may expose test-run metadata to analytics endpoints — scope this flag to local-only builds before promoting to CI.`,
5371
}
5472
}

0 commit comments

Comments
 (0)