Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions apps/api/src/app/playground/playground.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,22 +195,8 @@ export class PlaygroundService {
// Check if this is a special message type and set type accordingly
let messageType = type;

// Log all messages that contain "branch" to debug
if (parsedLine.msg && typeof parsedLine.msg === 'string' && parsedLine.msg.toLowerCase().includes('branch')) {
this.logger.log(`[Backend] Branch-related messages: "${parsedLine.msg}"`);
this.logger.log(`[Backend] Has branchesInformation field: ${!!parsedLine.branchesInformation}`);
}


if (parsedLine.msg === 'packageFiles with updates' && parsedLine.config) {
this.logger.debug('✅ Backend: Found packageFiles with updates');
messageType = 'packageFilesWithUpdates';
} else if (parsedLine.msg === 'packageFiles' && parsedLine.packageFiles) {
this.logger.debug('✅ Backend: Found packageFiles');
messageType = 'packageFiles';
} else if (parsedLine.msg === 'branches info extended' && parsedLine.branchesInformation) {
this.logger.log(`✅ Backend: Found branches info extended with ${parsedLine.branchesInformation?.length} branches`);
messageType = 'branchesInfoExtended';
}

// Format the message with timestamp
Expand All @@ -220,7 +206,8 @@ export class PlaygroundService {
original: line,
time: timestamp,
msg: parsedLine.msg || '',
level: parsedLine.level || 'info'
level: parsedLine.level || 'info',
...(parsedLine.config && { config: parsedLine.config })
},
type: messageType
};
Expand Down
10 changes: 9 additions & 1 deletion apps/ui/src/app/playground/playground.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ <h2 class="text-xl font-semibold mb-2">Discovered Dependencies</h2>
<th>Dependency</th>
<th>Current Version</th>
<th>New Version</th>
<th>Registry URL</th>
<th>Status</th>
</tr>
</thead>
Expand All @@ -73,14 +74,21 @@ <h2 class="text-xl font-semibold mb-2">Discovered Dependencies</h2>
<td>{{ dep.name }}</td>
<td>{{ dep.currentVersion }}</td>
<td>{{ dep.newVersion }}</td>
<td>
<a *ngIf="dep.registryUrl" [href]="dep.registryUrl" target="_blank" rel="noopener noreferrer" class="text-decoration-none">
{{ dep.registryUrl }}
<i class="bi bi-box-arrow-up-right ms-1"></i>
</a>
<span *ngIf="!dep.registryUrl" class="text-muted">N/A</span>
</td>
<td>
<span *ngIf="dep.status === 'discovered'" class="badge bg-info">Discovered</span>
<span *ngIf="dep.status === 'update-available'" class="badge bg-success">Update Available</span>
<span *ngIf="!dep.status" class="badge bg-secondary">Unknown</span>
</td>
</tr>
<tr *ngIf="dependencies.length === 0">
<td colspan="5" class="text-center">No dependencies updated yet.</td>
<td colspan="6" class="text-center">No dependencies updated yet.</td>
</tr>
</tbody>
</table>
Expand Down
169 changes: 51 additions & 118 deletions apps/ui/src/app/playground/playground.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface Dependency {
manager?: string;
depType?: string;
status?: 'discovered' | 'update-available';
registryUrl?: string;
}

