🐛 fix: Add migration mechanism for plugin data

This commit is contained in:
Nathan Smith 2024-06-30 16:34:31 -04:00
parent 50f2e7b14a
commit d0aff85157
6 changed files with 40 additions and 30 deletions

View file

@ -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,
};

View file

@ -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.");
}
}

View file

@ -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);

View file

@ -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.`);
}

View file

@ -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);
}

View file

@ -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 {