Skip to content

Commit

Permalink
feat: enhance libyear output (#33981)
Browse files Browse the repository at this point in the history
  • Loading branch information
RahulGautamSingh authored Feb 1, 2025
1 parent 35a56c7 commit 1386cf7
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 31 deletions.
83 changes: 83 additions & 0 deletions lib/workers/repository/process/libyear.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe('workers/repository/process/libyear', () => {
deps: [
{
depName: 'some/image',
datasource: 'docker',
currentVersion: '1.0.0',
updates: [{ newVersion: '2.0.0' }],
},
Expand All @@ -30,6 +31,7 @@ describe('workers/repository/process/libyear', () => {
deps: [
{
depName: 'dep1',
datasource: 'npm',
currentVersion: '0.1.0',
currentVersionTimestamp: '2019-07-01T00:00:00Z' as Timestamp,
updates: [
Expand All @@ -56,6 +58,7 @@ describe('workers/repository/process/libyear', () => {
{
depName: 'dep2',
currentVersion: '1.0.0',
datasource: 'rubygems',
currentVersionTimestamp: '2019-07-01T00:00:00Z' as Timestamp,
updates: [
{
Expand All @@ -67,6 +70,7 @@ describe('workers/repository/process/libyear', () => {
{
depName: 'dep3',
currentVersion: '1.0.0',
datasource: 'rubygems',
updates: [
{
newVersion: '2.0.0',
Expand All @@ -76,6 +80,8 @@ describe('workers/repository/process/libyear', () => {
},
{
depName: 'dep4',
datasource: 'rubygems',
currentValue: '1.0.0', // coverage
},
],
},
Expand All @@ -100,6 +106,83 @@ describe('workers/repository/process/libyear', () => {
},
// eslint-disable-next-line no-loss-of-precision
totalLibYears: 1.5027322404371585,
totalDepsCount: 5,
outdatedDepsCount: 4,
},
'Repository libYears',
);
});

it('de-duplicates if same dep found in different files', () => {
// there are three package files with the same dependency + version but mixed datasources
const packageFiles = {
npm: [
{
packageFile: 'folder1/package.json',
deps: [
{
depName: 'dep1',
currentVersion: '0.1.0',
datasource: 'npm',
currentVersionTimestamp: '2019-07-01T00:00:00Z' as Timestamp,
updates: [
{
newVersion: '1.0.0',
releaseTimestamp: '2020-07-01T00:00:00Z' as Timestamp,
},
],
},
],
},
{
packageFile: 'folder2/package.json',
deps: [
{
depName: 'dep1',
currentVersion: '0.1.0',
datasource: 'npm',
currentVersionTimestamp: '2019-07-01T00:00:00Z' as Timestamp,
updates: [
{
newVersion: '1.0.0',
releaseTimestamp: '2020-07-01T00:00:00Z' as Timestamp,
},
],
},
],
},
],
regex: [
{
packageFile: 'folder3/package.json',
deps: [
{
depName: 'dep1',
currentVersion: '0.1.0',
datsource: 'docker',
currentVersionTimestamp: '2019-07-01T00:00:00Z' as Timestamp,
updates: [
{
newVersion: '1.0.0',
releaseTimestamp: '2020-07-01T00:00:00Z' as Timestamp,
},
],
},
],
},
],
};
calculateLibYears(packageFiles);
expect(logger.logger.debug).toHaveBeenCalledWith(
{
managerLibYears: {
npm: 1,
regex: 1,
},
// eslint-disable-next-line no-loss-of-precision
totalLibYears: 2,
totalDepsCount: 2,
outdatedDepsCount: 2,
},
'Repository libYears',
);
Expand Down
132 changes: 101 additions & 31 deletions lib/workers/repository/process/libyear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,129 @@ import { DateTime } from 'luxon';
import { logger } from '../../../logger';
import type { PackageFile } from '../../../modules/manager/types';

interface DepInfo {
depName: string;
manager: string;
datasource: string;
version: string;
file: string;
outdated?: boolean;
libYear?: number;
}
export function calculateLibYears(
packageFiles?: Record<string, PackageFile[]>,
): void {
if (!packageFiles) {
return;
}
const managerLibYears: Record<string, number> = {};
const allDeps: DepInfo[] = [];
for (const [manager, files] of Object.entries(packageFiles)) {
for (const file of files) {
let fileLibYears = 0;
for (const dep of file.deps) {
const depInfo: DepInfo = {
depName: dep.depName!,
manager,
file: file.packageFile,
datasource: dep.datasource!,
version: (dep.currentVersion ?? dep.currentValue)!,
};

if (!dep.updates?.length) {
allDeps.push(depInfo);
continue;
}

depInfo.outdated = true;
if (!dep.currentVersionTimestamp) {
logger.debug(`No currentVersionTimestamp for ${dep.depName}`);
allDeps.push(depInfo);
continue;
}
// timestamps are in ISO format
const currentVersionDate = DateTime.fromISO(
dep.currentVersionTimestamp,
);

if (dep.updates?.length) {
for (const update of dep.updates) {
if (!update.releaseTimestamp) {
logger.debug(
`No releaseTimestamp for ${dep.depName} update to ${update.newVersion}`,
);
continue;
}
const releaseDate = DateTime.fromISO(update.releaseTimestamp);
const libYears = releaseDate.diff(
currentVersionDate,
'years',
).years;
if (libYears >= 0) {
update.libYears = libYears;
}
for (const update of dep.updates) {
if (!update.releaseTimestamp) {
logger.debug(
`No releaseTimestamp for ${dep.depName} update to ${update.newVersion}`,
);
continue;
}
const releaseDate = DateTime.fromISO(update.releaseTimestamp);
const libYears = releaseDate.diff(currentVersionDate, 'years').years;
if (libYears >= 0) {
update.libYears = libYears;
}
// Set the highest libYears for the dep
const depLibYears = Math.max(
...dep.updates.map((update) => update.libYears ?? 0),
0,
);
fileLibYears += depLibYears;
}
// Set the highest libYears for the dep
const depLibYears = Math.max(
...dep.updates.map((update) => update.libYears ?? 0),
0,
);
depInfo.libYear = depLibYears;
allDeps.push(depInfo);
}
managerLibYears[manager] ??= 0;
managerLibYears[manager] += fileLibYears;
}
}
// Sum up the libYears for the repo
let totalLibYears = 0;
for (const libYears of Object.values(managerLibYears)) {
totalLibYears += libYears;

const [totalDepsCount, outdatedDepsCount, totalLibYears] = getCounts(allDeps);
logger.debug(
{
managerLibYears: getManagerLibYears(allDeps),
totalLibYears,
totalDepsCount,
outdatedDepsCount,
},
'Repository libYears',
);
}

function getManagerLibYears(deps: DepInfo[]): Record<string, number> {
/** {manager : {depKey: libYear }} */
const managerLibYears: Record<string, Record<string, number>> = {};
for (const dep of deps) {
const depKey = `${dep.depName}@${dep.version}@${dep.datasource}`;
const manager = dep.manager;
managerLibYears[manager] ??= {};
if (dep.libYear) {
if (!managerLibYears[manager][depKey]) {
managerLibYears[manager][depKey] = dep.libYear;
}
}
}
logger.debug({ managerLibYears, totalLibYears }, 'Repository libYears');

const res: Record<string, number> = {};
for (const [manager, deps] of Object.entries(managerLibYears)) {
const managerLibYear = Object.values(deps).reduce((sum, curr) => {
return sum + curr;
}, 0);
res[manager] = managerLibYear;
}

return res;
}

function getCounts(deps: DepInfo[]): [number, number, number] {
const distinctDeps = new Set<string>();
let totalDepsCount = 0,
outdatedDepsCount = 0,
totalLibYears = 0;
for (const dep of deps) {
const depKey = `${dep.depName}@${dep.version}@${dep.datasource}`;
if (!distinctDeps.has(depKey)) {
if (dep.outdated) {
outdatedDepsCount++;
}
if (dep.libYear) {
totalLibYears += dep.libYear;
}

totalDepsCount++;
distinctDeps.add(depKey);
}
}

return [totalDepsCount, outdatedDepsCount, totalLibYears];
}

0 comments on commit 1386cf7

Please sign in to comment.