mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 10:09:50 +00:00
a473e73b3e
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.
153 lines
4.7 KiB
TypeScript
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;
|
|
}
|
|
}
|