renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
136 lines (135 loc) • 5.01 kB
JavaScript
import "../../../constants/error-messages.js";
import { regEx } from "../../../util/regex.js";
import { logger } from "../../../logger/index.js";
import { find, getAll } from "../../../util/host-rules.js";
import { deleteLocalFile, ensureCacheDir, findLocalSiblingOrParent, getSiblingFileName, localPathExists, readLocalFile, writeLocalFile } from "../../../util/fs/index.js";
import { exec } from "../../../util/exec/index.js";
import { isEmptyArray, isString } from "@sindresorhus/is";
import { quote } from "shlex";
//#region lib/modules/manager/mix/artifacts.ts
const hexRepoUrl = "https://hex.pm/";
const hexRepoOrgUrlRegex = regEx(`^https://hex\\.pm/api/repos/(?<organization>[a-z0-9_]+)/$`);
async function updateArtifacts({ packageFileName, updatedDeps, newPackageFileContent, config }) {
logger.debug(`mix.getArtifacts(${packageFileName})`);
const { isLockFileMaintenance } = config;
if (isEmptyArray(updatedDeps) && !isLockFileMaintenance) {
logger.debug("No updated mix deps");
return null;
}
let lockFileName = getSiblingFileName(packageFileName, "mix.lock");
let isUmbrella = false;
let existingLockFileContent = await readLocalFile(lockFileName, "utf8");
if (!existingLockFileContent) {
const lockFileError = await checkLockFileReadError(lockFileName);
if (lockFileError) return lockFileError;
const parentLockFileName = await findLocalSiblingOrParent(packageFileName, "mix.lock");
existingLockFileContent = parentLockFileName && await readLocalFile(parentLockFileName, "utf8");
if (parentLockFileName && existingLockFileContent) {
lockFileName = parentLockFileName;
isUmbrella = true;
} else if (parentLockFileName) {
const lockFileError = await checkLockFileReadError(parentLockFileName);
if (lockFileError) return lockFileError;
}
}
if (isLockFileMaintenance && isUmbrella) {
logger.debug("Cannot use lockFileMaintenance in an umbrella project, see https://docs.renovatebot.com/modules/manager/mix/#lockFileMaintenance");
return null;
}
if (isLockFileMaintenance && !existingLockFileContent) {
logger.debug("Cannot use lockFileMaintenance when no mix.lock file is present");
return null;
}
try {
await writeLocalFile(packageFileName, newPackageFileContent);
if (isLockFileMaintenance) await deleteLocalFile(lockFileName);
} catch (err) {
logger.warn({ err }, "mix.exs could not be written");
return [{ artifactError: {
fileName: lockFileName,
stderr: err.message
} }];
}
if (!existingLockFileContent) {
logger.debug("No mix.lock found");
return null;
}
const organizations = /* @__PURE__ */ new Set();
const hexHostRulesWithMatchHost = getAll().filter((hostRule) => !!hostRule.matchHost && hexRepoOrgUrlRegex.test(hostRule.matchHost));
for (const { matchHost } of hexHostRulesWithMatchHost) if (matchHost) {
const result = hexRepoOrgUrlRegex.exec(matchHost);
if (result?.groups) {
const { organization } = result.groups;
organizations.add(organization);
}
}
for (const { packageName } of updatedDeps) if (packageName) {
const [, organization] = packageName.split(":");
if (organization) organizations.add(organization);
}
const preCommands = Array.from(organizations).reduce((acc, organization) => {
const { token } = find({ url: `${hexRepoUrl}api/repos/${organization}/` });
if (token) {
logger.debug(`Authenticating to hex organization ${organization}`);
const authCommand = `mix hex.organization auth ${organization} --key ${token}`;
return [...acc, authCommand];
}
return acc;
}, []);
const execOptions = {
extraEnv: { MIX_ARCHIVES: await ensureCacheDir("mix_archives") },
cwdFile: packageFileName,
docker: {},
toolConstraints: [{
toolName: "erlang",
constraint: config.constraints?.erlang ?? "^26"
}, {
toolName: "elixir",
constraint: config.constraints?.elixir
}],
preCommands
};
let command;
if (isLockFileMaintenance) command = "mix deps.get";
else command = [
"mix",
"deps.update",
...updatedDeps.map((dep) => dep.depName).filter(isString).map((dep) => quote(dep))
].join(" ");
try {
await exec(command, execOptions);
} catch (err) {
/* v8 ignore next 3 */
if (err.message === "temporary-error") throw err;
logger.debug({
err,
message: err.message,
command
}, "Failed to update Mix lock file");
return [{ artifactError: {
fileName: lockFileName,
stderr: err.message
} }];
}
const newMixLockContent = await readLocalFile(lockFileName, "utf8");
if (existingLockFileContent === newMixLockContent) {
logger.debug("mix.lock is unchanged");
return null;
}
logger.debug("Returning updated mix.lock");
return [{ file: {
type: "addition",
path: lockFileName,
contents: newMixLockContent
} }];
}
async function checkLockFileReadError(lockFileName) {
if (await localPathExists(lockFileName)) return [{ artifactError: {
fileName: lockFileName,
stderr: `Error reading ${lockFileName}`
} }];
return null;
}
//#endregion
export { updateArtifacts };
//# sourceMappingURL=artifacts.js.map