renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
173 lines • 7.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PackagistDatasource = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const zod_1 = require("zod");
const logger_1 = require("../../../logger");
const external_host_error_1 = require("../../../types/errors/external-host-error");
const decorator_1 = require("../../../util/cache/package/decorator");
const hostRules = tslib_1.__importStar(require("../../../util/host-rules"));
const p = tslib_1.__importStar(require("../../../util/promises"));
const url_1 = require("../../../util/url");
const composerVersioning = tslib_1.__importStar(require("../../versioning/composer"));
const datasource_1 = require("../datasource");
const schema_1 = require("./schema");
class PackagistDatasource extends datasource_1.Datasource {
static id = 'packagist';
constructor() {
super(PackagistDatasource.id);
}
defaultRegistryUrls = ['https://repo.packagist.org'];
defaultVersioning = composerVersioning.id;
registryStrategy = 'hunt';
releaseTimestampSupport = true;
releaseTimestampNote = 'The release timestamp is determined from the `time` field in the results.';
// Note: this can be changed to 'release', as the source is present in each release but we remove it while processing
sourceUrlSupport = 'package';
sourceUrlNote = 'The source URL is determined from `source` field in the results.';
// We calculate auth at this datasource layer so that we can know whether it's safe to cache or not
static getHostOpts(url) {
const { username, password } = hostRules.find({
hostType: PackagistDatasource.id,
url,
});
return username && password ? { username, password } : {};
}
async getJson(url, schema) {
const opts = PackagistDatasource.getHostOpts(url);
const { body } = await this.http.getJson(url, opts, schema);
return body;
}
async getRegistryMeta(regUrl) {
const url = (0, url_1.resolveBaseUrl)(regUrl, 'packages.json');
const result = await this.getJson(url, schema_1.RegistryMeta);
return result;
}
static isPrivatePackage(regUrl) {
const opts = PackagistDatasource.getHostOpts(regUrl);
return !!opts.password;
}
static getPackagistFileUrl(regUrl, regFile) {
const { key, hash } = regFile;
const fileName = hash
? key.replace('%hash%', hash)
: /* istanbul ignore next: hard to test */ key;
const url = (0, url_1.resolveBaseUrl)(regUrl, fileName);
return url;
}
async getPackagistFile(regUrl, regFile) {
const url = PackagistDatasource.getPackagistFileUrl(regUrl, regFile);
const packagistFile = await this.getJson(url, schema_1.PackagistFile);
return packagistFile;
}
async fetchProviderPackages(regUrl, meta) {
await p.map(meta.files, async (file) => {
const res = await this.getPackagistFile(regUrl, file);
Object.assign(meta.providerPackages, res.providers);
});
}
async fetchIncludesPackages(regUrl, meta) {
await p.map(meta.includesFiles, async (file) => {
const res = await this.getPackagistFile(regUrl, file);
for (const [key, val] of Object.entries(res.packages)) {
meta.includesPackages[key] = (0, schema_1.extractDepReleases)(val);
}
});
}
async packagistV2Lookup(registryUrl, metadataUrl, packageName) {
const pkgUrl = (0, url_1.replaceUrlPath)(registryUrl, metadataUrl.replace('%package%', packageName));
const pkgPromise = this.getJson(pkgUrl, zod_1.z.unknown());
const devUrl = (0, url_1.replaceUrlPath)(registryUrl, metadataUrl.replace('%package%', `${packageName}~dev`));
const devPromise = this.getJson(devUrl, zod_1.z.unknown()).then((x) => x, () => null);
const responses = await Promise.all([
pkgPromise,
devPromise,
]).then((responses) => responses.filter(is_1.default.object));
return (0, schema_1.parsePackagesResponses)(packageName, responses);
}
getPkgUrl(packageName, registryUrl, registryMeta) {
if (registryMeta.providersUrl &&
packageName in registryMeta.providerPackages) {
let url = registryMeta.providersUrl.replace('%package%', packageName);
const hash = registryMeta.providerPackages[packageName];
if (hash) {
url = url.replace('%hash%', hash);
}
return (0, url_1.replaceUrlPath)(registryUrl, url);
}
if (registryMeta.providersLazyUrl) {
return (0, url_1.replaceUrlPath)(registryUrl, registryMeta.providersLazyUrl.replace('%package%', packageName));
}
return null;
}
async getReleases({ packageName, registryUrl, }) {
logger_1.logger.trace(`getReleases(${packageName})`);
/* v8 ignore next 3 -- should never happen */
if (!registryUrl) {
return null;
}
try {
const meta = await this.getRegistryMeta(registryUrl);
if (meta.availablePackages &&
!meta.availablePackages.includes(packageName)) {
return null;
}
if (meta.metadataUrl) {
const packagistResult = await this.packagistV2Lookup(registryUrl, meta.metadataUrl, packageName);
return packagistResult;
}
if (meta.packages[packageName]) {
const result = (0, schema_1.extractDepReleases)(meta.packages[packageName]);
return result;
}
await this.fetchIncludesPackages(registryUrl, meta);
if (meta.includesPackages[packageName]) {
return meta.includesPackages[packageName];
}
await this.fetchProviderPackages(registryUrl, meta);
const pkgUrl = this.getPkgUrl(packageName, registryUrl, meta);
if (!pkgUrl) {
return null;
}
const pkgRes = await this.getJson(pkgUrl, schema_1.PackagesResponse);
const dep = (0, schema_1.extractDepReleases)(pkgRes.packages[packageName]);
logger_1.logger.trace({ dep }, 'dep');
return dep;
}
catch (err) /* istanbul ignore next */ {
if (err.host === 'packagist.org') {
if (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT') {
throw new external_host_error_1.ExternalHostError(err);
}
if (err.statusCode && err.statusCode >= 500 && err.statusCode < 600) {
throw new external_host_error_1.ExternalHostError(err);
}
}
throw err;
}
}
}
exports.PackagistDatasource = PackagistDatasource;
tslib_1.__decorate([
(0, decorator_1.cache)({
namespace: `datasource-${PackagistDatasource.id}`,
key: (regUrl) => `getRegistryMeta:${regUrl}`,
})
], PackagistDatasource.prototype, "getRegistryMeta", null);
tslib_1.__decorate([
(0, decorator_1.cache)({
namespace: `datasource-${PackagistDatasource.id}`,
key: (regUrl, regFile) => `getPackagistFile:${PackagistDatasource.getPackagistFileUrl(regUrl, regFile)}`,
cacheable: (regUrl) => !PackagistDatasource.isPrivatePackage(regUrl),
ttlMinutes: 1440,
})
], PackagistDatasource.prototype, "getPackagistFile", null);
tslib_1.__decorate([
(0, decorator_1.cache)({
namespace: `datasource-${PackagistDatasource.id}`,
key: (registryUrl, metadataUrl, packageName) => `packagistV2Lookup:${registryUrl}:${metadataUrl}:${packageName}`,
ttlMinutes: 10,
})
], PackagistDatasource.prototype, "packagistV2Lookup", null);
//# sourceMappingURL=index.js.map