From f3c0909593977baeb8451c5a4bf21ba85b7365de Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 18 Oct 2024 09:57:07 +0100 Subject: [PATCH 1/5] Fix develop changelog parsing and DRY it Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/dialogs/ChangelogDialog.tsx | 30 ++++++++++++++----- src/toasts/UpdateToast.tsx | 13 ++------ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/components/views/dialogs/ChangelogDialog.tsx b/src/components/views/dialogs/ChangelogDialog.tsx index a33b2413ee7..f155db9444d 100644 --- a/src/components/views/dialogs/ChangelogDialog.tsx +++ b/src/components/views/dialogs/ChangelogDialog.tsx @@ -32,6 +32,22 @@ interface Commit { const REPOS = ["element-hq/element-web", "matrix-org/matrix-js-sdk"] as const; +/* + * Parse a version string is compatible with the Changelog dialog ([element-version]-js-[js-sdk-version]) + */ +export function parseVersion(version: string): Record<(typeof REPOS)[number], string> | null { + const parts = version.split("-"); + if (parts.length === 5 && parts[1] === "js") { + const obj: Record = {}; + for (let i = 0; i < REPOS.length; i++) { + const commit = parts[2 * i]; + obj[REPOS[i]] = commit; + } + return obj; + } + return null; +} + export default class ChangelogDialog extends React.Component { public constructor(props: IProps) { super(props); @@ -58,14 +74,12 @@ export default class ChangelogDialog extends React.Component { } public componentDidMount(): void { - const version = this.props.newVersion.split("-"); - const version2 = this.props.version.split("-"); - if (version == null || version2 == null) return; - // parse versions of form: [vectorversion]-react-[react-sdk-version]-js-[js-sdk-version] - for (let i = 0; i < REPOS.length; i++) { - const oldVersion = version2[2 * i]; - const newVersion = version[2 * i]; - this.fetchChanges(REPOS[i], oldVersion, newVersion); + const commits = parseVersion(this.props.version); + const newCommits = parseVersion(this.props.newVersion); + if (commits == null || newCommits == null) return; + + for (const repo of REPOS) { + this.fetchChanges(repo, commits[repo], newCommits[repo]); } } diff --git a/src/toasts/UpdateToast.tsx b/src/toasts/UpdateToast.tsx index a0ee6b80892..676dbf63e4a 100644 --- a/src/toasts/UpdateToast.tsx +++ b/src/toasts/UpdateToast.tsx @@ -13,21 +13,12 @@ import SdkConfig from "../SdkConfig"; import GenericToast from "../components/views/toasts/GenericToast"; import ToastStore from "../stores/ToastStore"; import QuestionDialog from "../components/views/dialogs/QuestionDialog"; -import ChangelogDialog from "../components/views/dialogs/ChangelogDialog"; +import ChangelogDialog, { parseVersion } from "../components/views/dialogs/ChangelogDialog"; import PlatformPeg from "../PlatformPeg"; import Modal from "../Modal"; const TOAST_KEY = "update"; -/* - * Check a version string is compatible with the Changelog - * dialog ([element-version]-react-[react-sdk-version]-js-[js-sdk-version]) - */ -function checkVersion(ver: string): boolean { - const parts = ver.split("-"); - return parts.length === 5 && parts[1] === "react" && parts[3] === "js"; -} - function installUpdate(): void { PlatformPeg.get()?.installUpdate(); } @@ -52,7 +43,7 @@ export const showToast = (version: string, newVersion: string, releaseNotes?: st }, }); }; - } else if (checkVersion(version) && checkVersion(newVersion)) { + } else if (parseVersion(version) && parseVersion(newVersion)) { onAccept = () => { Modal.createDialog(ChangelogDialog, { version, From fd1793716ebf7d31fbe156e894c6ec4daf05009a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 18 Oct 2024 09:59:07 +0100 Subject: [PATCH 2/5] duh Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/dialogs/ChangelogDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/ChangelogDialog.tsx b/src/components/views/dialogs/ChangelogDialog.tsx index f155db9444d..3ac8ae8b052 100644 --- a/src/components/views/dialogs/ChangelogDialog.tsx +++ b/src/components/views/dialogs/ChangelogDialog.tsx @@ -37,7 +37,7 @@ const REPOS = ["element-hq/element-web", "matrix-org/matrix-js-sdk"] as const; */ export function parseVersion(version: string): Record<(typeof REPOS)[number], string> | null { const parts = version.split("-"); - if (parts.length === 5 && parts[1] === "js") { + if (parts.length === 3 && parts[1] === "js") { const obj: Record = {}; for (let i = 0; i < REPOS.length; i++) { const commit = parts[2 * i]; From 1fc425a0e7b5df476caed48ea83904544caf4a8f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 18 Oct 2024 11:51:49 +0100 Subject: [PATCH 3/5] Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/dialogs/ChangelogDialog-test.tsx | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx b/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx index e16abb0e83e..ccc4c574f03 100644 --- a/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx @@ -10,7 +10,7 @@ import React from "react"; import fetchMock from "fetch-mock-jest"; import { render, screen, waitForElementToBeRemoved } from "jest-matrix-react"; -import ChangelogDialog from "../../../../../src/components/views/dialogs/ChangelogDialog"; +import ChangelogDialog, { parseVersion } from "../../../../../src/components/views/dialogs/ChangelogDialog"; describe("", () => { it("should fetch github proxy url for each repo with old and new version strings", async () => { @@ -78,3 +78,24 @@ describe("", () => { expect(asFragment()).toMatchSnapshot(); }); }); + +describe("parseVersion", () => { + it("should return null for old-style version strings", () => { + expect(parseVersion("aaaabbbb-react-ccccdddd-js-eeeeffff")).toBeNull(); + }); + + it("should return null for invalid version strings", () => { + expect(parseVersion("aaaabbbb-react-ccccdddd")).toBeNull(); + }); + + it("should return null for release version strings", () => { + expect(parseVersion("v1.22.33")).toBeNull(); + }); + + it("should return mapping for develop version string", () => { + expect(parseVersion("aaaabbbb-js-eeeeffff")).toEqual({ + "element-hq/element-web": "aaaabbbb", + "matrix-org/matrix-js-sdk": "eeeeffff", + }); + }); +}); From e7fefc97ec97c697edc75d4d63d517e174328307 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 18 Oct 2024 11:57:37 +0100 Subject: [PATCH 4/5] Typeguards! Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/dialogs/ChangelogDialog.tsx | 15 ++- src/toasts/UpdateToast.tsx | 4 +- .../views/dialogs/ChangelogDialog-test.tsx | 9 +- .../ChangelogDialog-test.tsx.snap | 109 ++++++++++++++++++ 4 files changed, 127 insertions(+), 10 deletions(-) diff --git a/src/components/views/dialogs/ChangelogDialog.tsx b/src/components/views/dialogs/ChangelogDialog.tsx index 3ac8ae8b052..ae3c157c788 100644 --- a/src/components/views/dialogs/ChangelogDialog.tsx +++ b/src/components/views/dialogs/ChangelogDialog.tsx @@ -15,8 +15,8 @@ import Spinner from "../elements/Spinner"; import Heading from "../typography/Heading"; interface IProps { - newVersion: string; - version: string; + newVersion: DevelopVersionString; + version: DevelopVersionString; onFinished: (success: boolean) => void; } @@ -32,6 +32,8 @@ interface Commit { const REPOS = ["element-hq/element-web", "matrix-org/matrix-js-sdk"] as const; +export type DevelopVersionString = string & { _developVersionString: never }; + /* * Parse a version string is compatible with the Changelog dialog ([element-version]-js-[js-sdk-version]) */ @@ -48,6 +50,10 @@ export function parseVersion(version: string): Record<(typeof REPOS)[number], st return null; } +export function checkVersion(version: string): version is DevelopVersionString { + return parseVersion(version) !== null; +} + export default class ChangelogDialog extends React.Component { public constructor(props: IProps) { super(props); @@ -74,9 +80,8 @@ export default class ChangelogDialog extends React.Component { } public componentDidMount(): void { - const commits = parseVersion(this.props.version); - const newCommits = parseVersion(this.props.newVersion); - if (commits == null || newCommits == null) return; + const commits = parseVersion(this.props.version)!; + const newCommits = parseVersion(this.props.newVersion)!; for (const repo of REPOS) { this.fetchChanges(repo, commits[repo], newCommits[repo]); diff --git a/src/toasts/UpdateToast.tsx b/src/toasts/UpdateToast.tsx index 676dbf63e4a..786b6263174 100644 --- a/src/toasts/UpdateToast.tsx +++ b/src/toasts/UpdateToast.tsx @@ -13,7 +13,7 @@ import SdkConfig from "../SdkConfig"; import GenericToast from "../components/views/toasts/GenericToast"; import ToastStore from "../stores/ToastStore"; import QuestionDialog from "../components/views/dialogs/QuestionDialog"; -import ChangelogDialog, { parseVersion } from "../components/views/dialogs/ChangelogDialog"; +import ChangelogDialog, { checkVersion } from "../components/views/dialogs/ChangelogDialog"; import PlatformPeg from "../PlatformPeg"; import Modal from "../Modal"; @@ -43,7 +43,7 @@ export const showToast = (version: string, newVersion: string, releaseNotes?: st }, }); }; - } else if (parseVersion(version) && parseVersion(newVersion)) { + } else if (checkVersion(version) && checkVersion(newVersion)) { onAccept = () => { Modal.createDialog(ChangelogDialog, { version, diff --git a/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx b/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx index ccc4c574f03..547534d207b 100644 --- a/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/ChangelogDialog-test.tsx @@ -10,7 +10,10 @@ import React from "react"; import fetchMock from "fetch-mock-jest"; import { render, screen, waitForElementToBeRemoved } from "jest-matrix-react"; -import ChangelogDialog, { parseVersion } from "../../../../../src/components/views/dialogs/ChangelogDialog"; +import ChangelogDialog, { + DevelopVersionString, + parseVersion, +} from "../../../../../src/components/views/dialogs/ChangelogDialog"; describe("", () => { it("should fetch github proxy url for each repo with old and new version strings", async () => { @@ -64,8 +67,8 @@ describe("", () => { files: [], }); - const newVersion = "newsha1-js-newsha3"; - const oldVersion = "oldsha1-js-oldsha3"; + const newVersion = "newsha1-js-newsha3" as DevelopVersionString; + const oldVersion = "oldsha1-js-oldsha3" as DevelopVersionString; const { asFragment } = render( , ); diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/ChangelogDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/ChangelogDialog-test.tsx.snap index b38ccbc8047..d0c68b3d670 100644 --- a/test/unit-tests/components/views/dialogs/__snapshots__/ChangelogDialog-test.tsx.snap +++ b/test/unit-tests/components/views/dialogs/__snapshots__/ChangelogDialog-test.tsx.snap @@ -1,5 +1,114 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[` should fail gracefully with invalid version strings 1`] = ` + +
+