Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c5773e4fd | |||
| ece7377fc8 | |||
| 68cd124f59 |
@@ -7,7 +7,7 @@ When the task is to triage review findings, follow this workflow:
|
||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
||||
4. Renumber from 1 after sorting.
|
||||
5. Fix real issues with the smallest safe change.
|
||||
6. Add false positives to `.gitea/ai-review/exclusions.json`.
|
||||
6. Add false positives to `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
7. Add or update tests when behavior changes.
|
||||
8. Re-check the issue after each fix.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ description: Triage findings, fix real issues, and exclude false positives.
|
||||
- info
|
||||
3. Renumber from 1.
|
||||
4. Fix real issues.
|
||||
5. Put false positives into `.gitea/ai-review/exclusions.json`.
|
||||
5. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
6. Add tests when behavior changes.
|
||||
|
||||
## Output Rules
|
||||
@@ -26,3 +26,4 @@ description: Triage findings, fix real issues, and exclude false positives.
|
||||
- Keep the final list short.
|
||||
- Keep numbering contiguous.
|
||||
- Preserve file path, location, and fix.
|
||||
- When writing exclusions, prefer the original issue text over paraphrased rewrites.
|
||||
|
||||
@@ -21,7 +21,7 @@ It is also used when some findings are false positives and should be moved into
|
||||
4. Renumber the sorted list from 1 upward.
|
||||
5. Rewrite each finding concisely so the final list reads cleanly and consistently.
|
||||
6. If a finding is a false positive, do not keep it in the final list.
|
||||
7. Add false positives to the exclusions list using the existing schema in the repo or task context.
|
||||
7. Add false positives to the exclusions list using the existing schema in the repo or task context, and preserve the original finding wording as much as possible, including language and semantics.
|
||||
|
||||
## Resolution Flow
|
||||
|
||||
@@ -41,4 +41,5 @@ After the list is merged and ordered, resolve the remaining findings one by one.
|
||||
- Keep numbering contiguous after filtering and merging.
|
||||
- Preserve useful details like file path, location, and suggested fix.
|
||||
- Keep exclusions entries minimal and consistent with the project schema.
|
||||
- When writing exclusions, prefer the original issue text and language; only paraphrase if needed to fit the schema.
|
||||
- If the source already provides a severity or title, keep it unless it conflicts with the final ordering.
|
||||
|
||||
@@ -18,7 +18,7 @@ description: Triage findings, fix real issues, and exclude false positives.
|
||||
- info
|
||||
3. Renumber from 1.
|
||||
4. Fix real issues.
|
||||
5. Put false positives into `.gitea/ai-review/exclusions.json`.
|
||||
5. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
6. Add tests when behavior changes.
|
||||
|
||||
## Output Rules
|
||||
@@ -26,3 +26,4 @@ description: Triage findings, fix real issues, and exclude false positives.
|
||||
- Keep the final list short.
|
||||
- Keep numbering contiguous.
|
||||
- Preserve file path, location, and fix.
|
||||
- When writing exclusions, prefer the original issue text over paraphrased rewrites.
|
||||
|
||||
@@ -7,7 +7,7 @@ Use the triage-finding workflow for review issue lists:
|
||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
||||
4. Renumber from 1.
|
||||
5. Fix real issues with the smallest safe change.
|
||||
6. Put false positives into `.gitea/ai-review/exclusions.json`.
|
||||
6. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
7. Add or update tests when behavior changes.
|
||||
8. Re-check after each fix.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Use the triage-finding workflow for review issue lists:
|
||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
||||
4. Renumber from 1.
|
||||
5. Fix real issues with the smallest safe change.
|
||||
6. Put false positives into `.gitea/ai-review/exclusions.json`.
|
||||
6. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
7. Add or update tests when behavior changes.
|
||||
8. Re-check after each fix.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ When the task is to triage review findings, follow this workflow:
|
||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
||||
4. Renumber from 1 after sorting.
|
||||
5. Fix real issues with the smallest safe change.
|
||||
6. Add false positives to `.gitea/ai-review/exclusions.json`.
|
||||
6. Add false positives to `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
7. Add or update tests when behavior changes.
|
||||
8. Re-check the issue after each fix.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Use the triage-finding workflow for review issue lists:
|
||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
||||
4. Renumber from 1.
|
||||
5. Fix real issues with the smallest safe change.
|
||||
6. Put false positives into `.gitea/ai-review/exclusions.json`.
|
||||
6. Put false positives into `.gitea/ai-review/exclusions.json`, preserving the original wording, language, and semantics as much as possible.
|
||||
7. Add or update tests when behavior changes.
|
||||
8. Re-check after each fix.
|
||||
|
||||
|
||||
@@ -227,4 +227,4 @@ Amazon Q:直接輸入 `triage-findings 問題原始檔(文字或截圖)`
|
||||
|
||||
### 版本包含
|
||||
|
||||
提交時一併包含 `triage-findings` skill 與各平台入口檔;已存在檔案一律覆蓋,同步到最新內容;若 workspace 沒有某個同步檔,記憶區會保留原檔,不做刪除。未來若新增任何 skill 或新增其他平台的 skill 入口,必須同時把對應檔案複製進 Docker image,並把同步清單更新到會使用此 action 的目標專案,避免 action 與目標專案內容脫節。
|
||||
提交時一併包含 `triage-findings` skill 與各平台入口檔;已存在檔案一律覆蓋,同步到最新內容;若 workspace 沒有某個同步檔,記憶區會保留原檔,不做刪除。寫入 `.gitea/ai-review/exclusions.json` 時,盡量保留原始問題文字的語言與語意,避免過度改寫。未來若新增任何 skill 或新增其他平台的 skill 入口,必須同時把對應檔案複製進 Docker image,並把同步清單更新到會使用此 action 的目標專案,避免 action 與目標專案內容脫節。
|
||||
|
||||
+12
-6
@@ -16,13 +16,19 @@ function buildTable(findings) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 寫入 findings.json 到 workspace
|
||||
* 寫入 findings.json。
|
||||
* 預設寫到 workspace;若提供 mirrorDir,則同步寫入另一份供 repo commit 使用。
|
||||
*/
|
||||
export function saveFindings(workspace, findings) {
|
||||
const fullPath = path.join(workspace, FINDINGS_PATH);
|
||||
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
||||
fs.writeFileSync(fullPath, JSON.stringify(findings, null, 2) + '\n', 'utf8');
|
||||
console.log(` ✅ findings 寫入: ${fullPath} (${findings.length} 筆)`);
|
||||
export function saveFindings(workspace, findings, mirrorDir = null) {
|
||||
const targets = [workspace];
|
||||
if (mirrorDir && mirrorDir !== workspace) targets.push(mirrorDir);
|
||||
|
||||
for (const targetDir of targets) {
|
||||
const fullPath = path.join(targetDir, FINDINGS_PATH);
|
||||
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
||||
fs.writeFileSync(fullPath, JSON.stringify(findings, null, 2) + '\n', 'utf8');
|
||||
console.log(` ✅ findings 寫入: ${fullPath} (${findings.length} 筆)`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { saveFindings } from './comments.js';
|
||||
import { FINDINGS_PATH } from './config.js';
|
||||
|
||||
describe('saveFindings', () => {
|
||||
it('writes findings to workspace and mirror dirs when provided', () => {
|
||||
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'findings-ws-'));
|
||||
const mirrorDir = fs.mkdtempSync(path.join(os.tmpdir(), 'findings-mirror-'));
|
||||
const findings = [{ level: 'warning', role: 'Leo', location: 'file.js:1', suggestion: 'test' }];
|
||||
|
||||
saveFindings(workspace, findings, mirrorDir);
|
||||
|
||||
const workspaceText = fs.readFileSync(path.join(workspace, FINDINGS_PATH), 'utf8');
|
||||
const mirrorText = fs.readFileSync(path.join(mirrorDir, FINDINGS_PATH), 'utf8');
|
||||
assert.equal(workspaceText, JSON.stringify(findings, null, 2) + '\n');
|
||||
assert.equal(mirrorText, JSON.stringify(findings, null, 2) + '\n');
|
||||
});
|
||||
});
|
||||
+5
-1
@@ -5,9 +5,9 @@ import { fileURLToPath } from 'url';
|
||||
import { GITEA_SERVER_URL, GITEA_REPOSITORY, GITEA_TOKEN, PR_HEAD_BRANCH, FINDINGS_PATH } from './config.js';
|
||||
|
||||
const ACTION_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const GENERATED_SYNC_PATHS = [FINDINGS_PATH, '.gitea/ai-review/exclusions.json'];
|
||||
const remoteUrl = `${GITEA_SERVER_URL.replace(/\/$/, '')}/${GITEA_REPOSITORY}.git`;
|
||||
export const SYNC_PATHS = [
|
||||
FINDINGS_PATH,
|
||||
'.amazonq/rules/triage-findings.md',
|
||||
'.codex/skills/triage-findings/SKILL.md',
|
||||
'.codex/skills/triage-findings/agents/openai.yaml',
|
||||
@@ -86,6 +86,10 @@ export async function commitAndPush(workspace, repoDir, _spawnSync = spawnSync,
|
||||
if (existingSyncPaths.length > 0) {
|
||||
run(['add', ...existingSyncPaths], repoDir);
|
||||
}
|
||||
const generatedSyncPaths = GENERATED_SYNC_PATHS.filter(relPath => fs.existsSync(path.join(repoDir, relPath)));
|
||||
if (generatedSyncPaths.length > 0) {
|
||||
run(['add', ...generatedSyncPaths], repoDir);
|
||||
}
|
||||
|
||||
const status = run(['status', '--porcelain'], repoDir);
|
||||
if (!status) {
|
||||
|
||||
+21
-13
@@ -94,20 +94,28 @@ describe('commitAndPush', () => {
|
||||
});
|
||||
|
||||
it('adds skill and entry files together with findings', async () => {
|
||||
const repoDir = path.join(workspace, 'repo');
|
||||
fs.mkdirSync(path.join(repoDir, '.gitea/ai-review'), { recursive: true });
|
||||
fs.writeFileSync(path.join(repoDir, '.gitea/ai-review/findings.json'), '[]\n');
|
||||
fs.writeFileSync(path.join(repoDir, '.gitea/ai-review/exclusions.json'), '[]\n');
|
||||
const spawn = makeSpawn();
|
||||
await commitAndPush(workspace, path.join(workspace, 'repo'), spawn, sourceRoot);
|
||||
const addCall = spawn.calls.find(c => c.args[0] === 'add');
|
||||
assert.ok(addCall, 'expected git add to run');
|
||||
assert.ok(addCall.args.includes('.github/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(addCall.args.includes('.codex/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(addCall.args.includes('.codex/skills/triage-findings/agents/openai.yaml'));
|
||||
assert.ok(addCall.args.includes('.claude/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(addCall.args.includes('.gemini/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(addCall.args.includes('.github/copilot-instructions.md'));
|
||||
assert.ok(addCall.args.includes('.amazonq/rules/triage-findings.md'));
|
||||
assert.ok(addCall.args.includes('CLAUDE.md'));
|
||||
assert.ok(addCall.args.includes('GEMINI.md'));
|
||||
assert.ok(!addCall.args.includes('README.md'));
|
||||
await commitAndPush(workspace, repoDir, spawn, sourceRoot);
|
||||
const addCalls = spawn.calls.filter(c => c.args[0] === 'add');
|
||||
const skillAddCall = addCalls.find(c => c.args.includes('.github/skills/triage-findings/SKILL.md'));
|
||||
const generatedAddCall = addCalls.find(c => c.args.includes('.gitea/ai-review/exclusions.json'));
|
||||
assert.ok(skillAddCall, 'expected git add for synced skill files');
|
||||
assert.ok(generatedAddCall, 'expected git add for generated review files');
|
||||
assert.ok(skillAddCall.args.includes('.codex/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(skillAddCall.args.includes('.codex/skills/triage-findings/agents/openai.yaml'));
|
||||
assert.ok(skillAddCall.args.includes('.claude/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(skillAddCall.args.includes('.gemini/skills/triage-findings/SKILL.md'));
|
||||
assert.ok(skillAddCall.args.includes('.github/copilot-instructions.md'));
|
||||
assert.ok(skillAddCall.args.includes('.amazonq/rules/triage-findings.md'));
|
||||
assert.ok(skillAddCall.args.includes('CLAUDE.md'));
|
||||
assert.ok(skillAddCall.args.includes('GEMINI.md'));
|
||||
assert.ok(!skillAddCall.args.includes('README.md'));
|
||||
assert.ok(generatedAddCall.args.includes('.gitea/ai-review/findings.json'));
|
||||
assert.ok(generatedAddCall.args.includes('.gitea/ai-review/exclusions.json'));
|
||||
});
|
||||
|
||||
it('keeps repo copies when the source sync file is missing', async () => {
|
||||
|
||||
+4
-3
@@ -88,7 +88,8 @@ async function main() {
|
||||
|
||||
// Step6: 寫入 findings.json,依序發布 comment
|
||||
console.log('\n📝 Step5: Findings 寫入與 Comment 發布');
|
||||
saveFindings(WORKSPACE, filtered);
|
||||
const reviewDir = repoDir || WORKSPACE;
|
||||
saveFindings(WORKSPACE, filtered, reviewDir);
|
||||
try {
|
||||
await postOldFindingsComment(filtered);
|
||||
await postNewNonCriticalComment(filtered);
|
||||
@@ -102,7 +103,7 @@ async function main() {
|
||||
console.log('\n🔎 Step6: JSON 格式驗證');
|
||||
const missingPaths = [];
|
||||
for (const relPath of [FINDINGS_PATH, EXCLUSIONS_PATH]) {
|
||||
const fullPath = path.join(repoDir || WORKSPACE, relPath);
|
||||
const fullPath = path.join(reviewDir, relPath);
|
||||
try {
|
||||
const result = await validateJSONArrayFile(fullPath, relPath);
|
||||
if (!result.exists) missingPaths.push({ fullPath, relPath });
|
||||
@@ -117,7 +118,7 @@ async function main() {
|
||||
|
||||
// Step7: commit/push findings.json 到來源分支
|
||||
console.log('\n💾 Step7: 記憶區 Commit/Push');
|
||||
await commitAndPush(WORKSPACE, repoDir);
|
||||
await commitAndPush(WORKSPACE, repoDir || WORKSPACE);
|
||||
|
||||
// Step9: 有 critical 問題則 exit 1
|
||||
console.log('\n🚦 Step8: 嚴重問題檢查');
|
||||
|
||||
Reference in New Issue
Block a user