mirror of
https://github.com/Kong/insomnia.git
synced 2026-08-04 11:52:33 -04:00
feat: adds logic to sync git FS/DB for project ruleset
This commit is contained in:
@@ -8,15 +8,15 @@ export function getByParentId(projectId: string) {
|
||||
}
|
||||
|
||||
export async function upsert(projectId: string, patch: Partial<ProjectLintRuleset> = {}) {
|
||||
const spec = await db.findOne<ProjectLintRuleset>(type, {
|
||||
const existing = await db.findOne<ProjectLintRuleset>(type, {
|
||||
parentId: projectId,
|
||||
});
|
||||
|
||||
if (!spec) {
|
||||
if (!existing) {
|
||||
return db.docCreate<ProjectLintRuleset>(type, { ...patch, parentId: projectId });
|
||||
}
|
||||
|
||||
return spec;
|
||||
return db.docUpdate(existing, patch);
|
||||
}
|
||||
|
||||
export function remove(projectId: string) {
|
||||
|
||||
@@ -51,6 +51,7 @@ import { database as db } from '../../common/database';
|
||||
import { InsomniaFileTypeValues } from '../../common/import-v5-parser';
|
||||
import { getInsomniaV5DataExport, tryImportV5Data } from '../../common/insomnia-v5';
|
||||
import { SyncQueue } from './sync-queue';
|
||||
import YAML from 'yaml';
|
||||
|
||||
const POLL_INTERVAL_MS = 10_000;
|
||||
const DEBOUNCE_MS = 300;
|
||||
@@ -223,6 +224,7 @@ class RepoFileWatcher {
|
||||
}
|
||||
|
||||
this.queue.enqueue(() => this.flushProjectWorkspacesToDisk());
|
||||
this.queue.enqueue(() => this.flushProjectLintRulesetToDisk());
|
||||
await this.queue.waitUntilDone();
|
||||
}
|
||||
|
||||
@@ -359,6 +361,7 @@ class RepoFileWatcher {
|
||||
this.flushDebounce = setTimeout(() => {
|
||||
this.flushDebounce = null;
|
||||
this.queue.enqueue(() => this.flushProjectWorkspacesToDisk());
|
||||
this.queue.enqueue(() => this.flushProjectLintRulesetToDisk());
|
||||
}, DEBOUNCE_MS);
|
||||
});
|
||||
}
|
||||
@@ -431,6 +434,39 @@ class RepoFileWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private async flushProjectLintRulesetToDisk(): Promise<void> {
|
||||
if (this.stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
const absPath = path.normalize(path.join(this.repoDir, '.spectral.yaml'));
|
||||
const ruleset = await services.projectLintRuleset.getByParentId(this.projectId);
|
||||
|
||||
try {
|
||||
if (!ruleset) {
|
||||
// Ruleset removed from the DB — remove the file if we were tracking it.
|
||||
if (this.lastWrittenHash.has(absPath) || this.lastSyncMtime.has(absPath)) {
|
||||
await fs.promises.rm(absPath, { force: true });
|
||||
this.lastWrittenHash.delete(absPath);
|
||||
this.lastSyncMtime.delete(absPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = contentHash(ruleset.rulesetContent);
|
||||
if (this.lastWrittenHash.get(absPath) === hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(absPath, ruleset.rulesetContent, 'utf8');
|
||||
this.lastWrittenHash.set(absPath, hash);
|
||||
const stat = await fs.promises.stat(absPath);
|
||||
this.lastSyncMtime.set(absPath, stat.mtimeMs);
|
||||
} catch (err) {
|
||||
console.warn('[repo-file-watcher] Could not flush project lint ruleset to disk:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FS → DB direction (inbound)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -505,6 +541,27 @@ class RepoFileWatcher {
|
||||
this.debounceTimers.set(absPath, timer);
|
||||
}
|
||||
|
||||
private isSpectralRulesetPath(normalisedPath: string): boolean {
|
||||
return (
|
||||
path.basename(normalisedPath) === '.spectral.yaml' &&
|
||||
path.normalize(path.dirname(normalisedPath)) === path.normalize(this.repoDir)
|
||||
);
|
||||
}
|
||||
|
||||
private isSpectralRulesetFile(normalisedPath: string, content: string): boolean {
|
||||
if (!this.isSpectralRulesetPath(normalisedPath)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const parsedContent = YAML.parse(content);
|
||||
return (
|
||||
!!parsedContent && typeof parsedContent === 'object' && ('extends' in parsedContent || 'rules' in parsedContent)
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a YAML file from disk and import its documents into the DB.
|
||||
*
|
||||
@@ -528,6 +585,12 @@ class RepoFileWatcher {
|
||||
this.lastWrittenHash.set(normalised, result.hash);
|
||||
this.lastSyncMtime.set(normalised, result.mtimeMs);
|
||||
|
||||
if (this.isSpectralRulesetFile(normalised, result.content)) {
|
||||
await services.projectLintRuleset.upsert(this.projectId, { rulesetContent: result.content });
|
||||
this.notifyRenderer();
|
||||
return;
|
||||
}
|
||||
|
||||
const docs = this.parseAndValidate(absPath, normalised, result.content);
|
||||
if (!docs) {
|
||||
return;
|
||||
@@ -685,6 +748,16 @@ class RepoFileWatcher {
|
||||
return;
|
||||
}
|
||||
|
||||
// The lint ruleset file was deleted — remove the ProjectLintRuleset record.
|
||||
if (this.isSpectralRulesetPath(normalised)) {
|
||||
await services.projectLintRuleset.remove(this.projectId);
|
||||
this.lastSyncMtime.delete(normalised);
|
||||
this.lastWrittenHash.delete(normalised);
|
||||
this.clearProblem(normalised);
|
||||
this.notifyRenderer();
|
||||
return;
|
||||
}
|
||||
|
||||
const relPath = this.toPosixRelPath(normalised);
|
||||
|
||||
// Find the workspace whose gitFilePath matches this deleted file
|
||||
@@ -726,12 +799,7 @@ class RepoFileWatcher {
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn(
|
||||
'[repo-file-watcher] Failed to remove workspace file from disk:',
|
||||
workspaceId,
|
||||
normalisedPath,
|
||||
err,
|
||||
);
|
||||
console.warn('[repo-file-watcher] Failed to remove workspace file from disk:', workspaceId, normalisedPath, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user