Skip to content

Commit

Permalink
feat: libyear (#33521)
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins authored Jan 11, 2025
1 parent 4466ccd commit db60332
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/modules/manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export interface LookupUpdate {
releaseTimestamp?: any;
newVersionAgeInDays?: number;
registryUrl?: string;
libYears?: number;
}

/**
Expand Down Expand Up @@ -144,6 +145,7 @@ export interface PackageDependency<T = Record<string, any>>
digestOneAndOnly?: boolean;
fixedVersion?: string;
currentVersion?: string;
currentVersionTimestamp?: string;
lockedVersion?: string;
propSource?: string;
registryUrls?: string[] | null;
Expand Down
2 changes: 2 additions & 0 deletions lib/workers/repository/process/extract-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { extractAllDependencies } from '../extract';
import { generateFingerprintConfig } from '../extract/extract-fingerprint-config';
import { branchifyUpgrades } from '../updates/branchify';
import { fetchUpdates } from './fetch';
import { calculateLibYears } from './libyear';
import { sortBranches } from './sort';
import { Vulnerabilities } from './vulnerabilities';
import type { WriteUpdateResult } from './write';
Expand Down Expand Up @@ -211,6 +212,7 @@ export async function lookup(
): Promise<ExtractResult> {
await fetchVulnerabilities(config, packageFiles);
await fetchUpdates(config, packageFiles);
calculateLibYears(packageFiles);
const { branches, branchList } = await branchifyUpgrades(
config,
packageFiles,
Expand Down
104 changes: 104 additions & 0 deletions lib/workers/repository/process/libyear.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { logger } from '../../../../test/util';
import type { PackageFile } from '../../../modules/manager/types';
import { calculateLibYears } from './libyear';

describe('workers/repository/process/libyear', () => {
describe('calculateLibYears', () => {
it('returns early if no packageFiles', () => {
calculateLibYears(undefined);
expect(logger.logger.debug).not.toHaveBeenCalled();
});

it('calculates libYears', () => {
const packageFiles: Record<string, PackageFile[]> = {
dockerfile: [
{
packageFile: 'Dockerfile',
deps: [
{
depName: 'some/image',
currentVersion: '1.0.0',
updates: [{ newVersion: '2.0.0' }],
},
],
},
],
npm: [
{
packageFile: 'package.json',
deps: [
{
depName: 'dep1',
currentVersion: '0.1.0',
currentVersionTimestamp: '2019-07-01T00:00:00Z',
updates: [
{
newVersion: '1.0.0',
releaseTimestamp: '2020-01-01T00:00:00Z',
},
{
newVersion: '2.0.0',
releaseTimestamp: '2020-07-01T00:00:00Z',
},
{
newVersion: '3.0.0',
},
],
},
],
},
],
bundler: [
{
packageFile: 'Gemfile',
deps: [
{
depName: 'dep2',
currentVersion: '1.0.0',
currentVersionTimestamp: '2019-07-01T00:00:00Z',
updates: [
{
newVersion: '2.0.0',
releaseTimestamp: '2020-01-01T00:00:00Z',
},
],
},
{
depName: 'dep3',
currentVersion: '1.0.0',
updates: [
{
newVersion: '2.0.0',
releaseTimestamp: '2020-01-01T00:00:00Z',
},
],
},
{
depName: 'dep4',
},
],
},
],
};
calculateLibYears(packageFiles);
expect(logger.logger.debug).toHaveBeenCalledWith(
'No releaseTimestamp for some/image update to 2.0.0',
);
expect(logger.logger.debug).toHaveBeenCalledWith(
'No releaseTimestamp for dep1 update to 3.0.0',
);
expect(logger.logger.debug).toHaveBeenCalledWith(
{
managerLibYears: {
bundler: 0.5027322404371585,
dockerfile: 0,
npm: 1,
},
// eslint-disable-next-line no-loss-of-precision
totalLibYears: 1.5027322404371585,
},
'Repository libYears',
);
});
});
});
59 changes: 59 additions & 0 deletions lib/workers/repository/process/libyear.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { DateTime } from 'luxon';
import { logger } from '../../../logger';
import type { PackageFile } from '../../../modules/manager/types';

export function calculateLibYears(
packageFiles?: Record<string, PackageFile[]>,
): void {
if (!packageFiles) {
return;
}
const managerLibYears: Record<string, number> = {};
for (const [manager, files] of Object.entries(packageFiles)) {
for (const file of files) {
let fileLibYears = 0;
for (const dep of file.deps) {
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;
}
if (!dep.currentVersionTimestamp) {
logger.debug(`No currentVersionTimestamp for ${dep.depName}`);
continue;
}
// timestamps are in ISO format
const currentVersionDate = DateTime.fromISO(
dep.currentVersionTimestamp,
);
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;
}
}
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;
}
logger.debug({ managerLibYears, totalLibYears }, 'Repository libYears');
}

0 comments on commit db60332

Please sign in to comment.