Files
Sebastian Poxhofer a473e73b3e fix(linters): forbid inert counts in v8 coverage-ignore comments (#45287)
Adds a custom oxlint rule renovate/v8-ignore-no-count that flags the
count form '/* v8 ignore next <N> */'. The count is not honored by
vitest's ast-v8-to-istanbul hint parser, which captures only the
keyword (if/else/next/file); 'next' always exempts exactly the next
AST node. Trailing counts therefore suggest a line range that is never
applied and mislead readers.

The rule is autofixable (drops the count, preserving actual behavior)
and has been applied to all existing occurrences.
2026-08-22 11:25:31 +00:00

153 lines
4.7 KiB
TypeScript

import { type ZodType } from 'zod/v4';
import { logger } from '../../../logger/index.ts';
import { withCache } from '../../../util/cache/package/with-cache.ts';
import { clone } from '../../../util/clone.ts';
import { asTimestamp } from '../../../util/timestamp.ts';
import { ensureTrailingSlash } from '../../../util/url.ts';
import { Datasource } from '../datasource.ts';
import type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';
import {
JenkinsPluginsInfoResponse,
JenkinsPluginsVersionsResponse,
} from './schema.ts';
export class JenkinsPluginsDatasource extends Datasource {
static readonly id = 'jenkins-plugins';
constructor() {
super(JenkinsPluginsDatasource.id);
}
override readonly customRegistrySupport = true;
override readonly defaultRegistryUrls = ['https://updates.jenkins.io'];
override readonly registryStrategy = 'hunt';
private static readonly packageInfoPath = 'current/update-center.actual.json';
private static readonly packageVersionsPath = 'current/plugin-versions.json';
override readonly releaseTimestampSupport = true;
override readonly releaseTimestampNote =
'The releaseTimestamp is determined from the `releaseTimestamp` or `buildDate` field in the results.';
override readonly sourceUrlSupport = 'package';
override readonly sourceUrlNote =
'The source URL is determined from the `scm` field in the results.';
async getReleases({
packageName,
registryUrl,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
/* v8 ignore next -- should never happen */
if (!registryUrl) {
return null;
}
const updateSiteUrl = ensureTrailingSlash(registryUrl);
const plugins = await this.getJenkinsPluginInfo(updateSiteUrl);
const plugin = plugins[packageName];
if (!plugin) {
return null;
}
const result = clone(plugin);
const versions = await this.getJenkinsPluginVersions(updateSiteUrl);
const releases = versions[packageName];
result.releases = releases ? clone(releases) : [];
return result;
}
private async _getJenkinsPluginInfo(
updateSiteUrl: string,
): Promise<Record<string, ReleaseResult>> {
const { plugins } = await this.getJenkinsUpdateCenterResponse(
`${updateSiteUrl}${JenkinsPluginsDatasource.packageInfoPath}`,
JenkinsPluginsInfoResponse,
);
const info: Record<string, ReleaseResult> = {};
for (const name of Object.keys(plugins)) {
info[name] = {
releases: [], // releases
sourceUrl: plugins[name]?.scm,
};
}
return info;
}
getJenkinsPluginInfo(
updateSiteUrl: string,
): Promise<Record<string, ReleaseResult>> {
return withCache(
{
namespace: `datasource-${JenkinsPluginsDatasource.id}`,
key: 'info',
ttlMinutes: 1440,
},
() => this._getJenkinsPluginInfo(updateSiteUrl),
);
}
private async _getJenkinsPluginVersions(
updateSiteUrl: string,
): Promise<Record<string, Release[]>> {
const { plugins } = await this.getJenkinsUpdateCenterResponse(
`${updateSiteUrl}${JenkinsPluginsDatasource.packageVersionsPath}`,
JenkinsPluginsVersionsResponse,
);
const versions: Record<string, Release[]> = {};
for (const name of Object.keys(plugins)) {
versions[name] = Object.keys(plugins[name]).map((version) => {
const downloadUrl = plugins[name][version]?.url;
const buildDate = plugins[name][version]?.buildDate;
const releaseTimestamp =
plugins[name][version]?.releaseTimestamp ?? asTimestamp(buildDate);
const jenkins = plugins[name][version]?.requiredCore;
const constraints = jenkins ? { jenkins: [`>=${jenkins}`] } : undefined;
return {
version,
downloadUrl,
releaseTimestamp,
...(constraints && { constraints }),
};
});
}
return versions;
}
getJenkinsPluginVersions(
updateSiteUrl: string,
): Promise<Record<string, Release[]>> {
return withCache(
{
namespace: `datasource-${JenkinsPluginsDatasource.id}`,
key: 'versions',
},
() => this._getJenkinsPluginVersions(updateSiteUrl),
);
}
private async getJenkinsUpdateCenterResponse<T>(
url: string,
schema: ZodType<T>,
): Promise<T> {
let response: T;
try {
logger.debug(`jenkins-plugins: Fetching Jenkins plugins from ${url}`);
const startTime = Date.now();
response = (await this.http.getJson(url, schema)).body;
const durationMs = Math.round(Date.now() - startTime);
logger.debug(
{ durationMs },
`jenkins-plugins: Fetched Jenkins plugins from ${url}`,
);
} catch (err) /* istanbul ignore next */ {
this.handleGenericErrors(err);
}
return response;
}
}