mirror of https://github.com/renovatebot/renovate
137 lines
4.5 KiB
TypeScript
137 lines
4.5 KiB
TypeScript
import { ExternalHostError } from '../../../types/errors/external-host-error';
|
|
import { cache } from '../../../util/cache/package/decorator';
|
|
import { regEx } from '../../../util/regex';
|
|
import { joinUrlParts } from '../../../util/url';
|
|
import { isVersion, id as semverVersioningId } from '../../versioning/semver';
|
|
import { Datasource } from '../datasource';
|
|
import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
|
|
|
|
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.';
|
|
|
|
@cache({ namespace: `datasource-${GolangVersionDatasource.id}`, key: 'all' })
|
|
async getReleases({
|
|
registryUrl,
|
|
}: GetReleasesConfig): Promise<ReleaseResult | null> {
|
|
// istanbul ignore if
|
|
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.get(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 = `${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;
|
|
}
|
|
}
|