From d0aff85157be0d898082b2350c7333837adf742a Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Sun, 30 Jun 2024 16:34:31 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Add=20migration=20mechani?= =?UTF-8?q?sm=20for=20plugin=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __mocks__/obsidian.ts | 2 ++ __mocks__/obsidian/Notice.ts | 13 +++++++++++ src/plugin.spec.ts | 4 +++- src/plugin.ts | 45 ++++++++++++++---------------------- src/settings/settings-tab.ts | 3 ++- src/settings/types.ts | 3 +++ 6 files changed, 40 insertions(+), 30 deletions(-) create mode 100644 __mocks__/obsidian/Notice.ts diff --git a/__mocks__/obsidian.ts b/__mocks__/obsidian.ts index d3b833c..5a64ed2 100644 --- a/__mocks__/obsidian.ts +++ b/__mocks__/obsidian.ts @@ -2,10 +2,12 @@ import { AppMock } from "./obsidian/App"; import { PluginMock } from "./obsidian/Plugin"; import { ModalMock } from "./obsidian/Modal"; import { PluginSettingTabMock } from "./obsidian/PluginSettingTab"; +import { NoticeMock } from "./obsidian/Notice"; module.exports = { App: AppMock, Plugin: PluginMock, Modal: ModalMock, PluginSettingTab: PluginSettingTabMock, + Notice: NoticeMock, }; diff --git a/__mocks__/obsidian/Notice.ts b/__mocks__/obsidian/Notice.ts new file mode 100644 index 0000000..66ff1a9 --- /dev/null +++ b/__mocks__/obsidian/Notice.ts @@ -0,0 +1,13 @@ +/* eslint-disable unused-imports/no-unused-vars */ +import type { Notice } from "obsidian"; + +export class NoticeMock implements Notice { + constructor(message: string | DocumentFragment, duration?: number | undefined) {} + noticeEl!: HTMLElement; + setMessage(message: string | DocumentFragment): this { + throw new Error("Method not implemented."); + } + hide(): void { + throw new Error("Method not implemented."); + } +} diff --git a/src/plugin.spec.ts b/src/plugin.spec.ts index f645500..a734ac4 100644 --- a/src/plugin.spec.ts +++ b/src/plugin.spec.ts @@ -8,6 +8,7 @@ import type { GithubLinkPluginSettings } from "./settings"; import { DEFAULT_SETTINGS } from "./settings"; import { CacheEntry, RequestCache } from "./github/cache"; import { LogLevel } from "./logger"; +import { DATA_VERSION } from "./settings/types"; jest.mock("./settings/settings-tab"); @@ -51,6 +52,7 @@ describe("GithubLinkPlugin", () => { expect(PluginData).toBeDefined(); expect(PluginData.cache).toEqual(null); expect(PluginData.settings).toEqual(DEFAULT_SETTINGS); + expect(PluginData.dataVersion).toEqual(DATA_VERSION); }); test("should load stored cache", async () => { @@ -62,7 +64,7 @@ describe("GithubLinkPlugin", () => { null, ); plugin = new GithubLinkPlugin(app, manifest); - mockedPlugin(plugin).data = { cache: [cacheEntry.toJSON()] }; + mockedPlugin(plugin).data = { cache: [cacheEntry.toJSON()], dataVersion: DATA_VERSION }; await plugin.onload(); expect(PluginData.cache).toEqual([cacheEntry.toJSON()]); expect(getCache().get(cacheEntry.request)).toEqual(cacheEntry); diff --git a/src/plugin.ts b/src/plugin.ts index 6787514..b40966c 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { Plugin } from "obsidian"; +import { Notice, Plugin } from "obsidian"; import { DEFAULT_SETTINGS, GithubLinkPluginSettingsTab } from "./settings"; import { Logger } from "./logger"; @@ -9,9 +9,10 @@ import { InlineRenderer } from "./inline/inline"; import { createInlineViewPlugin } from "./inline/view-plugin"; import { RequestCache } from "./github/cache"; import { QueryProcessor } from "./query/processor"; +import { DATA_VERSION } from "./settings/types"; export const PluginSettings: GithubLinkPluginSettings = { ...DEFAULT_SETTINGS }; -export const PluginData: GithubLinkPluginData = { cache: null, settings: PluginSettings }; +export const PluginData: GithubLinkPluginData = { cache: null, settings: PluginSettings, dataVersion: DATA_VERSION }; export const logger = new Logger(); let cache: RequestCache; export function getCache(): RequestCache { @@ -21,31 +22,7 @@ export function getCache(): RequestCache { export class GithubLinkPlugin extends Plugin { public cacheInterval: number | undefined; async onload() { - let data = (await this.loadData()) || {}; - - // Migrate settings from data root to settings -- remove in v1.0.0 - if (data.accounts) { - const newSettings: GithubLinkPluginSettings = { - accounts: data.accounts ?? PluginSettings.accounts, - cacheIntervalSeconds: data.cacheIntervalSeconds ?? PluginSettings.cacheIntervalSeconds, - defaultPageSize: data.defaultPageSize ?? PluginSettings.defaultPageSize, - logLevel: data.logLevel ?? PluginSettings.logLevel, - maxCacheAgeHours: data.maxCacheAgeHours ?? PluginSettings.maxCacheAgeHours, - minRequestSeconds: data.minRequestSeconds ?? PluginSettings.minRequestSeconds, - tagShowPRMergeable: data.tagShowPRMergeable ?? PluginSettings.tagShowPRMergeable, - tagTooltips: data.tagTooltips ?? PluginSettings.tagTooltips, - defaultAccount: data.defaultAccount ?? PluginSettings.defaultAccount, - showPagination: data.showPagination ?? PluginSettings.showPagination, - showRefresh: data.showRefresh ?? PluginSettings.showRefresh, - showExternalLink: data.showExternalLink ?? PluginSettings.showExternalLink, - }; - const newData: GithubLinkPluginData = { - cache: data.cache ?? PluginData.cache, - settings: newSettings, - }; - await this.saveData(newData); - data = newData; - } + const data = (await this.loadData()) || {}; Object.assign(PluginSettings, data.settings); Object.assign(PluginData, data); @@ -53,12 +30,24 @@ export class GithubLinkPlugin extends Plugin { cache = new RequestCache(PluginData.cache); + if (data.dataVersion === undefined || PluginData.dataVersion < DATA_VERSION) { + // Always clear cache when data version changes + const entriesDeleted = cache.clean(new Date()); + PluginData.cache = null; + PluginData.dataVersion = DATA_VERSION; + await this.saveData(PluginData); + new Notice( + `GitHub link data schema migrated to version ${DATA_VERSION}. Removed ${entriesDeleted} stored items from GitHub Link cache.`, + 3000, + ); + } + // Clean cache const maxAge = new Date(new Date().getTime() - PluginSettings.maxCacheAgeHours * 60 * 60 * 1000); const entriesDeleted = cache.clean(maxAge); if (entriesDeleted > 0) { PluginData.cache = cache.toJSON(); - await this.saveData(PluginSettings); + await this.saveData(PluginData); logger.info(`Cleaned ${entriesDeleted} entries from request cache.`); } diff --git a/src/settings/settings-tab.ts b/src/settings/settings-tab.ts index ceef15b..93d53a3 100644 --- a/src/settings/settings-tab.ts +++ b/src/settings/settings-tab.ts @@ -6,7 +6,7 @@ import type { GithubLinkPlugin } from "../plugin"; import { LogLevel } from "../logger"; import { PluginData, PluginSettings, getCache } from "../plugin"; import type { GithubAccount, GithubLinkPluginData } from "./types"; -import { DEFAULT_SETTINGS } from "./types"; +import { DATA_VERSION, DEFAULT_SETTINGS } from "./types"; import { AccountSettings } from "./account"; export class GithubLinkPluginSettingsTab extends PluginSettingTab { @@ -283,6 +283,7 @@ export class GithubLinkPluginSettingsTab extends PluginSettingTab { const newData: GithubLinkPluginData = { cache: PluginData.cache, settings: PluginSettings, + dataVersion: DATA_VERSION, }; return this.plugin.saveData(newData); } diff --git a/src/settings/types.ts b/src/settings/types.ts index 78caa90..c1f5f80 100644 --- a/src/settings/types.ts +++ b/src/settings/types.ts @@ -1,5 +1,7 @@ import { LogLevel } from "../logger"; +export const DATA_VERSION = 1; + export interface GithubAccount { id: string; name: string; @@ -12,6 +14,7 @@ export interface GithubAccount { export interface GithubLinkPluginData { settings: GithubLinkPluginSettings; cache: string[] | null; + dataVersion: number; } export interface GithubLinkPluginSettings {