Files
renovate/lib/util/minimum-release-age.ts
Sebastian Poxhofer 4215f35059 feat(config): add minimumReleaseAgeBuffer option (#45577)
* feat(config): add minimumReleaseAgeBuffer option

Adds a new config option which extends the time Renovate waits before
suggesting an update by a percentage of minimumReleaseAge. This gives
companion packages that are published after the main package (e.g.
platform-specific binaries) time to pass the package manager's own
release age cooldown, avoiding lock file artifact errors.

* feat(config): make minimumReleaseAgeBuffer a duration with 10 minutes default

* feat(config): raise minimumReleaseAgeBuffer default to 30 minutes
2026-09-17 07:08:00 +00:00

77 lines
2.2 KiB
TypeScript

import { isNonEmptyString } from '@sindresorhus/is';
import type { MinimumReleaseAgeBehaviour } from '../config/types.ts';
import { getElapsedMs } from './date.ts';
import { coerceNumber } from './number.ts';
import { toMs } from './pretty-time.ts';
import type { Timestamp } from './timestamp.ts';
export interface MinimumReleaseAgeCheckResult {
isPending: boolean;
/** Effective minimum release age, including `minimumReleaseAgeBuffer`. */
minimumReleaseAgeMs: number;
hasTimestamp: boolean;
}
/**
* Calculates the effective minimum release age in milliseconds, extended by
* the `minimumReleaseAgeBuffer` duration if configured.
*/
export function calculateMinimumReleaseAgeMs(config: {
minimumReleaseAge?: string | null;
minimumReleaseAgeBuffer?: string | null;
}): number {
const minimumReleaseAgeMs = isNonEmptyString(config.minimumReleaseAge)
? coerceNumber(toMs(config.minimumReleaseAge), 0)
: 0;
if (!minimumReleaseAgeMs) {
return 0;
}
const bufferMs = isNonEmptyString(config.minimumReleaseAgeBuffer)
? coerceNumber(toMs(config.minimumReleaseAgeBuffer), 0)
: 0;
return minimumReleaseAgeMs + Math.max(bufferMs, 0);
}
/**
* Checks whether a release satisfies `minimumReleaseAge`, extended by
* `minimumReleaseAgeBuffer` if configured.
*
* Separate from `internalChecksFilter` to allow reuse, and lives here so that
* managers can import it without an import cycle.
*/
export function checkMinimumReleaseAge(
config: {
minimumReleaseAge?: string | null;
minimumReleaseAgeBuffer?: string | null;
minimumReleaseAgeBehaviour?: MinimumReleaseAgeBehaviour | null;
},
releaseTimestamp: Timestamp | null | undefined,
): MinimumReleaseAgeCheckResult {
const minimumReleaseAgeMs = calculateMinimumReleaseAgeMs(config);
if (!minimumReleaseAgeMs) {
return {
isPending: false,
minimumReleaseAgeMs,
hasTimestamp: !!releaseTimestamp,
};
}
if (releaseTimestamp) {
return {
isPending: getElapsedMs(releaseTimestamp) < minimumReleaseAgeMs,
minimumReleaseAgeMs,
hasTimestamp: true,
};
}
return {
isPending: config.minimumReleaseAgeBehaviour === 'timestamp-required',
minimumReleaseAgeMs,
hasTimestamp: false,
};
}