mirror of https://github.com/renovatebot/renovate
236 lines
6.9 KiB
TypeScript
236 lines
6.9 KiB
TypeScript
import is from '@sindresorhus/is';
|
|
import { logger } from '../../../../logger';
|
|
import * as p from '../../../../util/promises';
|
|
import { escapeRegExp, regEx } from '../../../../util/regex';
|
|
import type { GetPkgReleasesConfig } from '../../../datasource';
|
|
import { getPkgReleases } from '../../../datasource';
|
|
import { get as getVersioning } from '../../../versioning';
|
|
import type {
|
|
UpdateArtifact,
|
|
UpdateArtifactsResult,
|
|
Upgrade,
|
|
} from '../../types';
|
|
import { massageProviderLookupName } from '../util';
|
|
import { TerraformProviderHash } from './hash';
|
|
import type { ProviderLock, ProviderLockUpdate } from './types';
|
|
import {
|
|
extractLocks,
|
|
findLockFile,
|
|
isPinnedVersion,
|
|
massageNewValue,
|
|
readLockFile,
|
|
writeLockUpdates,
|
|
} from './util';
|
|
|
|
async function updateAllLocks(
|
|
locks: ProviderLock[],
|
|
): Promise<ProviderLockUpdate[]> {
|
|
const updates = await p.map(
|
|
locks,
|
|
async (lock) => {
|
|
const updateConfig: GetPkgReleasesConfig = {
|
|
versioning: 'hashicorp',
|
|
datasource: 'terraform-provider',
|
|
packageName: lock.packageName,
|
|
};
|
|
const { releases } = (await getPkgReleases(updateConfig)) ?? {};
|
|
if (!releases) {
|
|
return null;
|
|
}
|
|
const versioning = getVersioning(updateConfig.versioning);
|
|
const versionsList = releases.map((release) => release.version);
|
|
const newVersion = versioning.getSatisfyingVersion(
|
|
versionsList,
|
|
lock.constraints,
|
|
);
|
|
|
|
// if the new version is the same as the last, signal that no update is needed
|
|
if (!newVersion || newVersion === lock.version) {
|
|
return null;
|
|
}
|
|
const update: ProviderLockUpdate = {
|
|
newVersion,
|
|
newConstraint: lock.constraints,
|
|
newHashes:
|
|
(await TerraformProviderHash.createHashes(
|
|
lock.registryUrl,
|
|
lock.packageName,
|
|
newVersion,
|
|
)) ?? [],
|
|
...lock,
|
|
};
|
|
return update;
|
|
},
|
|
{ concurrency: 4 },
|
|
);
|
|
|
|
return updates.filter(is.truthy);
|
|
}
|
|
|
|
export function getNewConstraint(
|
|
dep: Upgrade<Record<string, unknown>>,
|
|
oldConstraint: string | undefined,
|
|
): string | undefined {
|
|
const {
|
|
currentValue,
|
|
currentVersion,
|
|
newValue: rawNewValue,
|
|
newVersion,
|
|
packageName,
|
|
} = dep;
|
|
|
|
const newValue = massageNewValue(rawNewValue);
|
|
|
|
if (oldConstraint && currentValue && newValue && currentValue === newValue) {
|
|
logger.debug(
|
|
`Leaving constraints "${oldConstraint}" unchanged for "${packageName}" as current and new values are the same`,
|
|
);
|
|
return oldConstraint;
|
|
}
|
|
|
|
if (
|
|
oldConstraint &&
|
|
currentValue &&
|
|
newValue &&
|
|
oldConstraint.includes(currentValue)
|
|
) {
|
|
logger.debug(
|
|
`Updating constraint "${oldConstraint}" to replace "${currentValue}" with "${newValue}" for "${packageName}"`,
|
|
);
|
|
//remove surplus .0 version
|
|
return oldConstraint.replace(
|
|
regEx(`(,\\s|^)${escapeRegExp(currentValue)}(\\.0)*`),
|
|
`$1${newValue}`,
|
|
);
|
|
}
|
|
|
|
if (
|
|
oldConstraint &&
|
|
currentVersion &&
|
|
newVersion &&
|
|
oldConstraint.includes(currentVersion)
|
|
) {
|
|
logger.debug(
|
|
`Updating constraint "${oldConstraint}" to replace "${currentVersion}" with "${newVersion}" for "${packageName}"`,
|
|
);
|
|
return oldConstraint.replace(currentVersion, newVersion);
|
|
}
|
|
|
|
if (isPinnedVersion(newValue)) {
|
|
logger.debug(`Pinning constraint for "${packageName}" to "${newVersion}"`);
|
|
return newVersion;
|
|
}
|
|
|
|
logger.debug(
|
|
`Could not detect constraint to update for "${packageName}" so setting to newValue "${newValue}"`,
|
|
);
|
|
return newValue;
|
|
}
|
|
|
|
export async function updateArtifacts({
|
|
packageFileName,
|
|
updatedDeps,
|
|
config,
|
|
}: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
|
|
logger.debug(`terraform.updateArtifacts(${packageFileName})`);
|
|
|
|
const lockFilePath = await findLockFile(packageFileName);
|
|
|
|
if (!lockFilePath) {
|
|
logger.debug('No .terraform.lock.hcl found');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const lockFileContent = await readLockFile(lockFilePath);
|
|
if (!lockFileContent) {
|
|
logger.debug('No .terraform.lock.hcl found');
|
|
return null;
|
|
}
|
|
const locks = extractLocks(lockFileContent);
|
|
if (!locks) {
|
|
logger.debug('No Locks in .terraform.lock.hcl found');
|
|
return null;
|
|
}
|
|
|
|
const updates: ProviderLockUpdate[] = [];
|
|
if (config.updateType === 'lockFileMaintenance') {
|
|
// update all locks in the file during maintenance --> only update version in constraints
|
|
const maintenanceUpdates = await updateAllLocks(locks);
|
|
updates.push(...maintenanceUpdates);
|
|
} else {
|
|
const providerDeps = updatedDeps.filter((dep) =>
|
|
// TODO #22198
|
|
['provider', 'required_provider'].includes(dep.depType!),
|
|
);
|
|
logger.debug(`Found ${providerDeps.length} provider deps`);
|
|
for (const dep of providerDeps) {
|
|
massageProviderLookupName(dep);
|
|
const { registryUrls, newVersion, packageName } = dep;
|
|
|
|
const updateLock = locks.find(
|
|
(value) => value.packageName === packageName,
|
|
);
|
|
// istanbul ignore if: needs test
|
|
if (!updateLock) {
|
|
logger.debug(`Skipping. No lock found for "${packageName}"`);
|
|
continue;
|
|
}
|
|
if (dep.isLockfileUpdate) {
|
|
const versioning = getVersioning(dep.versioning);
|
|
const satisfyingVersion = versioning.getSatisfyingVersion(
|
|
[dep.newVersion!],
|
|
updateLock.constraints,
|
|
);
|
|
|
|
if (!satisfyingVersion) {
|
|
logger.debug(
|
|
`Skipping. Lockfile update with "${newVersion}" does not statisfy constraints "${updateLock.constraints}" for "${packageName}"`,
|
|
);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// use registryURL defined in the update and fall back to the one defined in the lockfile
|
|
const registryUrl = registryUrls?.[0] ?? updateLock.registryUrl;
|
|
|
|
const newConstraint = getNewConstraint(dep, updateLock.constraints);
|
|
const update: ProviderLockUpdate = {
|
|
// TODO #22198
|
|
newVersion: newVersion!,
|
|
newConstraint: newConstraint!,
|
|
newHashes:
|
|
(await TerraformProviderHash.createHashes(
|
|
registryUrl,
|
|
updateLock.packageName,
|
|
newVersion!,
|
|
)) ?? /* istanbul ignore next: needs test */ [],
|
|
...updateLock,
|
|
};
|
|
updates.push(update);
|
|
}
|
|
}
|
|
// if no updates have been found or there are failed hashes abort
|
|
if (
|
|
updates.length === 0 ||
|
|
updates.some((value) => !value.newHashes?.length)
|
|
) {
|
|
logger.debug('No updates found or hash creation failed');
|
|
return null;
|
|
}
|
|
logger.debug(`Writing updates to ${lockFilePath}`);
|
|
const res = writeLockUpdates(updates, lockFilePath, lockFileContent);
|
|
return [res];
|
|
} catch (err) {
|
|
/* istanbul ignore next */
|
|
return [
|
|
{
|
|
artifactError: {
|
|
lockFile: lockFilePath,
|
|
stderr: err.message,
|
|
},
|
|
},
|
|
];
|
|
}
|
|
}
|