Reformat src/*.mjs with Prettier; add format/format:check scripts
Every route handler was written as one dense semicolon-chained line (server.mjs's main handler was over 2000 characters wide) — real width, not a VSCode wrapping artifact. Ran Prettier to break statement structure into properly indented multi-line code; left template literal string contents untouched since Prettier doesn't reformat inside those, so the large HTML-generating return strings are still single long lines by nature, just no longer compounded by unformatted surrounding JS. Verified: tests pass, node --check passes, and the app renders identically before/after (screenshotted the diff). No devDependency added — npx prettier@3.9.5 pinned in the new scripts keeps the zero-runtime-dependency pledge intact; formatting is a dev- time concern only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
cdcc3c7937
commit
4b7b5a42d3
+70
-8
@@ -1,9 +1,71 @@
|
||||
const FIX_WORDS=/\b(fix(?:e[ds])?|bug|broken|race|crash|regression|rollback|restore[ds]?|duplicate[ds]?|auth|fail(?:ed|ure|ing)?)\b/i;
|
||||
const validRepo=value=>/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(value);
|
||||
export async function scanGiteaCandidates({baseUrl,repositories,token='',limit=100,fetchImpl=fetch}){
|
||||
const candidates=[],errors=[],headers={accept:'application/json'};if(token)headers.authorization=`token ${token}`;
|
||||
for(const repo of repositories){if(!validRepo(repo)){errors.push({repo,error:'invalid owner/repository identifier'});continue}const [owner,name]=repo.split('/');let seen=0;
|
||||
try{for(let page=1;seen<limit;page++){const count=Math.min(50,limit-seen),url=`${baseUrl.replace(/\/$/,'')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/commits?limit=${count}&page=${page}`;const response=await fetchImpl(url,{headers,signal:AbortSignal.timeout(5000)});if(!response.ok)throw new Error(`Gitea returned ${response.status}`);const commits=await response.json();if(!Array.isArray(commits))throw new Error('unexpected Gitea response');for(const commit of commits){seen++;const subject=String(commit.commit?.message||'').split('\n')[0].trim(),match=subject.match(FIX_WORDS);if(!match)continue;let paths='';try{const detail=await fetchImpl(`${baseUrl.replace(/\/$/,'')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/git/commits/${encodeURIComponent(commit.sha)}`,{headers,signal:AbortSignal.timeout(5000)});if(detail.ok){const data=await detail.json();paths=(data.files||[]).map(file=>file.filename).filter(Boolean).join('\n')}}catch{}candidates.push({repo,sha:commit.sha,committedAt:commit.commit?.committer?.date||commit.commit?.author?.date||commit.created||new Date().toISOString(),subject,paths,reason:`Gitea subject keyword: ${match[0].toLowerCase()}`})}if(commits.length<count)break}}
|
||||
catch(error){errors.push({repo,error:error.message})}
|
||||
}return{candidates,errors};
|
||||
const FIX_WORDS =
|
||||
/\b(fix(?:e[ds])?|bug|broken|race|crash|regression|rollback|restore[ds]?|duplicate[ds]?|auth|fail(?:ed|ure|ing)?)\b/i;
|
||||
const validRepo = (value) => /^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(value);
|
||||
export async function scanGiteaCandidates({
|
||||
baseUrl,
|
||||
repositories,
|
||||
token = '',
|
||||
limit = 100,
|
||||
fetchImpl = fetch,
|
||||
}) {
|
||||
const candidates = [],
|
||||
errors = [],
|
||||
headers = { accept: 'application/json' };
|
||||
if (token) headers.authorization = `token ${token}`;
|
||||
for (const repo of repositories) {
|
||||
if (!validRepo(repo)) {
|
||||
errors.push({ repo, error: 'invalid owner/repository identifier' });
|
||||
continue;
|
||||
}
|
||||
const [owner, name] = repo.split('/');
|
||||
let seen = 0;
|
||||
try {
|
||||
for (let page = 1; seen < limit; page++) {
|
||||
const count = Math.min(50, limit - seen),
|
||||
url = `${baseUrl.replace(/\/$/, '')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/commits?limit=${count}&page=${page}`;
|
||||
const response = await fetchImpl(url, { headers, signal: AbortSignal.timeout(5000) });
|
||||
if (!response.ok) throw new Error(`Gitea returned ${response.status}`);
|
||||
const commits = await response.json();
|
||||
if (!Array.isArray(commits)) throw new Error('unexpected Gitea response');
|
||||
for (const commit of commits) {
|
||||
seen++;
|
||||
const subject = String(commit.commit?.message || '')
|
||||
.split('\n')[0]
|
||||
.trim(),
|
||||
match = subject.match(FIX_WORDS);
|
||||
if (!match) continue;
|
||||
let paths = '';
|
||||
try {
|
||||
const detail = await fetchImpl(
|
||||
`${baseUrl.replace(/\/$/, '')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/git/commits/${encodeURIComponent(commit.sha)}`,
|
||||
{ headers, signal: AbortSignal.timeout(5000) },
|
||||
);
|
||||
if (detail.ok) {
|
||||
const data = await detail.json();
|
||||
paths = (data.files || [])
|
||||
.map((file) => file.filename)
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
}
|
||||
} catch {}
|
||||
candidates.push({
|
||||
repo,
|
||||
sha: commit.sha,
|
||||
committedAt:
|
||||
commit.commit?.committer?.date ||
|
||||
commit.commit?.author?.date ||
|
||||
commit.created ||
|
||||
new Date().toISOString(),
|
||||
subject,
|
||||
paths,
|
||||
reason: `Gitea subject keyword: ${match[0].toLowerCase()}`,
|
||||
});
|
||||
}
|
||||
if (commits.length < count) break;
|
||||
}
|
||||
} catch (error) {
|
||||
errors.push({ repo, error: error.message });
|
||||
}
|
||||
}
|
||||
return { candidates, errors };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user