fix: handle optional plugin field in CLI and web packages

Update all usages of project.tracker.plugin and project.scm.plugin
to use optional chaining since the plugin field is now optional
when package or path fields are specified.

Files updated:
- CLI: doctor.ts, status.ts, verify.ts
- Web: issues/route.ts, verify/route.ts, scm-webhooks.ts,
       serialize.ts, services.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
harshitsinghbhandari 2026-04-02 19:19:44 +05:30 committed by Gaurav Bhola
parent ebe6408586
commit f9d991d4fd
8 changed files with 20 additions and 14 deletions

View File

@ -343,7 +343,9 @@ async function sendTestNotifications(
const targets = new Map<string, NotifierTarget>();
for (const [name, notifierConfig] of configuredNotifiers) {
targets.set(notifierConfig.plugin, { label: name, pluginName: notifierConfig.plugin });
if (notifierConfig.plugin) {
targets.set(notifierConfig.plugin, { label: name, pluginName: notifierConfig.plugin });
}
}
for (const name of activeNotifierNames) {

View File

@ -386,7 +386,7 @@ export function registerStatus(program: Command): void {
let unverifiedTotal = 0;
for (const projectId of projectIds) {
const project: ProjectConfig | undefined = config.projects[projectId];
if (!project?.tracker) continue;
if (!project?.tracker?.plugin) continue;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker?.listIssues) continue;
try {

View File

@ -60,6 +60,10 @@ async function getTracker(
const registry = createPluginRegistry();
await registry.loadFromConfig(config, importPluginModuleFromSource);
if (!project.tracker.plugin) {
console.error(chalk.red("Project tracker plugin not configured."));
process.exit(1);
}
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker) {
console.error(chalk.red(`Tracker plugin "${project.tracker.plugin}" not found.`));

View File

@ -21,7 +21,7 @@ export async function GET(request: NextRequest) {
for (const [projectId, project] of Object.entries(config.projects)) {
if (projectFilter && projectId !== projectFilter) continue;
if (!project.tracker) continue;
if (!project.tracker?.plugin) continue;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker?.listIssues) continue;
@ -76,7 +76,7 @@ export async function POST(request: NextRequest) {
}
const project = config.projects[projectId];
if (!project.tracker) {
if (!project.tracker?.plugin) {
return NextResponse.json({ error: "No tracker configured for this project" }, { status: 422 });
}

View File

@ -64,7 +64,7 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: projectErr }, { status: 404 });
}
const project = config.projects[projectId];
if (!project.tracker) {
if (!project.tracker?.plugin) {
return NextResponse.json({ error: `Project ${projectId} has no tracker` }, { status: 422 });
}

View File

@ -34,7 +34,7 @@ export function findWebhookProjects(
pathname: string,
): WebhookProjectMatch[] {
return Object.entries(config.projects).flatMap(([projectId, project]) => {
if (!project.scm) return [];
if (!project.scm?.plugin) return [];
const webhookPath = getProjectWebhookPath(project);
if (!webhookPath || webhookPath !== pathname) return [];
const scm = registry.get<SCM>("scm", project.scm.plugin);

View File

@ -364,7 +364,7 @@ export async function enrichSessionsMetadata(
// Enrich issue labels (synchronous — must run before async title enrichment)
projects.forEach((project, i) => {
if (!dashboardSessions[i].issueUrl || !project?.tracker) return;
if (!dashboardSessions[i].issueUrl || !project?.tracker?.plugin) return;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker) return;
enrichSessionIssue(dashboardSessions[i], tracker, project);
@ -385,7 +385,7 @@ export async function enrichSessionsMetadata(
if (!dashboardSessions[i].issueUrl || !dashboardSessions[i].issueLabel) {
return Promise.resolve();
}
if (!project?.tracker) return Promise.resolve();
if (!project?.tracker?.plugin) return Promise.resolve();
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker) return Promise.resolve();
return enrichSessionIssueTitle(dashboardSessions[i], tracker, project);

View File

@ -137,7 +137,7 @@ async function labelIssuesForVerification(
for (const session of mergedSessions) {
const key = `${session.projectId}:${session.issueId}`;
const project = config.projects[session.projectId];
if (!project?.tracker) {
if (!project?.tracker?.plugin) {
processedIssues.add(key);
continue;
}
@ -180,7 +180,7 @@ async function relabelReopenedIssues(
registry: PluginRegistry,
): Promise<void> {
for (const [, project] of Object.entries(config.projects)) {
if (!project.tracker) continue;
if (!project.tracker?.plugin) continue;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker?.listIssues || !tracker.updateIssue) continue;
@ -240,7 +240,7 @@ export async function pollBacklog(): Promise<void> {
for (const [projectId, project] of Object.entries(config.projects)) {
if (availableSlots <= 0) break;
if (!project.tracker) continue;
if (!project.tracker?.plugin) continue;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker?.listIssues) continue;
@ -352,7 +352,7 @@ export async function getBacklogIssues(): Promise<Array<Issue & { projectId: str
try {
const { config, registry } = await getServices();
for (const [projectId, project] of Object.entries(config.projects)) {
if (!project.tracker) continue;
if (!project.tracker?.plugin) continue;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker?.listIssues) continue;
@ -380,7 +380,7 @@ export async function getVerifyIssues(): Promise<Array<Issue & { projectId: stri
try {
const { config, registry } = await getServices();
for (const [projectId, project] of Object.entries(config.projects)) {
if (!project.tracker) continue;
if (!project.tracker?.plugin) continue;
const tracker = registry.get<Tracker>("tracker", project.tracker.plugin);
if (!tracker?.listIssues) continue;
@ -404,6 +404,6 @@ export async function getVerifyIssues(): Promise<Array<Issue & { projectId: stri
/** Resolve the SCM plugin for a project. Returns null if not configured. */
export function getSCM(registry: PluginRegistry, project: ProjectConfig | undefined): SCM | null {
if (!project?.scm) return null;
if (!project?.scm?.plugin) return null;
return registry.get<SCM>("scm", project.scm.plugin);
}