Files
Sebastian Poxhofer 9717259ffc refactor(oxlint): enable no-else-return and unicorn/no-lonely-if (#44553)
Enable no-else-return (with allowElseIf: false) and unicorn/no-lonely-if
as errors in .oxlintrc.json and fix all 131 pre-existing violations
(91 no-else-return, 40 unicorn/no-lonely-if) across 98 files.

The no-else-return violations were fixed with the oxlint autofix
(iterated to a fixpoint, plus two else-if chains that required
--fix-dangerously) followed by Prettier formatting. One comment dropped
by the autofix in lib/modules/manager/pub/artifacts.ts was restored
manually. The unicorn/no-lonely-if violations were merged by hand,
preserving comments and coverage-ignore hints.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:11:21 +00:00

186 lines
5.7 KiB
TypeScript

import { isTruthy } from '@sindresorhus/is';
import { logger } from '../../../logger/index.ts';
import { withCache } from '../../../util/cache/package/with-cache.ts';
import { HttpError } from '../../../util/http/index.ts';
import * as p from '../../../util/promises.ts';
import { regEx } from '../../../util/regex.ts';
import { ensureTrailingSlash, joinUrlParts } from '../../../util/url.ts';
import * as pep440Versioning from '../../versioning/pep440/index.ts';
import { Datasource } from '../datasource.ts';
import type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';
import {
GalaxyV3,
GalaxyV3DetailedVersion,
GalaxyV3Versions,
} from './schema.ts';
const ansibleProtocolRegex = regEx(/^\S+\/api\/ansible\/.+/);
const repositoryRegex = regEx(
/^\S+\/api\/galaxy\/content\/(?<repository>[^/]+)/,
);
export class GalaxyCollectionDatasource extends Datasource {
static readonly id = 'galaxy-collection';
constructor() {
super(GalaxyCollectionDatasource.id);
}
override readonly customRegistrySupport = true;
override readonly registryStrategy = 'hunt';
override readonly defaultRegistryUrls = ['https://galaxy.ansible.com/api/'];
override readonly defaultVersioning = pep440Versioning.id;
override readonly releaseTimestampSupport = true;
override releaseTimestampNote =
'The release timestamp is determined from the `created_at` field in the results.';
// sourceUrl is returned in each release as well as the ReleaseResult
// the one present in release result is the sourceUrl of the latest release
override readonly sourceUrlSupport = 'release';
override readonly sourceUrlNote =
'The `sourceUrl` is determined from the `repository` field in the results.';
private async _getReleases({
packageName,
registryUrl,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
const baseUrl = this.constructBaseUrl(registryUrl!, packageName);
const { val: baseProject, err: baseErr } = await this.http
.getJsonSafe(baseUrl, GalaxyV3)
.onError((err) => {
if (!(err instanceof HttpError && err.response?.statusCode === 404)) {
logger.warn(
{ url: baseUrl, datasource: this.id, packageName, err },
'Error fetching from url',
);
}
})
.unwrap();
if (baseErr) {
this.handleGenericErrors(baseErr);
}
const versionsUrl = ensureTrailingSlash(joinUrlParts(baseUrl, 'versions'));
const { val: rawReleases, err: versionsErr } = await this.http
.getJsonSafe(versionsUrl, GalaxyV3Versions)
.onError((err) => {
logger.warn(
{ url: versionsUrl, datasource: this.id, packageName, err },
'Error fetching from url',
);
})
.unwrap();
if (versionsErr) {
this.handleGenericErrors(versionsErr);
}
const releases = rawReleases.map((value) => {
return {
...value,
isDeprecated: baseProject.deprecated,
};
});
// asynchronously get release details
const enrichedReleases = await p.map(
releases,
(release) => this.getVersionDetails(packageName, versionsUrl, release),
{ concurrency: 4 },
);
// filter failed versions
const filteredReleases = enrichedReleases.filter(isTruthy);
// extract base information which are only provided on the release from the newest release
// Find the source URL of the highest version release
const sourceUrlOfHighestRelease = enrichedReleases.find(
(release) => baseProject.highest_version.version === release.version,
)?.sourceUrl;
return {
releases: filteredReleases,
sourceUrl: sourceUrlOfHighestRelease,
};
}
getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {
return withCache(
{
namespace: `datasource-${GalaxyCollectionDatasource.id}`,
key: `getReleases:${config.packageName}`,
fallback: true,
},
() => this._getReleases(config),
);
}
constructBaseUrl(registryUrl: string, packageName: string): string {
const [namespace, projectName] = packageName.split('.');
if (ansibleProtocolRegex.test(registryUrl)) {
return ensureTrailingSlash(
joinUrlParts(registryUrl, 'api/v3/collections', namespace, projectName),
);
}
const repository =
repositoryRegex.exec(registryUrl)?.groups?.repository ?? 'published';
return ensureTrailingSlash(
joinUrlParts(
registryUrl,
'v3/plugin/ansible/content',
repository,
'collections/index',
namespace,
projectName,
),
);
}
private async _getVersionDetails(
packageName: string,
versionsUrl: string,
basicRelease: Release,
): Promise<Release> {
const detailedVersionUrl = ensureTrailingSlash(
joinUrlParts(versionsUrl, basicRelease.version),
);
const { val: rawDetailedVersion, err: versionsErr } = await this.http
.getJsonSafe(detailedVersionUrl, GalaxyV3DetailedVersion)
.onError((err) => {
logger.warn(
{ url: versionsUrl, datasource: this.id, packageName, err },
'Error fetching from url',
);
})
.unwrap();
if (versionsErr) {
this.handleGenericErrors(versionsErr);
}
return {
...rawDetailedVersion,
isDeprecated: basicRelease.isDeprecated,
releaseTimestamp: basicRelease.releaseTimestamp,
};
}
getVersionDetails(
packageName: string,
versionsUrl: string,
basicRelease: Release,
): Promise<Release> {
return withCache(
{
namespace: `datasource-${GalaxyCollectionDatasource.id}`,
key: `getVersionDetails:${versionsUrl}:${basicRelease.version}`,
ttlMinutes: 10080, // 1 week
},
() => this._getVersionDetails(packageName, versionsUrl, basicRelease),
);
}
}