// Define the LogEntry interface for displaying logs with time
Expand Down Expand Up @@ -90,9 +91,6 @@ export class PlaygroundComponent implements OnInit, AfterViewChecked, OnDestroy
next: (logMessage: RenovateLogMessage) => {
// Run inside Angular zone to trigger change detection
this.ngZone.run(() => {
console.log('Received log message:', logMessage);
console.log('Received log message:', logMessage);

// Create a log entry from the message
const logEntry: LogEntry = {
message: logMessage.msg || '',
Expand All @@ -106,17 +104,6 @@ export class PlaygroundComponent implements OnInit, AfterViewChecked, OnDestroy
// Process packageFiles if present
if (logMessage.type === 'packageFilesWithUpdates' && logMessage.config) {
this.processPackageFilesWithUpdates(logMessage.config);
} else if (logMessage.type === 'packageFiles' && logMessage.packageFiles) {
this.processPackageFiles(logMessage.packageFiles);
} else if (logMessage.type === 'branchesInfoExtended' && logMessage.branchesInformation) {
// TODO: Replace with proper logging mechanism if needed
this.processBranchesInfoExtended(logMessage.branchesInformation);
} else if (logMessage.msg === 'branches info extended' && logMessage.branchesInformation) {
// Fallback: Check msg directly in case type wasn't set
this.processBranchesInfoExtended(logMessage.branchesInformation);
} else {
// Still try the regex-based approach as fallback
this.parseDependencyUpdate(logEntry.message);
}
// Force change detection and scroll to bottom
this.cdr.detectChanges();
Expand Down Expand Up @@ -188,122 +175,68 @@ export class PlaygroundComponent implements OnInit, AfterViewChecked, OnDestroy
}
}

private parseDependencyUpdate(log: string): void {
const regex = /Upgrading dependency (\S+) from (\S+) to (\S+)/;
const match = log.match(regex);

if (match) {
const dep: Dependency = {
type: 'npm', // This can be enhanced to detect other types
name: match[1],
currentVersion: match[2],
newVersion: match[3],
};
if (!this.dependencies.some((d) => d.name === dep.name && d.newVersion === dep.newVersion)) {
this.dependencies.push(dep);
}
}
}

private processPackageFiles(packageFiles: unknown): void {
if (!packageFiles || !Array.isArray(packageFiles)) {
return;
}

// Process each package file
for (const pkgFile of packageFiles) {
if (pkgFile.deps) {
// Process each dependency in the package file
for (const [depName, depInfo] of Object.entries(pkgFile.deps)) {
const dep = depInfo as Record<string, unknown>;
if (dep.updates && Array.isArray(dep.updates) && dep.updates.length > 0) {
// Get the latest update
const update = dep.updates[dep.updates.length - 1] as Record<string, unknown>;

const dependency: Dependency = {
type: pkgFile.manager || 'npm',
name: depName,
currentVersion: (dep.currentVersion as string) || 'unknown',
newVersion: (update.newVersion as string) || 'unknown',
manager: pkgFile.manager,
depType: (dep.depType as string) || undefined
};

// Check if this dependency is already in the array
if (!this.dependencies.some((d) => d.name === dependency.name && d.newVersion === dependency.newVersion)) {
this.dependencies.push(dependency);
}
}
}
}
}
}

private processPackageFilesWithUpdates(config: unknown): void {
const configObj = config as Record<string, unknown>;
if (!configObj || !configObj.regex || !Array.isArray(configObj.regex)) {
return;
}

// Process each regex configuration
for (const regexConfig of configObj.regex) {
if (regexConfig.deps && Array.isArray(regexConfig.deps)) {
// Process each dependency in the regex config
for (const dep of regexConfig.deps) {
if (dep.updates && Array.isArray(dep.updates) && dep.updates.length > 0) {
// Process each update for this dependency
for (const update of dep.updates) {
const dependency: Dependency = {
type: dep.datasource || 'unknown',
name: dep.packageName || dep.depName || 'unknown',
currentVersion: dep.currentVersion || dep.currentValue || 'unknown',
newVersion: update.newVersion || update.newValue || 'unknown',
manager: regexConfig.packageFile ? 'regex' : dep.datasource,
depType: dep.depType || update.updateType
};

this.addOrUpdateDependency(dependency);

// Process all manager types dynamically (npm, regex, docker, maven, etc.)
for (const [managerKey, managerValue] of Object.entries(configObj)) {
if (!Array.isArray(managerValue)) continue;

for (const packageFile of managerValue) {
if (packageFile.deps && Array.isArray(packageFile.deps)) {
for (const dep of packageFile.deps) {
// Check if there are updates for this dependency
if (dep.updates && Array.isArray(dep.updates) && dep.updates.length > 0) {
// Process each update
for (const update of dep.updates) {
const packageName = dep.packageName || dep.depName || 'unknown';
const registryUrl = this.constructFullPackageUrl(
dep.registryUrl || dep.sourceUrl,
packageName,
dep.datasource || managerKey
);

const dependency: Dependency = {
type: dep.datasource || managerKey,
name: packageName,
currentVersion: dep.currentVersion || dep.currentValue || 'unknown',
newVersion: update.newVersion || update.newValue || 'unknown',
manager: packageFile.manager || managerKey,
depType: dep.depType || update.updateType,
status: 'discovered', // Default status for discovered updates
registryUrl: registryUrl
};

this.addOrUpdateDependency(dependency);
}
}
}
}
}
}
}

private processBranchesInfoExtended(branchesInformation: unknown[]): void {
if (!branchesInformation || !Array.isArray(branchesInformation)) {
return;
private constructFullPackageUrl(baseUrl: string | undefined, packageName: string, datasource: string): string | undefined {
if (!baseUrl || !packageName) {
return undefined;
}

// Logging: Starting to process branchesInformation

// Process each branch
for (const branch of branchesInformation) {
const branchObj = branch as Record<string, unknown>;
// Check if upgrades exist
if (branchObj.upgrades && Array.isArray(branchObj.upgrades)) {
// Process each upgrade in the branch
for (const upgrade of branchObj.upgrades) {
const upgradeObj = upgrade as Record<string, unknown>;
const dependency: Dependency = {
type: (upgradeObj.datasource as string) || 'unknown',
name: (upgradeObj.depName as string) || (upgradeObj.packageName as string) || 'unknown',
currentVersion: (upgradeObj.currentVersion as string) || (upgradeObj.fixedVersion as string) || 'unknown',
newVersion: (upgradeObj.newVersion as string) || 'unknown',
manager: upgradeObj.datasource as string,
depType: upgradeObj.updateType as string,
// Set status based on prNo - null means repo is not onboarded yet
status: branchObj.prNo === null ? 'discovered' : 'update-available'
};

this.addOrUpdateDependency(dependency);
// dependencyCount++;
}
}
// Handle different datasource types
switch (datasource) {
case 'npm':
// For npm registries, append the package name
return `${baseUrl}/${packageName}`;
case 'github-tags':
case 'github-releases':
// GitHub URLs are typically already complete
return baseUrl.includes(packageName) ? baseUrl : `https://github.com/${packageName}`;
case 'node-version':
// Node.js distribution URL
return baseUrl;
default:
// For other types, try to append package name if it's not already there
return baseUrl.includes(packageName) ? baseUrl : `${baseUrl}/${packageName}`;
}

// For production, consider using a proper logging service instead of console.log
// Example: this.logger.info(`[UI Component] Extracted ${dependencyCount} dependencies. Total in table: ${this.dependencies.length}`);
}

private addOrUpdateDependency(dependency: Dependency): void {
Expand Down
1 change: 0 additions & 1 deletion apps/ui/src/app/playground/playground.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ export class PlaygroundService {

try {
const parsedData = JSON.parse(dataMatch[1]);
console.log('SSE parsed data:', parsedData);

// Handle the new backend format: {data: {original, time, msg, level}, type}
let logMessage: RenovateLogMessage;
Expand Down