renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
186 lines • 6.87 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateArtifacts = updateArtifacts;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const shlex_1 = require("shlex");
const error_messages_1 = require("../../../constants/error-messages");
const logger_1 = require("../../../logger");
const exec_1 = require("../../../util/exec");
const fs_1 = require("../../../util/fs");
const hostRules = tslib_1.__importStar(require("../../../util/host-rules"));
const regex_1 = require("../../../util/regex");
const hexRepoUrl = 'https://hex.pm/';
const hexRepoOrgUrlRegex = (0, regex_1.regEx)(`^https://hex\\.pm/api/repos/(?<organization>[a-z0-9_]+)/$`);
async function updateArtifacts({ packageFileName, updatedDeps, newPackageFileContent, config, }) {
logger_1.logger.debug(`mix.getArtifacts(${packageFileName})`);
const { isLockFileMaintenance } = config;
if (is_1.default.emptyArray(updatedDeps) && !isLockFileMaintenance) {
logger_1.logger.debug('No updated mix deps');
return null;
}
let lockFileName = (0, fs_1.getSiblingFileName)(packageFileName, 'mix.lock');
let isUmbrella = false;
let existingLockFileContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
if (!existingLockFileContent) {
const lockFileError = await checkLockFileReadError(lockFileName);
if (lockFileError) {
return lockFileError;
}
const parentLockFileName = await (0, fs_1.findLocalSiblingOrParent)(packageFileName, 'mix.lock');
existingLockFileContent =
parentLockFileName && (await (0, fs_1.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_1.logger.debug('Cannot use lockFileMaintenance in an umbrella project, see https://docs.renovatebot.com/modules/manager/mix/#lockFileMaintenance');
return null;
}
if (isLockFileMaintenance && !existingLockFileContent) {
logger_1.logger.debug('Cannot use lockFileMaintenance when no mix.lock file is present');
return null;
}
try {
await (0, fs_1.writeLocalFile)(packageFileName, newPackageFileContent);
if (isLockFileMaintenance) {
await (0, fs_1.deleteLocalFile)(lockFileName);
}
}
catch (err) {
logger_1.logger.warn({ err }, 'mix.exs could not be written');
return [
{
artifactError: {
lockFile: lockFileName,
stderr: err.message,
},
},
];
}
if (!existingLockFileContent) {
logger_1.logger.debug('No mix.lock found');
return null;
}
const organizations = new Set();
const hexHostRulesWithMatchHost = hostRules
.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 url = `${hexRepoUrl}api/repos/${organization}/`;
const { token } = hostRules.find({ url });
if (token) {
logger_1.logger.debug(`Authenticating to hex organization ${organization}`);
const authCommand = `mix hex.organization auth ${organization} --key ${token}`;
return [...acc, authCommand];
}
return acc;
}, []);
const execOptions = {
extraEnv: {
// https://hexdocs.pm/mix/1.15.0/Mix.Tasks.Archive.html
// TODO: should include a version constraint
MIX_ARCHIVES: await (0, fs_1.ensureCacheDir)('mix_archives'),
},
cwdFile: packageFileName,
docker: {},
toolConstraints: [
{
toolName: 'erlang',
// https://hexdocs.pm/elixir/1.14.5/compatibility-and-deprecations.html#compatibility-between-elixir-and-erlang-otp
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(is_1.default.string)
.map((dep) => (0, shlex_1.quote)(dep)),
].join(' ');
}
try {
await (0, exec_1.exec)(command, execOptions);
}
catch (err) {
/* v8 ignore next 3 */
if (err.message === error_messages_1.TEMPORARY_ERROR) {
throw err;
}
logger_1.logger.debug({ err, message: err.message, command }, 'Failed to update Mix lock file');
return [
{
artifactError: {
lockFile: lockFileName,
stderr: err.message,
},
},
];
}
const newMixLockContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
if (existingLockFileContent === newMixLockContent) {
logger_1.logger.debug('mix.lock is unchanged');
return null;
}
logger_1.logger.debug('Returning updated mix.lock');
return [
{
file: {
type: 'addition',
path: lockFileName,
contents: newMixLockContent,
},
},
];
}
async function checkLockFileReadError(lockFileName) {
if (await (0, fs_1.localPathExists)(lockFileName)) {
return [
{
artifactError: {
lockFile: lockFileName,
stderr: `Error reading ${lockFileName}`,
},
},
];
}
return null;
}
//# sourceMappingURL=artifacts.js.map