mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 22:46:27 +00:00
fix(auto-replace): use regex replace to avoid infinite loops
This commit is contained in:
parent
435096d97e
commit
6f46153e09
2 changed files with 27 additions and 22 deletions
|
@ -2,6 +2,7 @@ import { logger } from '../../logger';
|
||||||
import { get } from '../../manager';
|
import { get } from '../../manager';
|
||||||
import { WORKER_FILE_UPDATE_FAILED } from '../../constants/error-messages';
|
import { WORKER_FILE_UPDATE_FAILED } from '../../constants/error-messages';
|
||||||
import { matchAt, replaceAt } from '../../util/string';
|
import { matchAt, replaceAt } from '../../util/string';
|
||||||
|
import { regEx } from '../../util/regex';
|
||||||
|
|
||||||
export async function confirmIfDepUpdated(
|
export async function confirmIfDepUpdated(
|
||||||
upgrade,
|
upgrade,
|
||||||
|
@ -59,6 +60,10 @@ export async function checkBranchDepsMatchBaseDeps(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(input: string): string {
|
||||||
|
return input.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||||
|
}
|
||||||
|
|
||||||
export async function doAutoReplace(
|
export async function doAutoReplace(
|
||||||
upgrade,
|
upgrade,
|
||||||
existingContent: string,
|
existingContent: string,
|
||||||
|
@ -77,27 +82,33 @@ export async function doAutoReplace(
|
||||||
return existingContent;
|
return existingContent;
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
|
depName,
|
||||||
currentValue,
|
currentValue,
|
||||||
newValue,
|
newValue,
|
||||||
currentDigest,
|
currentDigest,
|
||||||
newDigest,
|
newDigest,
|
||||||
autoReplaceData,
|
autoReplaceData = {},
|
||||||
} = upgrade;
|
} = upgrade;
|
||||||
const replaceString = autoReplaceData.replaceString || currentValue;
|
const replaceString = autoReplaceData.replaceString || currentValue;
|
||||||
|
logger.trace({ depName, replaceString }, 'autoReplace replaceString');
|
||||||
|
let searchIndex = existingContent.indexOf(replaceString);
|
||||||
|
if (searchIndex === -1) {
|
||||||
|
logger.error(
|
||||||
|
{ depName },
|
||||||
|
'Cannot find replaceString in current file content'
|
||||||
|
);
|
||||||
|
throw new Error(WORKER_FILE_UPDATE_FAILED);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let newString = replaceString;
|
let newString = replaceString.replace(
|
||||||
do {
|
regEx(escapeRegExp(currentValue), 'g'),
|
||||||
newString = newString.replace(currentValue, newValue);
|
newValue
|
||||||
} while (newString.includes(currentValue));
|
);
|
||||||
if (currentDigest) {
|
if (currentDigest && newDigest) {
|
||||||
do {
|
newString = newString.replace(
|
||||||
newString = newString.replace(currentDigest, newDigest);
|
regEx(escapeRegExp(currentDigest), 'g'),
|
||||||
} while (newString.includes(currentDigest));
|
newDigest
|
||||||
}
|
);
|
||||||
let searchIndex = existingContent.indexOf(replaceString);
|
|
||||||
if (searchIndex === -1) {
|
|
||||||
logger.error('Cannot find replaceString in current file content');
|
|
||||||
throw new Error(WORKER_FILE_UPDATE_FAILED);
|
|
||||||
}
|
}
|
||||||
logger.debug(`Starting search at index ${searchIndex}`);
|
logger.debug(`Starting search at index ${searchIndex}`);
|
||||||
// Iterate through the rest of the file
|
// Iterate through the rest of the file
|
||||||
|
@ -117,9 +128,9 @@ export async function doAutoReplace(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) /* istanbul ignore next */ {
|
||||||
logger.debug({ err }, 'doAutoReplace error');
|
logger.debug({ err }, 'doAutoReplace error');
|
||||||
}
|
}
|
||||||
logger.error('Could not autoReplace');
|
// istanbul ignore next
|
||||||
throw new Error(WORKER_FILE_UPDATE_FAILED);
|
throw new Error(WORKER_FILE_UPDATE_FAILED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,6 @@ describe('workers/branch/auto-replace', () => {
|
||||||
};
|
};
|
||||||
parentBranch = undefined;
|
parentBranch = undefined;
|
||||||
});
|
});
|
||||||
it('throws on error', async () => {
|
|
||||||
await expect(
|
|
||||||
doAutoReplace(upgrade, 'existing content', parentBranch)
|
|
||||||
).rejects.toThrow();
|
|
||||||
});
|
|
||||||
it('rebases if the deps list has changed', async () => {
|
it('rebases if the deps list has changed', async () => {
|
||||||
upgrade.baseDeps = extractPackageFile(sampleHtml).deps;
|
upgrade.baseDeps = extractPackageFile(sampleHtml).deps;
|
||||||
parentBranch = 'some existing branch';
|
parentBranch = 'some existing branch';
|
||||||
|
@ -54,7 +49,6 @@ describe('workers/branch/auto-replace', () => {
|
||||||
upgrade.newValue = '7.1.1';
|
upgrade.newValue = '7.1.1';
|
||||||
upgrade.autoReplaceData = {
|
upgrade.autoReplaceData = {
|
||||||
depIndex: 0,
|
depIndex: 0,
|
||||||
replaceString: script,
|
|
||||||
};
|
};
|
||||||
const res = await doAutoReplace(upgrade, src, parentBranch);
|
const res = await doAutoReplace(upgrade, src, parentBranch);
|
||||||
expect(res).toMatchSnapshot();
|
expect(res).toMatchSnapshot();
|
||||||
|
|
Loading…
Reference in a new issue