diff --git a/.eslintignore b/.eslintignore index 9b59cd01a..59bf495f4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1537,6 +1537,7 @@ packages/tools/update-readme-download.test.js packages/tools/update-readme-download.js packages/tools/update-readme-sponsors.js packages/tools/updateMarkdownDoc.js +packages/tools/utils/discourse.test.js packages/tools/utils/discourse.js packages/tools/utils/loadSponsors.js packages/tools/utils/translation.js diff --git a/.gitignore b/.gitignore index a6bc8fa78..6b4607e10 100644 --- a/.gitignore +++ b/.gitignore @@ -1514,6 +1514,7 @@ packages/tools/update-readme-download.test.js packages/tools/update-readme-download.js packages/tools/update-readme-sponsors.js packages/tools/updateMarkdownDoc.js +packages/tools/utils/discourse.test.js packages/tools/utils/discourse.js packages/tools/utils/loadSponsors.js packages/tools/utils/translation.js diff --git a/packages/tools/postPreReleasesToForum.ts b/packages/tools/postPreReleasesToForum.ts index 428b69783..d6f070bd9 100644 --- a/packages/tools/postPreReleasesToForum.ts +++ b/packages/tools/postPreReleasesToForum.ts @@ -1,7 +1,7 @@ import { pathExists } from 'fs-extra'; import { readFile, writeFile } from 'fs/promises'; import { GitHubRelease, gitHubLatestReleases, gitHubLinkify } from './tool-utils'; -import { config, createPost, createTopic, getForumTopPostByExternalId, getTopicByExternalId, updatePost } from './utils/discourse'; +import { config, createPost, createTopic, getForumTopPostByExternalId, getTopicByExternalId, trimPostToMaximumLength, updatePost } from './utils/discourse'; import { compareVersions } from 'compare-versions'; import dayjs = require('dayjs'); import { getRootDir } from '@joplin/utils'; @@ -135,7 +135,11 @@ const processReleases = async (releases: GitHubRelease[], platform: Platform, st await updatePost(topPost.id, { title: topicTitle, - raw: `${topPost.raw}\n\n${postBody}`, + // With a large number of pre-releases, the top post can get very long + // and needs to be trimmed. + raw: trimPostToMaximumLength( + `${topPost.raw}\n\n${postBody}`, + ), edit_reason: 'Auto-updated by script', }); diff --git a/packages/tools/utils/discourse.test.ts b/packages/tools/utils/discourse.test.ts new file mode 100644 index 000000000..af53ed7d3 --- /dev/null +++ b/packages/tools/utils/discourse.test.ts @@ -0,0 +1,18 @@ +import { trimPostToMaximumLength } from './discourse'; + +describe('utils/discourse', () => { + it('trimPostToMaximumLength should allow trimming posts to a maximum length', () => { + const makeLongString = (length: number) => { + const resultParts = []; + while (resultParts.length < length) { + resultParts.push('1'); + } + return resultParts.join(''); + }; + + const longContent = makeLongString(70_000); + const trimmed = trimPostToMaximumLength(longContent); + expect(trimmed.length).toBeLessThan(65_000); + expect(trimmed).toContain(`${longContent.substring(0, 65_000 - 153)}...\n\n**Note**:`); + }); +}); diff --git a/packages/tools/utils/discourse.ts b/packages/tools/utils/discourse.ts index dbc88e0e8..730b00b76 100644 --- a/packages/tools/utils/discourse.ts +++ b/packages/tools/utils/discourse.ts @@ -1,3 +1,4 @@ +import { substrWithEllipsis } from '@joplin/lib/string-utils'; import { msleep } from '@joplin/utils/time'; import fetch from 'node-fetch'; @@ -141,3 +142,16 @@ export const createPost = async (topicId: number, post: any): Promise => { await execApi(HttpMethod.PUT, `posts/${postId}.json`, content); }; + +export const trimPostToMaximumLength = (postBody: string) => { + // Discourse has a maximum post length of 65_000: + const maximumLength = 65_000; + if (postBody.length > maximumLength) { + return [ + substrWithEllipsis(postBody, 0, maximumLength - 150), + '**Note**: The full content of this post is longer than permitted by Discourse.', + ].join('\n\n'); + } + + return postBody; +};