feat: enhance CodeFeed with repo allowlist/denylist, optional timestamp filtering, and verbose logging

This commit is contained in:
2025-09-14 20:27:51 +00:00
parent 98f5c466a6
commit f21aa58c18
5 changed files with 214 additions and 138 deletions

View File

@@ -20,6 +20,10 @@ export class CodeFeed {
// allow/deny filters
private orgAllowlist?: string[];
private orgDenylist?: string[];
private repoAllowlist?: string[]; // entries like "org/repo"
private repoDenylist?: string[]; // entries like "org/repo"
private untilTimestamp?: string; // optional upper bound on commit timestamps
private verbose?: boolean; // optional metrics logging
constructor(
baseUrl: string,
@@ -32,6 +36,10 @@ export class CodeFeed {
taggedOnly?: boolean;
orgAllowlist?: string[];
orgDenylist?: string[];
repoAllowlist?: string[];
repoDenylist?: string[];
untilTimestamp?: string;
verbose?: boolean;
}
) {
this.baseUrl = baseUrl;
@@ -45,6 +53,10 @@ export class CodeFeed {
this.enableTaggedOnly = options?.taggedOnly ?? false;
this.orgAllowlist = options?.orgAllowlist;
this.orgDenylist = options?.orgDenylist;
this.repoAllowlist = options?.repoAllowlist;
this.repoDenylist = options?.repoDenylist;
this.untilTimestamp = options?.untilTimestamp;
this.verbose = options?.verbose ?? false;
this.cache = [];
// npm registry instance for version lookups
this.npmRegistry = new plugins.smartnpm.NpmRegistry();
@@ -85,9 +97,18 @@ export class CodeFeed {
)
);
// flatten to [{ owner, name }]
const allRepos = orgs.flatMap((org, i) =>
let allRepos = orgs.flatMap((org, i) =>
repoLists[i].map((r) => ({ owner: org, name: r.name }))
);
// apply repo allow/deny filters using slug "org/repo"
if (this.repoAllowlist && this.repoAllowlist.length > 0) {
const allow = new Set(this.repoAllowlist.map((s) => s.toLowerCase()));
allRepos = allRepos.filter(({ owner, name }) => allow.has(`${owner}/${name}`.toLowerCase()));
}
if (this.repoDenylist && this.repoDenylist.length > 0) {
const deny = new Set(this.repoDenylist.map((s) => s.toLowerCase()));
allRepos = allRepos.filter(({ owner, name }) => !deny.has(`${owner}/${name}`.toLowerCase()));
}
// 3) probe latest commit per repo and fetch full list only if new commits exist
const commitJobs = allRepos.map(({ owner, name }) =>
@@ -127,12 +148,14 @@ export class CodeFeed {
// 4) build new commit entries with tagging, npm and changelog support
const newResults: plugins.interfaces.ICommitResult[] = [];
let reposWithNewCommits = 0;
for (const { owner, name, commits } of commitResults) {
// skip repos with no new commits
if (commits.length === 0) {
this.changelogContent = '';
continue;
}
reposWithNewCommits++;
// load changelog for this repo
await this.loadChangelogFromRepo(owner, name);
// fetch tags for this repo
@@ -178,6 +201,13 @@ export class CodeFeed {
changelogEntry = this.getChangelogForVersion(versionFromTag);
}
}
// optionally enforce an upper bound on commit timestamps
if (this.untilTimestamp) {
const ts = new Date(c.commit.author.date).getTime();
if (ts > new Date(this.untilTimestamp).getTime()) {
continue;
}
}
newResults.push({
baseUrl: this.baseUrl,
org: owner,
@@ -212,6 +242,11 @@ export class CodeFeed {
if (this.enableTaggedOnly) {
return this.cache.filter((c) => c.tagged === true);
}
if (this.verbose) {
console.log(
`[CodeFeed] orgs=${orgs.length} repos=${allRepos.length} reposWithNew=${reposWithNewCommits} commits=${this.cache.length} (cached)`
);
}
return this.cache;
}
// no caching: apply tagged-only filter if requested
@@ -223,10 +258,13 @@ export class CodeFeed {
return true;
});
unique.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
if (this.enableTaggedOnly) {
return unique.filter((c) => c.tagged === true);
const result = this.enableTaggedOnly ? unique.filter((c) => c.tagged === true) : unique;
if (this.verbose) {
console.log(
`[CodeFeed] orgs=${orgs.length} repos=${allRepos.length} reposWithNew=${reposWithNewCommits} commits=${result.length}`
);
}
return unique;
return result;
}
/**