Skip to content

Fix/readme-implementation-sync#7

Merged
ccsert merged 2 commits into
mainfrom
fix/readme-implementation-sync
Jan 31, 2026
Merged

Fix/readme-implementation-sync#7
ccsert merged 2 commits into
mainfrom
fix/readme-implementation-sync

Conversation

@ccsert
Copy link
Copy Markdown
Owner

@ccsert ccsert commented Jan 31, 2026

  • Add incremental review and structured tags to features list
  • Update project structure with complete tool list (5 tools)
  • Add skills/ directory and gitea-assistant agent to structure
  • Clarify that .gitea/workflows/ is created after installation
  • Remove unused AUTO_APPROVE env var from Dockerfile
  • Update copilot-instructions.md with all available tools

ccsert added 2 commits January 31, 2026 23:56
- Add gitea-incremental-diff tool for reviewing only new changes since last review
- Add structured review tags (BUG, SECURITY, PERFORMANCE, STYLE, DOCS, TEST)
- Add severity levels (CRITICAL, HIGH, MEDIUM, LOW)
- Add unit tests for new features
- Update code-review agent to support incremental reviews
- Add incremental review and structured tags to features list
- Update project structure with complete tool list (5 tools)
- Add skills/ directory and gitea-assistant agent to structure
- Clarify that .gitea/workflows/ is created after installation
- Remove unused AUTO_APPROVE env var from Dockerfile
- Update copilot-instructions.md with all available tools
Copilot AI review requested due to automatic review settings January 31, 2026 16:00
@ccsert ccsert merged commit f2a1c4a into main Jan 31, 2026
4 checks passed
@ccsert ccsert deleted the fix/readme-implementation-sync branch January 31, 2026 16:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR synchronizes documentation with the implementation of new incremental review and structured tagging features for the OpenCode Gitea Review tool.

Changes:

  • Added documentation for incremental review feature and structured tags to README files
  • Removed unused AUTO_APPROVE environment variable from Dockerfile
  • Updated tool documentation and agent instructions with complete tool list and structured tag format
  • Added three new test files for validating review tags, statistics, and incremental diff functionality

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
README.md Added incremental review and structured tags features; updated project structure with complete 5-tool list and skills/ directory
README_zh.md Chinese translation of the same README.md changes
Dockerfile Removed unused AUTO_APPROVE environment variable
.opencode-review/tools/gitea-review.txt Comprehensive documentation update with summary format guidelines and structured tag examples
.opencode-review/tools/gitea-review.ts Added structured tag constants, helper functions (formatReviewTag, parseReviewTag, formatCommentBody), and suggestion support
.opencode-review/tools/gitea-incremental-diff.txt New documentation for incremental diff feature
.opencode-review/tools/gitea-incremental-diff.ts New tool implementation for fetching only changes since last review
.opencode-review/tests/gitea-review-tags.test.ts New test file for structured tag formatting and parsing
.opencode-review/tests/gitea-review-stats.test.ts New test file for review statistics (references non-existent implementation)
.opencode-review/tests/gitea-incremental-diff.test.ts New test file for incremental diff helper functions
.opencode-review/agents/code-review.md Updated agent instructions with structured tags, auto-fix suggestions, and incremental review workflow
.github/copilot-instructions.md Updated with complete tool list and structured tag format

Comment on lines +30 to +52
// 从 gitea-incremental-diff.ts 复制的函数
function findLastReviewedCommit(reviews: Review[], commits: Commit[]): string | null {
if (!reviews || reviews.length === 0) return null

const commitShas = new Set(commits.map(c => c.sha))

const validReviews = reviews
.filter(r => r.commit_id && commitShas.has(r.commit_id))
.sort((a, b) => new Date(b.submitted_at).getTime() - new Date(a.submitted_at).getTime())

return validReviews.length > 0 ? validReviews[0].commit_id : null
}

