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.9 KiB
TypeScript
153 lines
4.9 KiB
TypeScript
import { ExternalHostError } from '../../../types/errors/external-host-error.ts';
|
|
import { withCache } from '../../../util/cache/package/with-cache.ts';
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import { asTimestamp } from '../../../util/timestamp.ts';
|
|
import { joinUrlParts } from '../../../util/url.ts';
|
|
import {
|
|
isVersion,
|
|
id as semverVersioningId,
|
|
} from '../../versioning/semver/index.ts';
|
|
import { Datasource } from '../datasource.ts';
|
|
import type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';
|
|
|
|
const lineTerminationRegex = regEx(`\r?\n`);
|
|
const releaseBeginningChar = '\t{';
|
|
const releaseTerminationChar = '\t},';
|
|
const releaseDateRegex = regEx(
|
|
`Date\\{(?<year>\\d+),\\s+(?<month>\\d+),\\s+(?<day>\\d+)\\}`,
|
|
);
|
|
const releaseVersionRegex = regEx(
|
|
`Version\\{(?<versionMajor>\\d+),\\s+(?<versionMinor>\\d+),\\s+(?<patch>\\d+)\\}`,
|
|
);
|
|
const releaseFutureRegex = regEx(`Future:\\s+true`);
|
|
|
|
export class GolangVersionDatasource extends Datasource {
|
|
static readonly id = 'golang-version';
|
|
|
|
constructor() {
|
|
super(GolangVersionDatasource.id);
|
|
}
|
|
|
|
override readonly defaultRegistryUrls = [
|
|
'https://raw.githubusercontent.com/golang/website',
|
|
];
|
|
|
|
override readonly customRegistrySupport = true;
|
|
|
|
override readonly defaultVersioning = semverVersioningId;
|
|
|
|
override readonly releaseTimestampSupport = true;
|
|
override readonly releaseTimestampNote =
|
|
'The release timestamp is determined from the `Date` field in the results.';
|
|
override readonly sourceUrlSupport = 'package';
|
|
override readonly sourceUrlNote =
|
|
'We use the URL: https://github.com/golang/go.';
|
|
|
|
private async _getReleases({
|
|
registryUrl,
|
|
}: GetReleasesConfig): Promise<ReleaseResult | null> {
|
|
/* v8 ignore next -- should never happen */
|
|
if (!registryUrl) {
|
|
return null;
|
|
}
|
|
|
|
const res: ReleaseResult = {
|
|
homepage: 'https://go.dev/',
|
|
sourceUrl: 'https://github.com/golang/go',
|
|
releases: [],
|
|
};
|
|
|
|
const golangVersionsUrl = joinUrlParts(
|
|
registryUrl,
|
|
'/HEAD/internal/history/release.go',
|
|
);
|
|
|
|
const response = await this.http.getText(golangVersionsUrl);
|
|
|
|
const lines = response.body.split(lineTerminationRegex);
|
|
|
|
const startOfReleases = lines.indexOf('var Releases = []*Release{');
|
|
if (startOfReleases === -1) {
|
|
throw new ExternalHostError(
|
|
new Error('Invalid file - could not find the Releases section'),
|
|
);
|
|
}
|
|
|
|
// Remove part before releases
|
|
lines.splice(0, startOfReleases + 1);
|
|
|
|
// Parse the release list
|
|
let release: Omit<Release, 'version'> & { version?: string | undefined } = {
|
|
version: undefined,
|
|
};
|
|
let skipFutureRelease = false;
|
|
while (lines.length !== 0) {
|
|
const line = lines.shift()!;
|
|
if (line === releaseBeginningChar) {
|
|
if (release.version !== undefined) {
|
|
throw new ExternalHostError(
|
|
new Error(
|
|
'Invalid file - unexpected error while parsing a release',
|
|
),
|
|
);
|
|
}
|
|
} else if (line === releaseTerminationChar) {
|
|
if (skipFutureRelease) {
|
|
skipFutureRelease = false;
|
|
} else {
|
|
if (release.version === undefined) {
|
|
throw new ExternalHostError(
|
|
new Error('Invalid file - release has empty version'),
|
|
);
|
|
}
|
|
res.releases.push(release as Release);
|
|
}
|
|
release = { version: undefined };
|
|
} else {
|
|
const isFutureRelease = releaseFutureRegex.test(line);
|
|
if (isFutureRelease) {
|
|
skipFutureRelease = true;
|
|
}
|
|
const releaseDateMatch = releaseDateRegex.exec(line);
|
|
if (releaseDateMatch?.groups) {
|
|
// Make a valid UTC timestamp
|
|
const year = releaseDateMatch.groups.year.padStart(4, '0');
|
|
const month = releaseDateMatch.groups.month.padStart(2, '0');
|
|
const day = releaseDateMatch.groups.day.padStart(2, '0');
|
|
release.releaseTimestamp = asTimestamp(
|
|
`${year}-${month}-${day}T00:00:00.000Z`,
|
|
);
|
|
}
|
|
const releaseVersionMatch = releaseVersionRegex.exec(line);
|
|
if (releaseVersionMatch?.groups) {
|
|
release.version = `${releaseVersionMatch.groups.versionMajor}.${releaseVersionMatch.groups.versionMinor}.${releaseVersionMatch.groups.patch}`;
|
|
if (!isVersion(release.version)) {
|
|
throw new ExternalHostError(
|
|
new Error(`Version ${release.version} is not a valid semver`),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (res.releases.length === 0) {
|
|
throw new ExternalHostError(
|
|
new Error(`Invalid file - zero releases extracted`),
|
|
);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {
|
|
return withCache(
|
|
{
|
|
namespace: `datasource-${GolangVersionDatasource.id}`,
|
|
key: 'all',
|
|
fallback: true,
|
|
},
|
|
() => this._getReleases(config),
|
|
);
|
|
}
|
|
}
|