From efa01e62827cb17f026116cd4ed015e90747cb2a Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Tue, 17 Mar 2026 12:45:50 +0100 Subject: [PATCH] [web] fix incremental compile from history for old history ids (#32222) * [saas-e2e] port history tests to old history * [web] fix incremental compile from history for old history ids * [saas-e2e] tweak return type GitOrigin-RevId: 2c89b570647c292c720cd0d02b6188f66e3e3a69 --- .../app/src/Features/Compile/ClsiManager.mjs | 8 +++---- .../src/Features/History/HistoryManager.mjs | 13 +++++++++- .../Project/ProjectCreationHandler.mjs | 4 ++-- services/web/scripts/e2e_test_setup.mjs | 24 +++++++++++++++++-- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/services/web/app/src/Features/Compile/ClsiManager.mjs b/services/web/app/src/Features/Compile/ClsiManager.mjs index 85b377fa03..b514529c8c 100644 --- a/services/web/app/src/Features/Compile/ClsiManager.mjs +++ b/services/web/app/src/Features/Compile/ClsiManager.mjs @@ -931,10 +931,10 @@ async function _buildRequestFromHistoryIncremental( let size = 0 while (hasMore) { let changes - ;({ changes, hasMore } = await HistoryManager.promises.getChanges( - historyId, - { since } - )) + ;({ changes, hasMore } = + await HistoryManager.promises.getChangesWithHistoryId(historyId, { + since, + })) since += changes.length const newRawChangeOperations = _rawChangeOperationsFromChanges(changes) size += Buffer.from(JSON.stringify(newRawChangeOperations)).byteLength diff --git a/services/web/app/src/Features/History/HistoryManager.mjs b/services/web/app/src/Features/History/HistoryManager.mjs index 8874a5a5c2..7aa08ab346 100644 --- a/services/web/app/src/Features/History/HistoryManager.mjs +++ b/services/web/app/src/Features/History/HistoryManager.mjs @@ -50,7 +50,7 @@ function getFilestoreBlobURL(historyId, hash) { async function initializeProject(projectId) { const body = await fetchJson(`${settings.apis.project_history.url}/project`, { method: 'POST', - json: { historyId: projectId.toString() }, + json: { historyId: projectId }, }) const historyId = body && body.project && body.project.id if (!historyId) { @@ -299,7 +299,17 @@ async function getLatestHistoryWithHistoryId(historyId) { */ async function getChanges(projectId, opts = {}) { const historyId = await getHistoryId(projectId) + return await getChangesWithHistoryId(historyId, opts) +} +/** + * Get history changes since a given version and historyId + * + * @param {string} historyId + * @param {object} [opts] + * @param {number} [opts.since] - The start version of changes to get + */ +async function getChangesWithHistoryId(historyId, opts = {}) { const url = new URL(`${HISTORY_V1_URL}/projects/${historyId}/changes`) if (opts.since) { url.searchParams.set('since', opts.since) @@ -449,6 +459,7 @@ export default { requestBlobWithProjectId, getLatestHistory, getChanges, + getChangesWithHistoryId, getProjectBlobStats, getBlobStats, getLatestHistoryWithHistoryId, diff --git a/services/web/app/src/Features/Project/ProjectCreationHandler.mjs b/services/web/app/src/Features/Project/ProjectCreationHandler.mjs index dc30e23886..718b646f9f 100644 --- a/services/web/app/src/Features/Project/ProjectCreationHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectCreationHandler.mjs @@ -163,8 +163,8 @@ async function populateClsiCacheForExampleProject( return projectId } -async function createExampleProject(ownerId, projectName) { - const project = await _createBlankProject(ownerId, projectName) +async function createExampleProject(ownerId, projectName, attributes = {}) { + const project = await _createBlankProject(ownerId, projectName, attributes) const { fileEntries, docEntries } = await _addExampleProjectFiles( ownerId, diff --git a/services/web/scripts/e2e_test_setup.mjs b/services/web/scripts/e2e_test_setup.mjs index 685fa732ec..603b78acb1 100644 --- a/services/web/scripts/e2e_test_setup.mjs +++ b/services/web/scripts/e2e_test_setup.mjs @@ -9,6 +9,8 @@ import ProjectDeleter from '../app/src/Features/Project/ProjectDeleter.mjs' import SplitTestManager from '../app/src/Features/SplitTests/SplitTestManager.mjs' import UserDeleter from '../app/src/Features/User/UserDeleter.mjs' import UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.mjs' +import HistoryManager from '../app/src/Features/History/HistoryManager.mjs' +import ProjectCreationHandler from '../app/src/Features/Project/ProjectCreationHandler.mjs' const MONOREPO = Path.dirname( Path.dirname(Path.dirname(Path.dirname(fileURLToPath(import.meta.url)))) @@ -16,7 +18,7 @@ const MONOREPO = Path.dirname( /** * @param {string} email - * @return {Promise} + * @return {Promise} */ async function createUser(email) { const user = await UserRegistrationHandler.promises.registerNewUser({ @@ -43,6 +45,7 @@ async function createUser(email) { }, } ) + return user._id.toString() } /** @@ -75,6 +78,19 @@ async function deleteUser(email) { await UserDeleter.promises.expireDeletedUser(user._id) } +async function createProjectWithOldHistoryId(userId) { + const projectName = 'old history id' + const historyId = parseInt( + await HistoryManager.promises.initializeProject(), + 10 + ) + await ProjectCreationHandler.promises.createExampleProject( + userId, + projectName, + { overleaf: { history: { id: historyId } } } + ) +} + /** * @param {string} email * @return {Promise} @@ -86,7 +102,11 @@ async function provisionUser(email) { ) } await deleteUser(email) - await createUser(email) + const userId = await createUser(email) + + if (email === 'user+old-history-id@example.com') { + await createProjectWithOldHistoryId(userId) + } } async function provisionUsers() {