function findCommitsAfter(commits: Commit[], afterSha: string | null): Commit[] {
if (!afterSha) return commits

const afterIndex = commits.findIndex(c => c.sha === afterSha)
if (afterIndex === -1) {
return commits
}

return commits.slice(afterIndex + 1)
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file duplicates function implementations instead of importing them from gitea-incremental-diff.ts. These functions (findLastReviewedCommit, findCommitsAfter) are defined in the source file but not exported. Either export them from the source file and import them here, or keep them as internal implementation details and test the tool's public interface instead. Testing copied code doesn't validate the actual implementation.

Copilot uses AI. Check for mistakes.
* Parse a review comment to extract category and severity
*/
export function parseReviewTag(body: string): { category?: ReviewCategory; severity?: ReviewSeverity } | null {
const match = body.match(/\*?\*?\[([A-Z]+):([A-Z]+)\]\*?\*?/)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern allows optional asterisks in flexible positions (e.g., it would match "[BUG:HIGH]" or "[BUG:HIGH]"). This could lead to inconsistent parsing. Consider using a stricter pattern like /^\*\*\[([A-Z]+):([A-Z]+)\]\*\*$/ to only match properly formatted tags, or at minimum use \*{0,2} to ensure matched asterisks are properly paired.

Suggested change
const match = body.match(/\*?\*?\[([A-Z]+):([A-Z]+)\]\*?\*?/)
const match = body.match(/\*{0,2}\[([A-Z]+):([A-Z]+)\]\*{0,2}/)

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines +17 to +19
- � **Incremental Review** - Only reviews new changes since last review (for updated PRs)
- 🏷️ **Structured Tags** - Categorizes issues by type (BUG, SECURITY, PERFORMANCE) and severity
- �🐳 **Docker Support** - Zero-config installation with pre-built image
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The emoji characters are not displaying correctly in the feature list. Line 17 shows "� Incremental Review" and line 19 shows "�🐳 Docker Support" with corrupted characters. This will make the README look unprofessional and harder to read. Ensure proper UTF-8 encoding is used and valid emoji code points are inserted.

Suggested change
- **Incremental Review** - Only reviews new changes since last review (for updated PRs)
- 🏷️ **Structured Tags** - Categorizes issues by type (BUG, SECURITY, PERFORMANCE) and severity
- 🐳 **Docker Support** - Zero-config installation with pre-built image
- 🔁 **Incremental Review** - Only reviews new changes since last review (for updated PRs)
- 🏷️ **Structured Tags** - Categorizes issues by type (BUG, SECURITY, PERFORMANCE) and severity
- 🐳 **Docker Support** - Zero-config installation with pre-built image

Copilot uses AI. Check for mistakes.
Comment thread README_zh.md
Comment on lines +17 to +19
- � **增量审查** - 仅审查上次审查后的新变更(适用于 PR 更新)
- 🏷️ **结构化标签** - 按类型(BUG、SECURITY、PERFORMANCE)和严重程度分类问题
- �🐳 **Docker 支持** - 预构建镜像,零配置安装
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The emoji characters are not displaying correctly in the feature list. Line 17 shows "� 增量审查" and line 19 shows "�🐳 Docker 支持" with corrupted characters. This will make the README look unprofessional and harder to read. Ensure proper UTF-8 encoding is used and valid emoji code points are inserted.

Suggested change
- **增量审查** - 仅审查上次审查后的新变更(适用于 PR 更新)
- 🏷️ **结构化标签** - 按类型(BUG、SECURITY、PERFORMANCE)和严重程度分类问题
- 🐳 **Docker 支持** - 预构建镜像,零配置安装
- 📈 **增量审查** - 仅审查上次审查后的新变更(适用于 PR 更新)
- 🏷️ **结构化标签** - 按类型(BUG、SECURITY、PERFORMANCE)和严重程度分类问题
- 🐳 **Docker 支持** - 预构建镜像,零配置安装

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +103
// Identify bot reviews by checking for our review marker
const BOT_REVIEW_MARKER = "<!-- opencode-review -->"

function isBotReview(review: Review): boolean {
// Check if review was made by a bot-like user or contains our marker
// Since we can't easily identify our own reviews, we look for any APPROVED or REQUEST_CHANGES
// reviews that have a commit_id
return Boolean(review.commit_id && review.commit_id.length > 0 &&
(review.state === "APPROVED" || review.state === "REQUEST_CHANGES" || review.state === "COMMENT"))
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constant BOT_REVIEW_MARKER is defined but never used. The isBotReview function doesn't reference it, instead just checking the review state and commit_id. Either this marker should be used to identify bot reviews (e.g., by checking review body content), or it should be removed to avoid confusion.

Suggested change
// Identify bot reviews by checking for our review marker
const BOT_REVIEW_MARKER = "<!-- opencode-review -->"
function isBotReview(review: Review): boolean {
// Check if review was made by a bot-like user or contains our marker
// Since we can't easily identify our own reviews, we look for any APPROVED or REQUEST_CHANGES
// reviews that have a commit_id
return Boolean(review.commit_id && review.commit_id.length > 0 &&
(review.state === "APPROVED" || review.state === "REQUEST_CHANGES" || review.state === "COMMENT"))
// Heuristic to determine which reviews should be considered when finding the last reviewed commit.
// Since we can't easily identify our own reviews, we look for any APPROVED, REQUEST_CHANGES, or COMMENT
// reviews that have a non-empty commit_id.
function isBotReview(review: Review): boolean {
return Boolean(
review.commit_id &&
review.commit_id.length > 0 &&
(review.state === "APPROVED" || review.state === "REQUEST_CHANGES" || review.state === "COMMENT")
)

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +43
// 复制自 gitea-review.ts 的常量和函数
const REVIEW_CATEGORIES = ["BUG", "SECURITY", "PERFORMANCE", "STYLE", "DOCS", "TEST"] as const
const REVIEW_SEVERITIES = ["CRITICAL", "HIGH", "MEDIUM", "LOW"] as const

type ReviewCategory = typeof REVIEW_CATEGORIES[number]
type ReviewSeverity = typeof REVIEW_SEVERITIES[number]

function formatReviewTag(category: ReviewCategory, severity: ReviewSeverity): string {
return `**[${category}:${severity}]**`
}

function parseReviewTag(body: string): { category?: ReviewCategory; severity?: ReviewSeverity } | null {
const match = body.match(/\*?\*?\[([A-Z]+):([A-Z]+)\]\*?\*?/)
if (!match) return null

const category = match[1] as ReviewCategory
const severity = match[2] as ReviewSeverity

if (REVIEW_CATEGORIES.includes(category) && REVIEW_SEVERITIES.includes(severity)) {
return { category, severity }
}
return null
}

function formatCommentBody(body: string, suggestion?: string): string {
if (!suggestion) return body

const trimmedBody = body.trimEnd()

return `${trimmedBody}

\`\`\`suggestion
${suggestion}
\`\`\`
`
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file duplicates function implementations instead of importing them from gitea-review.ts. The actual functions are exported from gitea-review.ts (e.g., formatReviewTag, parseReviewTag, formatCommentBody at lines 93-127) and should be imported here. This duplication means if the implementation changes, the tests will continue passing while testing outdated logic, defeating the purpose of automated testing.

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +116
// 从 gitea-review-stats.ts 复制的类型和函数
interface ReviewStats {
totalReviews: number
totalComments: number
byCategory: Record<ReviewCategory, number>
bySeverity: Record<ReviewSeverity, number>
byFile: Record<string, number>
byCategorySeverity: Record<string, number>
timeline: Array<{ date: string; count: number }>
suggestions: number
untaggedComments: number
issues: IssueRecord[]
}

function parseReviewTag(body: string): { category?: ReviewCategory; severity?: ReviewSeverity } | null {
const match = body.match(/\*?\*?\[([A-Z]+):([A-Z]+)\]\*?\*?/)
if (!match) return null

const category = match[1] as ReviewCategory
const severity = match[2] as ReviewSeverity

if (REVIEW_CATEGORIES.includes(category) && REVIEW_SEVERITIES.includes(severity)) {
return { category, severity }
}
return null
}

function initializeStats(): ReviewStats {
const byCategory = {} as Record<ReviewCategory, number>
const bySeverity = {} as Record<ReviewSeverity, number>

for (const cat of REVIEW_CATEGORIES) {
byCategory[cat] = 0
}
for (const sev of REVIEW_SEVERITIES) {
bySeverity[sev] = 0
}

return {
totalReviews: 0,
totalComments: 0,
byCategory,
bySeverity,
byFile: {},
byCategorySeverity: {},
timeline: [],
suggestions: 0,
untaggedComments: 0,
issues: [],
}
}

function extractDescription(body: string): string {
const cleaned = body.replace(/\*?\*?\[[A-Z]+:[A-Z]+\]\*?\*?\s*/g, "").trim()
const withoutSuggestion = cleaned.replace(/```suggestion[\s\S]*?```/g, "").trim()
if (withoutSuggestion.length > 100) {
return withoutSuggestion.slice(0, 97) + "..."
}
return withoutSuggestion || "(no description)"
}

function analyzeComment(comment: { body: string; path?: string }, stats: ReviewStats): void {
stats.totalComments++

const hasSuggestion = comment.body.includes("```suggestion")

if (hasSuggestion) {
stats.suggestions++
}

const tag = parseReviewTag(comment.body)
if (tag && tag.category && tag.severity) {
stats.byCategory[tag.category]++
stats.bySeverity[tag.severity]++

const key = `${tag.category}:${tag.severity}`
stats.byCategorySeverity[key] = (stats.byCategorySeverity[key] || 0) + 1

stats.issues.push({
category: tag.category,
severity: tag.severity,
file: comment.path || "(summary)",
description: extractDescription(comment.body),
hasSuggestion,
})
} else {
stats.untaggedComments++
}

if (comment.path) {
stats.byFile[comment.path] = (stats.byFile[comment.path] || 0) + 1
}
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file references "gitea-review-stats.ts" in the comment, but this file doesn't exist in the codebase. The functions being tested (initializeStats, analyzeComment, extractDescription) are not found in any tool file. Either the test is for a feature that doesn't exist yet, or it's testing copied code that should be part of an actual implementation. Tests should validate actual implementation code, not isolated copies.

Copilot uses AI. Check for mistakes.
- `gitea-incremental-diff` - **NEW** Fetch only new changes since last review (for updated PRs)
- `gitea-pr-files` - List changed files (optional)
- `gitea-review` - **REQUIRED** Submit review to Gitea
- `gitea-review` - **REQUIRED** Submit review to Gitea (includes statistics report automatically)
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "includes statistics report automatically" for the gitea-review tool, but there's no statistics functionality implemented in gitea-review.ts. The tool only counts suggestions and shows them in the success message. Either remove this misleading claim or implement the statistics feature that gitea-review-stats.test.ts appears to be testing.

Suggested change
- `gitea-review` - **REQUIRED** Submit review to Gitea (includes statistics report automatically)
- `gitea-review` - **REQUIRED** Submit review to Gitea

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants