Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ env:
# are we on a release branch?
DO_REALEASE: ${{ github.ref_name == github.event.repository.default_branch || github.ref_name == 'next' || startsWith(github.ref_name, 'maint/')}}
NODE_VERSION: 22
PDM_VERSION: 2.24.1 # renovate: datasource=pypi depName=pdm
PDM_VERSION: 2.24.2 # renovate: datasource=pypi depName=pdm
DRY_RUN: true
TEST_LEGACY_DECRYPTION: true
SPARSE_CHECKOUT: |-
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/manager/azure-pipelines/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ resources:
- container: linux
image: ubuntu:24.04
- container: python
image: python:3.13@sha256:e3424acce37cdb1d7f885b2d13c14a550a0b6b96ff8a58d2a08883f3f865fd1e
image: python:3.13@sha256:a4b2b11a9faf847c52ad07f5e0d4f34da59bad9d8589b8f2c476165d94c6b377

stages:
- stage: StageOne
Expand Down
3 changes: 3 additions & 0 deletions lib/modules/manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ export interface PackageDependency<T = Record<string, any>>
* override data source's default strategy.
*/
registryStrategy?: RegistryStrategy;

mostRecentTimestamp?: Timestamp;
isAbandoned?: boolean;
}

export interface Upgrade<T = Record<string, any>> extends PackageDependency<T> {
Expand Down
92 changes: 92 additions & 0 deletions lib/util/stats.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as memCache from './cache/memory';
import {
AbandonedPackageStats,
DatasourceCacheStats,
HttpCacheStats,
HttpStats,
Expand Down Expand Up @@ -574,4 +575,95 @@ describe('util/stats', () => {
});
});
});

describe('AbandonmentStats', () => {
beforeEach(() => {
memCache.init();
});

it('returns empty report', () => {
const res = AbandonedPackageStats.getReport();
expect(res).toEqual({});
});

it('writes data points', () => {
AbandonedPackageStats.write(
'npm',
'package1',
'2023-01-01T00:00:00.000Z',
);
AbandonedPackageStats.write(
'npm',
'package2',
'2023-02-01T00:00:00.000Z',
);
AbandonedPackageStats.write(
'docker',
'image1',
'2023-03-01T00:00:00.000Z',
);

const data = AbandonedPackageStats.getData();
expect(data).toEqual([
{
datasource: 'npm',
packageName: 'package1',
mostRecentTimestamp: '2023-01-01T00:00:00.000Z',
},
{
datasource: 'npm',
packageName: 'package2',
mostRecentTimestamp: '2023-02-01T00:00:00.000Z',
},
{
datasource: 'docker',
packageName: 'image1',
mostRecentTimestamp: '2023-03-01T00:00:00.000Z',
},
]);

const report = AbandonedPackageStats.getReport();
expect(report).toEqual({
npm: {
package1: '2023-01-01T00:00:00.000Z',
package2: '2023-02-01T00:00:00.000Z',
},
docker: {
image1: '2023-03-01T00:00:00.000Z',
},
});
});

it('logs report', () => {
AbandonedPackageStats.write(
'npm',
'package1',
'2023-01-01T00:00:00.000Z',
);
AbandonedPackageStats.write(
'docker',
'image1',
'2023-03-01T00:00:00.000Z',
);

AbandonedPackageStats.report();

expect(logger.logger.debug).toHaveBeenCalledTimes(1);
const [data, msg] = logger.logger.debug.mock.calls[0];
expect(msg).toBe('Abandoned package statistics');
expect(data).toEqual({
npm: {
package1: '2023-01-01T00:00:00.000Z',
},
docker: {
image1: '2023-03-01T00:00:00.000Z',
},
});
});

it('does not log report when no data', () => {
AbandonedPackageStats.report();
expect(logger.logger.debug).not.toHaveBeenCalled();
});
});
});
55 changes: 55 additions & 0 deletions lib/util/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,3 +520,58 @@ export class ObsoleteCacheHitLogger {
}
}
/* v8 ignore stop: temporary code */

interface AbandonedPackage {
datasource: string;
packageName: string;
mostRecentTimestamp: string;
}

type AbandonedPackageReport = Record<string, Record<string, string>>;

export class AbandonedPackageStats {
static getData(): AbandonedPackage[] {
return memCache.get<AbandonedPackage[]>('abandonment-stats') ?? [];
}

private static setData(data: AbandonedPackage[]): void {
memCache.set('abandonment-stats', data);
}

static write(
datasource: string,
packageName: string,
mostRecentTimestamp: string,
): void {
const data = this.getData();
data.push({ datasource, packageName, mostRecentTimestamp });
this.setData(data);
}

static getReport(): AbandonedPackageReport {
const data = this.getData();
const result: AbandonedPackageReport = {};

for (const { datasource, packageName, mostRecentTimestamp } of data) {
result[datasource] ??= {};
result[datasource][packageName] = mostRecentTimestamp;
}

const sortedResult: AbandonedPackageReport = {};
for (const datasource of Object.keys(result).sort()) {
sortedResult[datasource] = {};
for (const packageName of Object.keys(result[datasource]).sort()) {
sortedResult[datasource][packageName] = result[datasource][packageName];
}
}

return sortedResult;
}

static report(): void {
const report = this.getReport();
if (Object.keys(report).length > 0) {
logger.debug(report, 'Abandoned package statistics');
}
}
}
2 changes: 2 additions & 0 deletions lib/workers/repository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as queue from '../../util/http/queue';
import * as throttle from '../../util/http/throttle';
import { addSplit, getSplits, splitInit } from '../../util/split';
import {
AbandonedPackageStats,
DatasourceCacheStats,
HttpCacheStats,
HttpStats,
Expand Down Expand Up @@ -149,6 +150,7 @@ export async function renovateRepository(
HttpCacheStats.report();
LookupStats.report();
ObsoleteCacheHitLogger.report();
AbandonedPackageStats.report();
const cloned = isCloned();
logger.info({ cloned, durationMs: splits.total }, 'Repository finished');
resetRepositoryLogLevelRemaps();
Expand Down
6 changes: 6 additions & 0 deletions lib/workers/repository/process/lookup/abandonment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DateTime } from 'luxon';
import { logger } from '../../../../logger';
import type { ReleaseResult } from '../../../../modules/datasource/types';
import { toMs } from '../../../../util/pretty-time';
import { AbandonedPackageStats } from '../../../../util/stats';
import type { LookupUpdateConfig } from './types';

export function calculateAbandonment(
Expand Down Expand Up @@ -63,5 +64,10 @@ export function calculateAbandonment(
'Calculated abandonment status',
);

if (isAbandoned) {
const { datasource, packageName } = config;
AbandonedPackageStats.write(datasource, packageName, mostRecentTimestamp);
}

return releaseResult;
}
2 changes: 2 additions & 0 deletions lib/workers/repository/process/lookup/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ export async function lookupUpdates(
'dependencyUrl',
'lookupName',
'packageScope',
'mostRecentTimestamp',
'isAbandoned',
]);

const latestVersion = dependency.tags?.latest;
Expand Down
3 changes: 3 additions & 0 deletions lib/workers/repository/process/lookup/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
} from '../../../../modules/manager/types';
import type { SkipReason } from '../../../../types';
import type { MergeConfidence } from '../../../../util/merge-confidence/types';
import type { Timestamp } from '../../../../util/timestamp';

export interface FilterConfig {
allowedVersions?: string;
Expand Down Expand Up @@ -75,4 +76,6 @@ export interface UpdateResult {
currentVersionTimestamp?: string;
vulnerabilityFixVersion?: string;
vulnerabilityFixStrategy?: string;
mostRecentTimestamp?: Timestamp | null;
isAbandoned?: boolean;
}
6 changes: 3 additions & 3 deletions tools/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ ARG BASE_IMAGE_TYPE=slim
# --------------------------------------
# slim image
# --------------------------------------
FROM ghcr.io/renovatebot/base-image:9.70.1@sha256:a8792db7337b6079536fbbc5e0a2fc712d6047cd2d186335e644460b54359a5e AS slim-base
FROM ghcr.io/renovatebot/base-image:9.70.3@sha256:01ad59538532d0d9eb4c072a4b3de0131dfee2e25ed802b4d7606e366e09e575 AS slim-base

# --------------------------------------
# full image
# --------------------------------------
FROM ghcr.io/renovatebot/base-image:9.70.1-full@sha256:a7c383069d0b83483261b6d456c2d6401a204aca09a284fdd195c5a9551040f8 AS full-base
FROM ghcr.io/renovatebot/base-image:9.70.3-full@sha256:3c7e3c75b673e337bd8190e0c34a83493ec7dadf669cdd204db64a1d356b2e84 AS full-base

ENV RENOVATE_BINARY_SOURCE=global

# --------------------------------------
# build image
# --------------------------------------
FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:9.70.1@sha256:a8792db7337b6079536fbbc5e0a2fc712d6047cd2d186335e644460b54359a5e AS build
FROM --platform=$BUILDPLATFORM ghcr.io/renovatebot/base-image:9.70.3@sha256:01ad59538532d0d9eb4c072a4b3de0131dfee2e25ed802b4d7606e366e09e575 AS build

# We want a specific node version here
# renovate: datasource=github-releases packageName=containerbase/node-prebuild versioning=node
Expand Down
Loading